[network-manager-applet/nma-1-0] editor: let users edit connection.interface-name property (rh #1139536)



commit a0b0166e8942cb1df0fcdf6d28e16147adecf77b
Author: Jiří Klimeš <jklimes redhat com>
Date:   Mon Mar 16 12:23:52 2015 +0100

    editor: let users edit connection.interface-name property (rh #1139536)
    
    "Device MAC address" has been changed to "Device" that now accepts both
    interface name and MAC. Either of the two data can be set, or both:
    "em1 (3C:97:0E:18:4C:C7)", "3C:97:0E:18:4C:C7 (em1)", "em1", "3C:97:0E:18:4C:C7".
    This lets user also lock connection to an interface name for Ethernet, Wi-Fi,
    WiMAX, PPPoE, InfiniBand and mobile broadband connections. It is more useful
    than MAC address now that interface names are stable.
    
    For virtual connections, interface name entry is on the corresponding
    page (like bond, bridge, etc.) because it is mandatory.
    
    https://bugzilla.redhat.com/show_bug.cgi?id=1139536
    
    Base on commit 286168120566e4a543c91a11e8d600bbd6d9c3ca, but had to be updated
    substantially to work for nma-1-0 branch.

 src/connection-editor/ce-page-ethernet.ui   |    6 +-
 src/connection-editor/ce-page-infiniband.ui |    6 +-
 src/connection-editor/ce-page-wifi.ui       |    6 +-
 src/connection-editor/ce-page-wimax.ui      |    6 +-
 src/connection-editor/ce-page.c             |  389 ++++++++++++++++++++++-----
 src/connection-editor/ce-page.h             |   22 ++-
 src/connection-editor/page-bluetooth.c      |    7 +-
 src/connection-editor/page-ethernet.c       |   75 +++---
 src/connection-editor/page-infiniband.c     |   66 +++---
 src/connection-editor/page-vlan.c           |    9 +-
 src/connection-editor/page-wifi.c           |   81 +++---
 src/connection-editor/page-wimax.c          |   62 +++--
 12 files changed, 499 insertions(+), 236 deletions(-)
---
diff --git a/src/connection-editor/ce-page-ethernet.ui b/src/connection-editor/ce-page-ethernet.ui
index e619da8..4c7c1ba 100644
--- a/src/connection-editor/ce-page-ethernet.ui
+++ b/src/connection-editor/ce-page-ethernet.ui
@@ -165,11 +165,11 @@
       </packing>
     </child>
     <child>
-      <object class="GtkLabel" id="ethernet_device_mac_label">
+      <object class="GtkLabel" id="ethernet_device_label">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="xalign">0</property>
-        <property name="label" translatable="yes">_Device MAC address:</property>
+        <property name="label" translatable="yes">_Device:</property>
         <property name="use_underline">True</property>
       </object>
       <packing>
@@ -180,7 +180,7 @@
       </packing>
     </child>
     <child>
-      <object class="GtkAlignment" id="ethernet_device_mac_alignment">
+      <object class="GtkAlignment" id="ethernet_device_alignment">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="xalign">0</property>
diff --git a/src/connection-editor/ce-page-infiniband.ui b/src/connection-editor/ce-page-infiniband.ui
index 7773eee..391fa44 100644
--- a/src/connection-editor/ce-page-infiniband.ui
+++ b/src/connection-editor/ce-page-infiniband.ui
@@ -28,11 +28,11 @@
       </packing>
     </child>
     <child>
-      <object class="GtkLabel" id="infiniband_device_mac_label">
+      <object class="GtkLabel" id="infiniband_device_label">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="xalign">0</property>
-        <property name="label" translatable="yes">_Device MAC address:</property>
+        <property name="label" translatable="yes">_Device:</property>
         <property name="use_underline">True</property>
       </object>
       <packing>
@@ -43,7 +43,7 @@
       </packing>
     </child>
     <child>
-      <object class="GtkAlignment" id="infiniband_device_mac_alignment">
+      <object class="GtkAlignment" id="infiniband_device_alignment">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="xalign">0</property>
diff --git a/src/connection-editor/ce-page-wifi.ui b/src/connection-editor/ce-page-wifi.ui
index e2e544b..a7b8f20 100644
--- a/src/connection-editor/ce-page-wifi.ui
+++ b/src/connection-editor/ce-page-wifi.ui
@@ -118,7 +118,7 @@
       </packing>
     </child>
     <child>
-      <object class="GtkAlignment" id="wifi_device_mac_alignment">
+      <object class="GtkAlignment" id="wifi_device_alignment">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="xalign">0</property>
@@ -135,11 +135,11 @@
       </packing>
     </child>
     <child>
-      <object class="GtkLabel" id="wifi_device_mac_label">
+      <object class="GtkLabel" id="wifi_device_label">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="xalign">0</property>
-        <property name="label" translatable="yes">_Device MAC address:</property>
+        <property name="label" translatable="yes">_Device:</property>
         <property name="use_underline">True</property>
       </object>
       <packing>
diff --git a/src/connection-editor/ce-page-wimax.ui b/src/connection-editor/ce-page-wimax.ui
index 5d7468b..326d887 100644
--- a/src/connection-editor/ce-page-wimax.ui
+++ b/src/connection-editor/ce-page-wimax.ui
@@ -10,7 +10,7 @@
     <property name="column_spacing">12</property>
     <property name="row_spacing">6</property>
     <child>
-      <object class="GtkAlignment" id="wimax_device_mac_alignment">
+      <object class="GtkAlignment" id="wimax_device_alignment">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="xalign">0</property>
@@ -27,11 +27,11 @@
       </packing>
     </child>
     <child>
-      <object class="GtkLabel" id="wimax_device_mac_label">
+      <object class="GtkLabel" id="wimax_device_label">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="xalign">0</property>
-        <property name="label" translatable="yes">_Device MAC address:</property>
+        <property name="label" translatable="yes">_Device:</property>
         <property name="use_underline">True</property>
       </object>
       <packing>
diff --git a/src/connection-editor/ce-page.c b/src/connection-editor/ce-page.c
index eb6dd4d..4c29a3e 100644
--- a/src/connection-editor/ce-page.c
+++ b/src/connection-editor/ce-page.c
@@ -150,74 +150,159 @@ ce_page_last_update (CEPage *self, NMConnection *connection, GError **error)
        return TRUE;
 }
 
-char **
-ce_page_get_mac_list (CEPage *self, GType device_type, const char *mac_property)
+static int
+hwaddr_binary_len (const char *asc)
 {
-       const GPtrArray *devices;
-       GPtrArray *macs;
-       int i;
+       int octets = 1;
 
-       g_return_val_if_fail (CE_IS_PAGE (self), NULL);
+       if (!*asc)
+               return 0;
 
-       if (!self->client)
-               return NULL;
+       for (; *asc; asc++) {
+               if (*asc == ':' || *asc == '-')
+                       octets++;
+       }
+       return octets;
+}
 
-       macs = g_ptr_array_new ();
-       devices = nm_client_get_devices (self->client);
-       for (i = 0; devices && (i < devices->len); i++) {
-               NMDevice *dev = g_ptr_array_index (devices, i);
-               const char *iface;
-               char *mac, *item;
+static gboolean
+_hwaddr_matches (const char *addr1, const char *addr2, int type)
+{
+       GByteArray *mac1, *mac2;
+       guint8 *ptr1, *ptr2;
+       int addr1_len, addr2_len, len;
+       int ret;
+
+       if (!addr1 || !addr2)
+               return FALSE;
+
+       addr1_len = hwaddr_binary_len (addr1);
+       addr2_len = hwaddr_binary_len (addr2);
+       if (addr1_len == 0 || addr2_len == 0)
+               return FALSE;
+       if (addr1_len != addr2_len)
+               return FALSE;
+
+       mac1 = nm_utils_hwaddr_atoba (addr1, type);
+       if (!mac1)
+               return FALSE;
+       mac2 = nm_utils_hwaddr_atoba (addr2, type);
+       if (!mac2)
+               return FALSE;
+
+       ptr1 = mac1->data;
+       ptr2 = mac2->data;
+       len = mac1->len;
+       if (type == ARPHRD_INFINIBAND) {
+               ptr1 = ptr1 + 20 - 8;
+               ptr2 = ptr2 + 20 - 8;
+               len = 8;
+       }
+       ret = memcmp (ptr1, ptr2, len);
+       g_byte_array_free (mac1, TRUE);
+       g_byte_array_free (mac2, TRUE);
 
-               if (!G_TYPE_CHECK_INSTANCE_TYPE (dev, device_type))
-                       continue;
+       return ret == 0;
+}
+
+static void
+_set_active_combo_item (GtkComboBox *combo, const char *item,
+                        const char *combo_item, int combo_idx)
+{
+       GtkWidget *entry;
+
+       if (item) {
+               /* set active item */
+               gtk_combo_box_set_active (combo, combo_idx);
 
-               g_object_get (G_OBJECT (dev), mac_property, &mac, NULL);
-               iface = nm_device_get_iface (NM_DEVICE (dev));
-               item = g_strdup_printf ("%s (%s)", mac, iface);
-               g_free (mac);
-               g_ptr_array_add (macs, item);
+               if (!combo_item)
+                       gtk_combo_box_text_prepend_text (GTK_COMBO_BOX_TEXT (combo), item);
+
+               entry = gtk_bin_get_child (GTK_BIN (combo));
+               if (entry)
+                       gtk_entry_set_text (GTK_ENTRY (entry), combo_item ? combo_item : item);
        }
+}
 
-       g_ptr_array_add (macs, NULL);
-       return (char **)g_ptr_array_free (macs, FALSE);
+/* Combo box storing data in the form of "text1 (text2)" */
+void
+ce_page_setup_data_combo (CEPage *self, GtkComboBox *combo,
+                          const char *data, char **list)
+{
+       char **iter, *active_item = NULL;
+       int i, active_idx = -1;
+       int data_len;
+
+       if (data)
+               data_len = strlen (data);
+       else
+               data_len = -1;
+
+       for (iter = list, i = 0; iter && *iter; iter++, i++) {
+               gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), *iter);
+               if (   data
+                   && g_ascii_strncasecmp (*iter, data, data_len) == 0
+                   && ((*iter)[data_len] == '\0' || (*iter)[data_len] == ' ')) {
+                       active_item = *iter;
+                       active_idx = i;
+               }
+       }
+       _set_active_combo_item (combo, data, active_item, active_idx);
 }
 
+/* Combo box storing MAC addresses only */
 void
 ce_page_setup_mac_combo (CEPage *self, GtkComboBox *combo,
-                         const char *current_mac, char **mac_list)
+                         const GByteArray *mac, int type, char **mac_list)
 {
        char **iter, *active_mac = NULL;
        int i, active_idx = -1;
-       int current_mac_len;
-       GtkWidget *entry;
+       char *mac_str;
 
-       if (current_mac)
-               current_mac_len = strlen (current_mac);
-       else
-               current_mac_len = -1;
+       mac_str = mac ? nm_utils_hwaddr_ntoa (mac->data, type) : NULL;
 
        for (iter = mac_list, i = 0; iter && *iter; iter++, i++) {
                gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), *iter);
-               if (   current_mac
-                   && g_ascii_strncasecmp (*iter, current_mac, current_mac_len) == 0
-                   && ((*iter)[current_mac_len] == '\0' || (*iter)[current_mac_len] == ' ')) {
+               if (mac_str && *iter && _hwaddr_matches (mac_str, *iter, type)) {
                        active_mac = *iter;
                        active_idx = i;
                }
        }
+       _set_active_combo_item (combo, mac_str, active_mac, active_idx);
+       g_free (mac_str);
+}
 
-       if (current_mac) {
-               /* set active item */
-               gtk_combo_box_set_active (combo, active_idx);
-               
-               if (!active_mac)
-                       gtk_combo_box_text_prepend_text (GTK_COMBO_BOX_TEXT (combo), current_mac);
+static gboolean
+_mac_is_valid (const char *mac, int type)
+{
+       GByteArray *array;
+       gboolean valid;
 
-               entry = gtk_bin_get_child (GTK_BIN (combo));
-               if (entry)
-                       gtk_entry_set_text (GTK_ENTRY (entry), active_mac ? active_mac : current_mac);
-       }
+       array = nm_utils_hwaddr_atoba (mac, type);
+       if (!array)
+               return FALSE;
+
+       valid = TRUE;
+       if (type == ARPHRD_ETHER && !utils_ether_addr_valid ((struct ether_addr *)array->data))
+               valid = FALSE;
+
+       g_byte_array_free (array, TRUE);
+       return valid;
+}
+
+gboolean
+ce_page_mac_entry_valid (GtkEntry *entry, int type)
+{
+       const char *mac;
+
+       g_return_val_if_fail (entry != NULL, FALSE);
+       g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
+
+       mac = gtk_entry_get_text (entry);
+       if (!mac || !*mac)
+               return TRUE;
+
+       return _mac_is_valid (mac, type);
 }
 
 void
@@ -242,9 +327,7 @@ ce_page_mac_to_entry (const GByteArray *mac, int type, GtkEntry *entry)
 GByteArray *
 ce_page_entry_to_mac (GtkEntry *entry, int type, gboolean *invalid)
 {
-       const char *temp, *sp;
-       char *buf = NULL;
-       GByteArray *mac;
+       const char *temp;
 
        g_return_val_if_fail (entry != NULL, NULL);
        g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
@@ -253,29 +336,213 @@ ce_page_entry_to_mac (GtkEntry *entry, int type, gboolean *invalid)
                g_return_val_if_fail (*invalid == FALSE, NULL);
 
        temp = gtk_entry_get_text (entry);
-       if (!temp || !strlen (temp))
+       if (!temp || !*temp)
                return NULL;
 
-       sp = strchr (temp, ' ');
-       if (sp)
-               temp = buf = g_strndup (temp, sp - temp);
+       return nm_utils_hwaddr_atoba (temp, type);
+}
 
-       mac = nm_utils_hwaddr_atoba (temp, type);
-       g_free (buf);
-       if (!mac) {
-               if (invalid)
-                       *invalid = TRUE;
+static char **
+_get_device_list (CEPage *self,
+                  GType device_type,
+                  gboolean set_ifname,
+                  const char *mac_property,
+                  gboolean ifname_first)
+{
+       const GPtrArray *devices;
+       GPtrArray *interfaces;
+       int i;
+
+       g_return_val_if_fail (CE_IS_PAGE (self), NULL);
+       g_return_val_if_fail (set_ifname || mac_property, NULL);
+
+       if (!self->client)
                return NULL;
+
+       interfaces = g_ptr_array_new ();
+       devices = nm_client_get_devices (self->client);
+       for (i = 0; devices && (i < devices->len); i++) {
+               NMDevice *dev = g_ptr_array_index (devices, i);
+               const char *ifname;
+               char *mac;
+               char *item;
+
+               if (!G_TYPE_CHECK_INSTANCE_TYPE (dev, device_type))
+                       continue;
+
+               ifname = nm_device_get_iface (NM_DEVICE (dev));
+               if (mac_property)
+                       g_object_get (G_OBJECT (dev), mac_property, &mac, NULL);
+
+               if (set_ifname && mac_property) {
+                       if (ifname_first)
+                               item = g_strdup_printf ("%s (%s)", ifname, mac);
+                       else
+                               item = g_strdup_printf ("%s (%s)", mac, ifname);
+               } else
+                       item = g_strdup (set_ifname ? ifname : mac);
+
+               g_ptr_array_add (interfaces, item);
+               if (mac_property)
+                       g_free (mac);
        }
+       g_ptr_array_add (interfaces, NULL);
 
-       if (type == ARPHRD_ETHER && !utils_ether_addr_valid ((struct ether_addr *)mac->data)) {
-               g_byte_array_free (mac, TRUE);
-               if (invalid)
-                       *invalid = TRUE;
-               return NULL;
+       return (char **)g_ptr_array_free (interfaces, FALSE);
+}
+
+static gboolean
+_device_entry_parse (const char *entry_text, char **first, char **second)
+{
+       const char *sp, *left, *right;
+
+       if (!entry_text || !*entry_text) {
+               *first = NULL;
+               *second = NULL;
+               return TRUE;
+       }
+
+       sp = strchr (entry_text, ' ');
+       if (sp) {
+               *first = g_strndup (entry_text, sp - entry_text);
+               left = sp + 1;
+               right = strchr (left, ')');
+               if (*left == '(' && right && right > left)
+                       *second = g_strndup (left + 1, right - left - 1);
+               else {
+                       *second = NULL;
+                       return FALSE;
+               }
+       } else {
+               *first = g_strdup (entry_text);
+               *second = NULL;
+       }
+       return TRUE;
+}
+
+static gboolean
+_device_entries_match (const char *ifname, const char *mac, int type, const char *entry)
+{
+       char *first, *second;
+       gboolean ifname_match = FALSE, mac_match = FALSE;
+       gboolean both;
+
+       if (!ifname && !mac)
+               return FALSE;
+
+       _device_entry_parse (entry, &first, &second);
+       both = first && second;
+
+       if (   ifname
+           && (   !g_strcmp0 (ifname, first)
+               || !g_strcmp0 (ifname, second)))
+               ifname_match = TRUE;
+
+       if (   mac
+           && (   (first && _hwaddr_matches (mac, first, type))
+               || (second && _hwaddr_matches (mac, second, type))))
+               mac_match = TRUE;
+
+       g_free (first);
+       g_free (second);
+
+       if (both)
+               return ifname_match && mac_match;
+       else {
+               if (ifname)
+                       return ifname_match;
+               if (mac)
+                       return mac_match;
+               return FALSE;
+       }
+}
+
+/* Combo box storing ifname and/or MAC */
+void
+ce_page_setup_device_combo (CEPage *self,
+                            GtkComboBox *combo,
+                            GType device_type,
+                            const char *ifname,
+                            const GByteArray *mac,
+                            int mac_type,
+                            const char *mac_property,
+                            gboolean ifname_first)
+{
+       char **iter, *active_item = NULL;
+       int i, active_idx = -1;
+       char **device_list;
+       char *item;
+       char *mac_str;
+
+       mac_str = mac ? nm_utils_hwaddr_ntoa (mac->data, mac_type) : NULL;
+       device_list = _get_device_list (self, device_type, TRUE, mac_property, ifname_first);
+
+       if (ifname && mac_str)
+               item = g_strdup_printf ("%s (%s)", ifname, mac_str);
+       else if (!ifname && !mac_str)
+               item = NULL;
+       else
+               item = g_strdup (ifname ? ifname : mac_str);
+
+       for (iter = device_list, i = 0; iter && *iter; iter++, i++) {
+               gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), *iter);
+               if (_device_entries_match (ifname, mac_str, mac_type, *iter)) {
+                       active_item = *iter;
+                       active_idx = i;
+               }
        }
+       _set_active_combo_item (combo, item, active_item, active_idx);
+
+       g_free (mac_str);
+       g_free (item);
+       g_strfreev (device_list);
+}
+
+gboolean
+ce_page_device_entry_get (GtkEntry *entry, int type, char **ifname, GByteArray **mac)
+{
+       char *first, *second;
+       const char *ifname_tmp = NULL, *mac_tmp = NULL;
+       gboolean valid = TRUE;
+
+       g_return_val_if_fail (entry != NULL, FALSE);
+       g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
+
+       valid = _device_entry_parse (gtk_entry_get_text (entry), &first, &second);
+
+       if (first) {
+               if (_mac_is_valid (first, type))
+                       mac_tmp = first;
+               else if (nm_utils_iface_valid_name (first))
+                       ifname_tmp = first;
+               else
+                       valid = FALSE;
+       }
+       if (second) {
+               if (_mac_is_valid (second, type)) {
+                       if (!mac_tmp)
+                               mac_tmp = second;
+                       else
+                               valid = FALSE;
+               } else if (nm_utils_iface_valid_name (second)) {
+                       if (!ifname_tmp)
+                               ifname_tmp = second;
+                       else
+                               valid = FALSE;
+               } else
+                       valid = FALSE;
+       }
+
+       if (ifname)
+               *ifname = g_strdup (ifname_tmp);
+       if (mac) {
+               *mac = mac_tmp ? nm_utils_hwaddr_atoba (mac_tmp, type) : NULL;
+       }
+
+       g_free (first);
+       g_free (second);
 
-       return mac;
+       return valid;
 }
 
 char *
diff --git a/src/connection-editor/ce-page.h b/src/connection-editor/ce-page.h
index 4306fc8..41711d9 100644
--- a/src/connection-editor/ce-page.h
+++ b/src/connection-editor/ce-page.h
@@ -108,16 +108,26 @@ const char * ce_page_get_title (CEPage *self);
 gboolean ce_page_validate (CEPage *self, NMConnection *connection, GError **error);
 gboolean ce_page_last_update (CEPage *self, NMConnection *connection, GError **error);
 
-char **ce_page_get_mac_list (CEPage *self, GType device_type, const char *mac_property);
 void ce_page_setup_mac_combo (CEPage *self, GtkComboBox *combo,
-                              const char *current_mac, char **mac_list);
-
-void ce_page_changed (CEPage *self);
-
+                              const GByteArray *mac, int type, char **mac_list);
+void ce_page_setup_data_combo (CEPage *self, GtkComboBox *combo,
+                               const char *data, char **list);
+void ce_page_setup_device_combo (CEPage *self,
+                                 GtkComboBox *combo,
+                                 GType device_type,
+                                 const char *ifname,
+                                 const GByteArray *mac,
+                                 int mac_type,
+                                 const char *mac_property,
+                                 gboolean ifname_first);
+gboolean ce_page_mac_entry_valid (GtkEntry *entry, int type);
+gboolean ce_page_device_entry_get (GtkEntry *entry, int type,
+                                   char **ifname, GByteArray **mac);
 void ce_page_mac_to_entry (const GByteArray *mac, int type, GtkEntry *entry);
-
 GByteArray *ce_page_entry_to_mac (GtkEntry *entry, int type, gboolean *invalid);
 
+void ce_page_changed (CEPage *self);
+
 gboolean ce_spin_output_with_automatic (GtkSpinButton *spin, gpointer user_data);
 
 gboolean ce_spin_output_with_default (GtkSpinButton *spin, gpointer user_data);
diff --git a/src/connection-editor/page-bluetooth.c b/src/connection-editor/page-bluetooth.c
index 35490e5..7882da0 100644
--- a/src/connection-editor/page-bluetooth.c
+++ b/src/connection-editor/page-bluetooth.c
@@ -147,14 +147,9 @@ validate (CEPage *page, NMConnection *connection, GError **error)
 {
        CEPageBluetooth *self = CE_PAGE_BLUETOOTH (page);
        CEPageBluetoothPrivate *priv = CE_PAGE_BLUETOOTH_GET_PRIVATE (self);
-       GByteArray *bdaddr;
-       gboolean invalid;
 
-       bdaddr = ce_page_entry_to_mac (priv->bdaddr, ARPHRD_ETHER, &invalid);
-       if (invalid)
+       if (!ce_page_mac_entry_valid (priv->bdaddr, ARPHRD_ETHER))
                return FALSE;
-       if (bdaddr)
-               g_byte_array_free (bdaddr, TRUE);
 
        ui_to_setting (self);
        return nm_setting_verify (NM_SETTING (priv->setting), NULL, error);
diff --git a/src/connection-editor/page-ethernet.c b/src/connection-editor/page-ethernet.c
index 16c8204..451ee22 100644
--- a/src/connection-editor/page-ethernet.c
+++ b/src/connection-editor/page-ethernet.c
@@ -42,8 +42,8 @@ G_DEFINE_TYPE (CEPageEthernet, ce_page_ethernet, CE_TYPE_PAGE)
 typedef struct {
        NMSettingWired *setting;
 
-       GtkComboBoxText *device_mac;  /* Permanent MAC of the device */
-       GtkEntry *cloned_mac;         /* Cloned MAC - used for MAC spoofing */
+       GtkComboBoxText *device_combo; /* Device identification (ifname and/or MAC) */
+       GtkEntry *cloned_mac;          /* Cloned MAC - used for MAC spoofing */
        GtkComboBox *port;
        GtkComboBox *speed;
        GtkToggleButton *duplex;
@@ -73,18 +73,20 @@ ethernet_private_init (CEPageEthernet *self)
 
        builder = CE_PAGE (self)->builder;
 
-       priv->device_mac = GTK_COMBO_BOX_TEXT (gtk_combo_box_text_new_with_entry ());
-       gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (priv->device_mac), 0);
-       gtk_widget_set_tooltip_text (GTK_WIDGET (priv->device_mac),
-                                    _("This option locks this connection to the network device specified by 
its permanent MAC address entered here.  Example: 00:11:22:33:44:55"));
+       priv->device_combo = GTK_COMBO_BOX_TEXT (gtk_combo_box_text_new_with_entry ());
+       gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (priv->device_combo), 0);
+       gtk_widget_set_tooltip_text (GTK_WIDGET (priv->device_combo),
+                                    _("This option locks this connection to the network device specified "
+                                      "either by its interface name or permanent MAC or both. Examples: "
+                                      "\"em1\", \"3C:97:0E:42:1A:19\", \"em1 (3C:97:0E:42:1A:19)\""));
 
-       align = GTK_WIDGET (gtk_builder_get_object (builder, "ethernet_device_mac_alignment"));
-       gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET (priv->device_mac));
-       gtk_widget_show_all (GTK_WIDGET (priv->device_mac));
+       align = GTK_WIDGET (gtk_builder_get_object (builder, "ethernet_device_alignment"));
+       gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET (priv->device_combo));
+       gtk_widget_show_all (GTK_WIDGET (priv->device_combo));
 
-       /* Set mnemonic widget for device MAC label */
-       label = GTK_LABEL (gtk_builder_get_object (builder, "ethernet_device_mac_label"));
-       gtk_label_set_mnemonic_widget (label, GTK_WIDGET (priv->device_mac));
+       /* Set mnemonic widget for Device label */
+       label = GTK_LABEL (gtk_builder_get_object (builder, "ethernet_device_label"));
+       gtk_label_set_mnemonic_widget (label, GTK_WIDGET (priv->device_combo));
 
        priv->cloned_mac = GTK_ENTRY (gtk_builder_get_object (builder, "ethernet_cloned_mac"));
        priv->port = GTK_COMBO_BOX (gtk_builder_get_object (builder, "ethernet_port"));
@@ -110,9 +112,8 @@ populate_ui (CEPageEthernet *self)
        int port_idx = PORT_DEFAULT;
        int speed_idx;
        int mtu_def;
-       char **mac_list;
        const GByteArray *s_mac;
-       char *s_mac_str;
+       const char *s_ifname;
 
        /* Port */
        port = nm_setting_wired_get_port (setting);
@@ -159,20 +160,17 @@ populate_ui (CEPageEthernet *self)
        gtk_toggle_button_set_active (priv->autonegotiate, 
                                      nm_setting_wired_get_auto_negotiate (setting));
 
-       /* Device MAC address */
-       mac_list = ce_page_get_mac_list (CE_PAGE (self), NM_TYPE_DEVICE_ETHERNET,
-                                        NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS);
+       /* Device ifname/MAC */
+       s_ifname = nm_connection_get_interface_name (CE_PAGE (self)->connection);
        s_mac = nm_setting_wired_get_mac_address (setting);
-       s_mac_str = s_mac ? nm_utils_hwaddr_ntoa (s_mac->data, ARPHRD_ETHER) : NULL;
-       ce_page_setup_mac_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->device_mac),
-                                s_mac_str, mac_list);
-       g_free (s_mac_str);
-       g_strfreev (mac_list);
-       g_signal_connect (priv->device_mac, "changed", G_CALLBACK (stuff_changed), self);
+       ce_page_setup_device_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->device_combo),
+                                   NM_TYPE_DEVICE_ETHERNET, s_ifname,
+                                   s_mac, ARPHRD_ETHER, NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS, TRUE);
+       g_signal_connect (priv->device_combo, "changed", G_CALLBACK (stuff_changed), self);
 
        /* Cloned MAC address */
-       ce_page_mac_to_entry (nm_setting_wired_get_cloned_mac_address (setting),
-                             ARPHRD_ETHER, priv->cloned_mac);
+       s_mac = nm_setting_wired_get_cloned_mac_address (setting);
+       ce_page_mac_to_entry (s_mac, ARPHRD_ETHER, priv->cloned_mac);
        g_signal_connect (priv->cloned_mac, "changed", G_CALLBACK (stuff_changed), self);
 
        /* MTU */
@@ -261,12 +259,17 @@ static void
 ui_to_setting (CEPageEthernet *self)
 {
        CEPageEthernetPrivate *priv = CE_PAGE_ETHERNET_GET_PRIVATE (self);
+       NMSettingConnection *s_con;
        const char *port;
        guint32 speed;
+       char *ifname = NULL;
        GByteArray *device_mac = NULL;
        GByteArray *cloned_mac = NULL;
        GtkWidget *entry;
 
+       s_con = nm_connection_get_setting_connection (CE_PAGE (self)->connection);
+       g_return_if_fail (s_con != NULL);
+
        /* Port */
        switch (gtk_combo_box_get_active (priv->port)) {
        case PORT_TP:
@@ -305,11 +308,14 @@ ui_to_setting (CEPageEthernet *self)
                break;
        }
 
-       entry = gtk_bin_get_child (GTK_BIN (priv->device_mac));
+       entry = gtk_bin_get_child (GTK_BIN (priv->device_combo));
        if (entry)
-               device_mac = ce_page_entry_to_mac (GTK_ENTRY (entry), ARPHRD_ETHER, NULL);
+               ce_page_device_entry_get (GTK_ENTRY (entry), ARPHRD_ETHER, &ifname, &device_mac);
        cloned_mac = ce_page_entry_to_mac (priv->cloned_mac, ARPHRD_ETHER, NULL);
 
+       g_object_set (s_con,
+                     NM_SETTING_CONNECTION_INTERFACE_NAME, ifname,
+                     NULL);
        g_object_set (priv->setting,
                      NM_SETTING_WIRED_MAC_ADDRESS, device_mac,
                      NM_SETTING_WIRED_CLONED_MAC_ADDRESS, cloned_mac,
@@ -320,6 +326,7 @@ ui_to_setting (CEPageEthernet *self)
                      NM_SETTING_WIRED_MTU, (guint32) gtk_spin_button_get_value_as_int (priv->mtu),
                      NULL);
 
+       g_free (ifname);
        if (device_mac)
                g_byte_array_free (device_mac, TRUE);
        if (cloned_mac)
@@ -332,24 +339,16 @@ validate (CEPage *page, NMConnection *connection, GError **error)
 {
        CEPageEthernet *self = CE_PAGE_ETHERNET (page);
        CEPageEthernetPrivate *priv = CE_PAGE_ETHERNET_GET_PRIVATE (self);
-       gboolean invalid = FALSE;
-       GByteArray *ignore;
        GtkWidget *entry;
 
-       entry = gtk_bin_get_child (GTK_BIN (priv->device_mac));
+       entry = gtk_bin_get_child (GTK_BIN (priv->device_combo));
        if (entry) {
-               ignore = ce_page_entry_to_mac (GTK_ENTRY (entry), ARPHRD_ETHER, &invalid);
-               if (invalid)
+               if (!ce_page_device_entry_get (GTK_ENTRY (entry), ARPHRD_ETHER, NULL, NULL))
                        return FALSE;
-               if (ignore)
-                       g_byte_array_free (ignore, TRUE);
        }
 
-       ignore = ce_page_entry_to_mac (priv->cloned_mac, ARPHRD_ETHER, &invalid);
-       if (invalid)
+       if (!ce_page_mac_entry_valid (priv->cloned_mac, ARPHRD_ETHER))
                return FALSE;
-       if (ignore)
-               g_byte_array_free (ignore, TRUE);
 
        ui_to_setting (self);
        return nm_setting_verify (NM_SETTING (priv->setting), NULL, error);
diff --git a/src/connection-editor/page-infiniband.c b/src/connection-editor/page-infiniband.c
index f85e453..19560a2 100644
--- a/src/connection-editor/page-infiniband.c
+++ b/src/connection-editor/page-infiniband.c
@@ -40,7 +40,7 @@ G_DEFINE_TYPE (CEPageInfiniband, ce_page_infiniband, CE_TYPE_PAGE)
 typedef struct {
        NMSettingInfiniband *setting;
 
-       GtkComboBoxText *device_mac;  /* Permanent MAC of the device */
+       GtkComboBoxText *device_combo; /* Device identification (ifname and/or MAC) */
 
        GtkComboBox *transport_mode;
        GtkSpinButton *mtu;
@@ -59,18 +59,21 @@ infiniband_private_init (CEPageInfiniband *self)
 
        builder = CE_PAGE (self)->builder;
 
-       priv->device_mac = GTK_COMBO_BOX_TEXT (gtk_combo_box_text_new_with_entry ());
-       gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (priv->device_mac), 0);
-       gtk_widget_set_tooltip_text (GTK_WIDGET (priv->device_mac),
-                                    _("This option locks this connection to the network device specified by 
its permanent MAC address entered here.  Example: 00:11:22:33:44:55"));
+       priv->device_combo = GTK_COMBO_BOX_TEXT (gtk_combo_box_text_new_with_entry ());
+       gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (priv->device_combo), 0);
+       gtk_widget_set_tooltip_text (GTK_WIDGET (priv->device_combo),
+                                    _("This option locks this connection to the network device specified "
+                                      "either by its interface name or permanent MAC or both. Examples: "
+                                      "\"ib0\", 
\"80:00:00:48:fe:80:00:00:00:00:00:00:00:02:c9:03:00:00:0f:65\", "
+                                      "\"ib0 
(80:00:00:48:fe:80:00:00:00:00:00:00:00:02:c9:03:00:00:0f:65)\""));
 
-       align = GTK_WIDGET (gtk_builder_get_object (builder, "infiniband_device_mac_alignment"));
-       gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET (priv->device_mac));
-       gtk_widget_show_all (GTK_WIDGET (priv->device_mac));
+       align = GTK_WIDGET (gtk_builder_get_object (builder, "infiniband_device_alignment"));
+       gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET (priv->device_combo));
+       gtk_widget_show_all (GTK_WIDGET (priv->device_combo));
 
-       /* Set mnemonic widget for device MAC label */
-       label = GTK_LABEL (gtk_builder_get_object (builder, "infiniband_device_mac_label"));
-       gtk_label_set_mnemonic_widget (label, GTK_WIDGET (priv->device_mac));
+       /* Set mnemonic widget for Device label */
+       label = GTK_LABEL (gtk_builder_get_object (builder, "infiniband_device_label"));
+       gtk_label_set_mnemonic_widget (label, GTK_WIDGET (priv->device_combo));
 
        priv->transport_mode = GTK_COMBO_BOX (gtk_builder_get_object (builder, "infiniband_mode"));
        priv->mtu = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "infiniband_mtu"));
@@ -90,9 +93,8 @@ populate_ui (CEPageInfiniband *self)
        const char *mode;
        int mode_idx = TRANSPORT_MODE_DATAGRAM;
        int mtu_def;
-       char **mac_list;
        const GByteArray *s_mac;
-       char *s_mac_str;
+       const char *s_ifname;
 
        /* Port */
        mode = nm_setting_infiniband_get_transport_mode (setting);
@@ -104,16 +106,13 @@ populate_ui (CEPageInfiniband *self)
        }
        gtk_combo_box_set_active (priv->transport_mode, mode_idx);
 
-       /* Device MAC address */
-       mac_list = ce_page_get_mac_list (CE_PAGE (self), NM_TYPE_DEVICE_INFINIBAND,
-                                        NM_DEVICE_INFINIBAND_HW_ADDRESS);
+       /* Device */
+       s_ifname = nm_connection_get_interface_name (CE_PAGE (self)->connection);
        s_mac = nm_setting_infiniband_get_mac_address (setting);
-       s_mac_str = s_mac ? nm_utils_hwaddr_ntoa (s_mac->data, ARPHRD_INFINIBAND) : NULL;
-       ce_page_setup_mac_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->device_mac),
-                                s_mac_str, mac_list);
-       g_free (s_mac_str);
-       g_strfreev (mac_list);
-       g_signal_connect (priv->device_mac, "changed", G_CALLBACK (stuff_changed), self);
+       ce_page_setup_device_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->device_combo),
+                                   NM_TYPE_DEVICE_INFINIBAND, s_ifname,
+                                   s_mac, ARPHRD_INFINIBAND, NM_DEVICE_INFINIBAND_HW_ADDRESS, TRUE);
+       g_signal_connect (priv->device_combo, "changed", G_CALLBACK (stuff_changed), self);
 
        /* MTU */
        mtu_def = ce_get_property_default (NM_SETTING (setting), NM_SETTING_INFINIBAND_MTU);
@@ -181,27 +180,35 @@ static void
 ui_to_setting (CEPageInfiniband *self)
 {
        CEPageInfinibandPrivate *priv = CE_PAGE_INFINIBAND_GET_PRIVATE (self);
+       NMSettingConnection *s_con;
        const char *mode;
+       char *ifname = NULL;
        GByteArray *device_mac = NULL;
        GtkWidget *entry;
 
+       s_con = nm_connection_get_setting_connection (CE_PAGE (self)->connection);
+       g_return_if_fail (s_con != NULL);
+
        /* Transport mode */
        if (gtk_combo_box_get_active (priv->transport_mode) == TRANSPORT_MODE_CONNECTED)
                mode = "connected";
        else
                mode = "datagram";
 
-       entry = gtk_bin_get_child (GTK_BIN (priv->device_mac));
+       entry = gtk_bin_get_child (GTK_BIN (priv->device_combo));
        if (entry)
-               device_mac = nm_utils_hwaddr_atoba (gtk_entry_get_text (GTK_ENTRY (entry)),
-                                                   ARPHRD_INFINIBAND);
+               ce_page_device_entry_get (GTK_ENTRY (entry), ARPHRD_INFINIBAND, &ifname, &device_mac);
 
+       g_object_set (s_con,
+                     NM_SETTING_CONNECTION_INTERFACE_NAME, ifname,
+                     NULL);
        g_object_set (priv->setting,
                      NM_SETTING_INFINIBAND_MAC_ADDRESS, device_mac,
                      NM_SETTING_INFINIBAND_MTU, (guint32) gtk_spin_button_get_value_as_int (priv->mtu),
                      NM_SETTING_INFINIBAND_TRANSPORT_MODE, mode,
                      NULL);
 
+       g_free (ifname);
        if (device_mac)
                g_byte_array_free (device_mac, TRUE);
 }
@@ -211,17 +218,12 @@ validate (CEPage *page, NMConnection *connection, GError **error)
 {
        CEPageInfiniband *self = CE_PAGE_INFINIBAND (page);
        CEPageInfinibandPrivate *priv = CE_PAGE_INFINIBAND_GET_PRIVATE (self);
-       gboolean invalid = FALSE;
-       GByteArray *ignore;
        GtkWidget *entry;
 
-       entry = gtk_bin_get_child (GTK_BIN (priv->device_mac));
+       entry = gtk_bin_get_child (GTK_BIN (priv->device_combo));
        if (entry) {
-               ignore = ce_page_entry_to_mac (GTK_ENTRY (entry), ARPHRD_INFINIBAND, &invalid);
-               if (invalid)
+               if (!ce_page_device_entry_get (GTK_ENTRY (entry), ARPHRD_INFINIBAND, NULL, NULL))
                        return FALSE;
-               if (ignore)
-                       g_byte_array_free (ignore, TRUE);
        }
 
        ui_to_setting (self);
diff --git a/src/connection-editor/page-vlan.c b/src/connection-editor/page-vlan.c
index 6fa6cc5..1a8c6b6 100644
--- a/src/connection-editor/page-vlan.c
+++ b/src/connection-editor/page-vlan.c
@@ -416,7 +416,7 @@ populate_ui (CEPageVlan *self)
                        break;
                }
        }
-       ce_page_setup_mac_combo (CE_PAGE (self), priv->parent, current_parent, priv->parent_labels);
+       ce_page_setup_data_combo (CE_PAGE (self), priv->parent, current_parent, priv->parent_labels);
        g_signal_connect (priv->parent, "changed", G_CALLBACK (parent_changed), self);
 
        if (current_parent)
@@ -605,8 +605,6 @@ validate (CEPage *page, NMConnection *connection, GError **error)
 {
        CEPageVlan *self = CE_PAGE_VLAN (page);
        CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
-       gboolean invalid = FALSE;
-       GByteArray *ignore;
        int parent_id;
        const char *parent;
        char *parent_iface;
@@ -623,11 +621,8 @@ validate (CEPage *page, NMConnection *connection, GError **error)
                        return FALSE;
        }
 
-       ignore = ce_page_entry_to_mac (priv->cloned_mac, ARPHRD_ETHER, &invalid);
-       if (invalid)
+       if (!ce_page_mac_entry_valid (priv->cloned_mac, ARPHRD_ETHER))
                return FALSE;
-       if (ignore)
-               g_byte_array_free (ignore, TRUE);
 
        ui_to_setting (self);
 
diff --git a/src/connection-editor/page-wifi.c b/src/connection-editor/page-wifi.c
index dbf4e20..8a25c64 100644
--- a/src/connection-editor/page-wifi.c
+++ b/src/connection-editor/page-wifi.c
@@ -44,8 +44,8 @@ typedef struct {
 
        GtkEntry *ssid;
        GtkComboBoxText *bssid;
-       GtkComboBoxText *device_mac;  /* Permanent MAC of the device */
-       GtkEntry *cloned_mac;         /* Cloned MAC - used for MAC spoofing */
+       GtkComboBoxText *device_combo; /* Device identification (ifname and/or MAC) */
+       GtkEntry *cloned_mac;          /* Cloned MAC - used for MAC spoofing */
        GtkComboBox *mode;
        GtkComboBox *band;
        GtkSpinButton *channel;
@@ -88,18 +88,20 @@ wifi_private_init (CEPageWifi *self)
        gtk_widget_show_all (GTK_WIDGET (priv->bssid));
 
        /* Device MAC */
-       priv->device_mac = GTK_COMBO_BOX_TEXT (gtk_combo_box_text_new_with_entry ());
-       gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (priv->device_mac), 0);
-       gtk_widget_set_tooltip_text (GTK_WIDGET (priv->device_mac),
-                                    _("This option locks this connection to the network device specified by 
its permanent MAC address entered here.  Example: 00:11:22:33:44:55"));
+       priv->device_combo = GTK_COMBO_BOX_TEXT (gtk_combo_box_text_new_with_entry ());
+       gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (priv->device_combo), 0);
+       gtk_widget_set_tooltip_text (GTK_WIDGET (priv->device_combo),
+                                    _("This option locks this connection to the network device specified "
+                                      "either by its interface name or permanent MAC or both. Examples: "
+                                      "\"wlan0\", \"3C:97:0E:42:1A:19\", \"wlan0 (3C:97:0E:42:1A:19)\""));
 
-       align = GTK_WIDGET (gtk_builder_get_object (builder, "wifi_device_mac_alignment"));
-       gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET (priv->device_mac));
-       gtk_widget_show_all (GTK_WIDGET (priv->device_mac));
+       align = GTK_WIDGET (gtk_builder_get_object (builder, "wifi_device_alignment"));
+       gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET (priv->device_combo));
+       gtk_widget_show_all (GTK_WIDGET (priv->device_combo));
 
-       /* Set mnemonic widget for device MAC label */
-       label = GTK_LABEL (gtk_builder_get_object (builder, "wifi_device_mac_label"));
-       gtk_label_set_mnemonic_widget (label, GTK_WIDGET (priv->device_mac));
+       /* Set mnemonic widget for Device label */
+       label = GTK_LABEL (gtk_builder_get_object (builder, "wifi_device_label"));
+       gtk_label_set_mnemonic_widget (label, GTK_WIDGET (priv->device_combo));
 
        priv->rate     = GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "wifi_rate"));
        widget = GTK_WIDGET (gtk_builder_get_object (builder, "rate_units"));
@@ -305,9 +307,8 @@ populate_ui (CEPageWifi *self)
        int tx_power_def;
        int mtu_def;
        char *utf8_ssid;
-       char **mac_list;
        const GByteArray *s_mac, *s_bssid;
-       char *s_mac_str, *s_bssid_str;
+       const char *s_ifname;
        GPtrArray *bssid_array;
        char **bssid_list;
        guint32 idx;
@@ -391,27 +392,22 @@ populate_ui (CEPageWifi *self)
        g_ptr_array_add (bssid_array, NULL);
        bssid_list = (char **) g_ptr_array_free (bssid_array, FALSE);
        s_bssid = nm_setting_wireless_get_bssid (setting);
-       s_bssid_str = s_bssid ? nm_utils_hwaddr_ntoa (s_bssid->data, ARPHRD_ETHER) : NULL;
        ce_page_setup_mac_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->bssid),
-                                s_bssid_str, bssid_list);
-       g_free (s_bssid_str);
+                                s_bssid, ARPHRD_ETHER, bssid_list);
        g_strfreev (bssid_list);
        g_signal_connect_swapped (priv->bssid, "changed", G_CALLBACK (ce_page_changed), self);
 
        /* Device MAC address */
-       mac_list = ce_page_get_mac_list (CE_PAGE (self), NM_TYPE_DEVICE_WIFI,
-                                        NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS);
+       s_ifname = nm_connection_get_interface_name (CE_PAGE (self)->connection);
        s_mac = nm_setting_wireless_get_mac_address (setting);
-       s_mac_str = s_mac ? nm_utils_hwaddr_ntoa (s_mac->data, ARPHRD_ETHER) : NULL;
-       ce_page_setup_mac_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->device_mac),
-                                s_mac_str, mac_list);
-       g_free (s_mac_str);
-       g_strfreev (mac_list);
-       g_signal_connect_swapped (priv->device_mac, "changed", G_CALLBACK (ce_page_changed), self);
+       ce_page_setup_device_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->device_combo),
+                                   NM_TYPE_DEVICE_WIFI, s_ifname,
+                                   s_mac, ARPHRD_ETHER, NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS, TRUE);
+       g_signal_connect_swapped (priv->device_combo, "changed", G_CALLBACK (ce_page_changed), self);
 
        /* Cloned MAC address */
-       ce_page_mac_to_entry (nm_setting_wireless_get_cloned_mac_address (setting),
-                             ARPHRD_ETHER, priv->cloned_mac);
+       s_mac = nm_setting_wireless_get_cloned_mac_address (setting);
+       ce_page_mac_to_entry (s_mac, ARPHRD_ETHER, priv->cloned_mac);
        g_signal_connect_swapped (priv->cloned_mac, "changed", G_CALLBACK (ce_page_changed), self);
 
        gtk_spin_button_set_value (priv->rate, (gdouble) nm_setting_wireless_get_rate (setting));
@@ -505,14 +501,19 @@ static void
 ui_to_setting (CEPageWifi *self)
 {
        CEPageWifiPrivate *priv = CE_PAGE_WIFI_GET_PRIVATE (self);
+       NMSettingConnection *s_con;
        GByteArray *ssid;
        GByteArray *bssid = NULL;
        GByteArray *device_mac = NULL;
        GByteArray *cloned_mac = NULL;
+       char *ifname = NULL;
        const char *mode;
        const char *band;
        GtkWidget *entry;
 
+       s_con = nm_connection_get_setting_connection (CE_PAGE (self)->connection);
+       g_return_if_fail (s_con != NULL);
+
        ssid = ce_page_wifi_get_ssid (self);
 
        if (gtk_combo_box_get_active (priv->mode) == 1)
@@ -537,11 +538,14 @@ ui_to_setting (CEPageWifi *self)
        /* BSSID is only valid for infrastructure not for adhoc */
        if (entry && mode && strcmp (mode, "adhoc") != 0)
                bssid = ce_page_entry_to_mac (GTK_ENTRY (entry), ARPHRD_ETHER, NULL);
-       entry = gtk_bin_get_child (GTK_BIN (priv->device_mac));
+       entry = gtk_bin_get_child (GTK_BIN (priv->device_combo));
        if (entry)
-               device_mac = ce_page_entry_to_mac (GTK_ENTRY (entry), ARPHRD_ETHER, NULL);
+               ce_page_device_entry_get (GTK_ENTRY (entry), ARPHRD_ETHER, &ifname, &device_mac);
        cloned_mac = ce_page_entry_to_mac (priv->cloned_mac, ARPHRD_ETHER, NULL);
 
+       g_object_set (s_con,
+                     NM_SETTING_CONNECTION_INTERFACE_NAME, ifname,
+                     NULL);
        g_object_set (priv->setting,
                      NM_SETTING_WIRELESS_SSID, ssid,
                      NM_SETTING_WIRELESS_BSSID, bssid,
@@ -571,33 +575,22 @@ validate (CEPage *page, NMConnection *connection, GError **error)
        CEPageWifi *self = CE_PAGE_WIFI (page);
        CEPageWifiPrivate *priv = CE_PAGE_WIFI_GET_PRIVATE (self);
        gboolean success;
-       gboolean invalid = FALSE;
-       GByteArray *ignore;
        GtkWidget *entry;
 
        entry = gtk_bin_get_child (GTK_BIN (priv->bssid));
        if (entry) {
-               ignore = ce_page_entry_to_mac (GTK_ENTRY (entry), ARPHRD_ETHER, &invalid);
-               if (invalid)
+               if (!ce_page_mac_entry_valid (GTK_ENTRY (entry), ARPHRD_ETHER))
                        return FALSE;
-               if (ignore)
-                       g_byte_array_free (ignore, TRUE);
        }
 
-       entry = gtk_bin_get_child (GTK_BIN (priv->device_mac));
+       entry = gtk_bin_get_child (GTK_BIN (priv->device_combo));
        if (entry) {
-               ignore = ce_page_entry_to_mac (GTK_ENTRY (entry), ARPHRD_ETHER, &invalid);
-               if (invalid)
+               if (!ce_page_device_entry_get (GTK_ENTRY (entry), ARPHRD_ETHER, NULL, NULL))
                        return FALSE;
-               if (ignore)
-                       g_byte_array_free (ignore, TRUE);
        }
 
-       ignore = ce_page_entry_to_mac (priv->cloned_mac, ARPHRD_ETHER, &invalid);
-       if (invalid)
+       if (!ce_page_mac_entry_valid (priv->cloned_mac, ARPHRD_ETHER))
                return FALSE;
-       if (ignore)
-               g_byte_array_free (ignore, TRUE);
 
        ui_to_setting (self);
 
diff --git a/src/connection-editor/page-wimax.c b/src/connection-editor/page-wimax.c
index 3b786c2..97c4d90 100644
--- a/src/connection-editor/page-wimax.c
+++ b/src/connection-editor/page-wimax.c
@@ -38,7 +38,7 @@ typedef struct {
        NMSettingWimax *setting;
 
        GtkEntry *name;
-       GtkComboBoxText *device_mac;  /* Permanent MAC of the device */
+       GtkComboBoxText *device_combo;  /* Device identification (ifname and/or MAC) */
 } CEPageWimaxPrivate;
 
 static void
@@ -53,18 +53,20 @@ wimax_private_init (CEPageWimax *self)
 
        priv->name = GTK_ENTRY (gtk_builder_get_object (builder, "wimax_name"));
 
-       priv->device_mac = GTK_COMBO_BOX_TEXT (gtk_combo_box_text_new_with_entry ());
-       gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (priv->device_mac), 0);
-       gtk_widget_set_tooltip_text (GTK_WIDGET (priv->device_mac),
-                                    _("This option locks this connection to the network device specified by 
its permanent MAC address entered here.  Example: 00:11:22:33:44:55"));
+       priv->device_combo = GTK_COMBO_BOX_TEXT (gtk_combo_box_text_new_with_entry ());
+       gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (priv->device_combo), 0);
+       gtk_widget_set_tooltip_text (GTK_WIDGET (priv->device_combo),
+                                    _("This option locks this connection to the network device specified "
+                                      "either by its interface name or permanent MAC or both. Examples: "
+                                      "\"em1\", \"3C:97:0E:42:1A:19\", \"em1 (3C:97:0E:42:1A:19)\""));
 
-       align = GTK_WIDGET (gtk_builder_get_object (builder, "wimax_device_mac_alignment"));
-       gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET (priv->device_mac));
-       gtk_widget_show_all (GTK_WIDGET (priv->device_mac));
+       align = GTK_WIDGET (gtk_builder_get_object (builder, "wimax_device_alignment"));
+       gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET (priv->device_combo));
+       gtk_widget_show_all (GTK_WIDGET (priv->device_combo));
 
-       /* Set mnemonic widget for device MAC label */
-       label = GTK_LABEL (gtk_builder_get_object (builder, "wimax_device_mac_label"));
-       gtk_label_set_mnemonic_widget (label, GTK_WIDGET (priv->device_mac));
+       /* Set mnemonic widget for Device label */
+       label = GTK_LABEL (gtk_builder_get_object (builder, "wimax_device_label"));
+       gtk_label_set_mnemonic_widget (label, GTK_WIDGET (priv->device_combo));
 }
 
 static void
@@ -72,23 +74,19 @@ populate_ui (CEPageWimax *self)
 {
        CEPageWimaxPrivate *priv = CE_PAGE_WIMAX_GET_PRIVATE (self);
        NMSettingWimax *setting = priv->setting;
-       char **mac_list;
        const GByteArray *s_mac;
-       char *s_mac_str;
+       const char *s_ifname;
 
        gtk_entry_set_text (priv->name, nm_setting_wimax_get_network_name (setting));
        g_signal_connect_swapped (priv->name, "changed", G_CALLBACK (ce_page_changed), self);
 
        /* Device MAC address */
-       mac_list = ce_page_get_mac_list (CE_PAGE (self), NM_TYPE_DEVICE_WIMAX,
-                                        NM_DEVICE_WIMAX_HW_ADDRESS);
+       s_ifname = nm_connection_get_interface_name (CE_PAGE (self)->connection);
        s_mac = nm_setting_wimax_get_mac_address (setting);
-       s_mac_str = s_mac ? nm_utils_hwaddr_ntoa (s_mac->data, ARPHRD_ETHER) : NULL;
-       ce_page_setup_mac_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->device_mac),
-                                s_mac_str, mac_list);
-       g_free (s_mac_str);
-       g_strfreev (mac_list);
-       g_signal_connect_swapped (priv->device_mac, "changed", G_CALLBACK (ce_page_changed), self);
+       ce_page_setup_device_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->device_combo),
+                                   NM_TYPE_DEVICE_WIMAX, s_ifname,
+                                   s_mac, ARPHRD_ETHER, NM_DEVICE_WIMAX_HW_ADDRESS, TRUE);
+       g_signal_connect_swapped (priv->device_combo, "changed", G_CALLBACK (ce_page_changed), self);
 }
 
 static void
@@ -145,21 +143,30 @@ static void
 ui_to_setting (CEPageWimax *self)
 {
        CEPageWimaxPrivate *priv = CE_PAGE_WIMAX_GET_PRIVATE (self);
+       NMSettingConnection *s_con;
        const char *name;
+       char *ifname = NULL;
        GByteArray *device_mac = NULL;
        GtkWidget *entry;
 
+       s_con = nm_connection_get_setting_connection (CE_PAGE (self)->connection);
+       g_return_if_fail (s_con != NULL);
+
        name = gtk_entry_get_text (priv->name);
 
-       entry = gtk_bin_get_child (GTK_BIN (priv->device_mac));
+       entry = gtk_bin_get_child (GTK_BIN (priv->device_combo));
        if (entry)
-               device_mac = ce_page_entry_to_mac (GTK_ENTRY (entry), ARPHRD_ETHER, NULL);
+               ce_page_device_entry_get (GTK_ENTRY (entry), ARPHRD_ETHER, &ifname, &device_mac);
 
+       g_object_set (s_con,
+                     NM_SETTING_CONNECTION_INTERFACE_NAME, ifname,
+                     NULL);
        g_object_set (priv->setting,
                      NM_SETTING_WIMAX_NETWORK_NAME, name,
                      NM_SETTING_WIMAX_MAC_ADDRESS, device_mac,
                      NULL);
 
+       g_free (ifname);
        if (device_mac)
                g_byte_array_free (device_mac, TRUE);
 }
@@ -170,21 +177,16 @@ validate (CEPage *page, NMConnection *connection, GError **error)
        CEPageWimax *self = CE_PAGE_WIMAX (page);
        CEPageWimaxPrivate *priv = CE_PAGE_WIMAX_GET_PRIVATE (self);
        const char *name;
-       gboolean invalid = FALSE;
-       GByteArray *ignore;
        GtkWidget *entry;
 
        name = gtk_entry_get_text (priv->name);
        if (!*name)
                return FALSE;
 
-       entry = gtk_bin_get_child (GTK_BIN (priv->device_mac));
+       entry = gtk_bin_get_child (GTK_BIN (priv->device_combo));
        if (entry) {
-               ignore = ce_page_entry_to_mac (GTK_ENTRY (entry), ARPHRD_ETHER, &invalid);
-               if (invalid)
+               if (!ce_page_device_entry_get (GTK_ENTRY (entry), ARPHRD_ETHER, NULL, NULL))
                        return FALSE;
-               if (ignore)
-                       g_byte_array_free (ignore, TRUE);
        }
 
        ui_to_setting (self);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]