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



commit ba01263f9efc66d6f563451ada09b3fd0abd03ec
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 a corresponding
    page (like bond, bridge, etc.) because it is mandatory.
    
    https://bugzilla.redhat.com/show_bug.cgi?id=1139536

 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             |  299 +++++++++++++++++++++------
 src/connection-editor/ce-page.h             |   17 ++-
 src/connection-editor/page-bluetooth.c      |   13 +-
 src/connection-editor/page-ethernet.c       |   84 ++++----
 src/connection-editor/page-infiniband.c     |   66 ++++---
 src/connection-editor/page-vlan.c           |   15 +-
 src/connection-editor/page-wifi.c           |  101 +++++-----
 src/connection-editor/page-wimax.c          |   67 ++++---
 12 files changed, 437 insertions(+), 249 deletions(-)
---
diff --git a/src/connection-editor/ce-page-ethernet.ui b/src/connection-editor/ce-page-ethernet.ui
index 8e2fcb4..1bade41 100644
--- a/src/connection-editor/ce-page-ethernet.ui
+++ b/src/connection-editor/ce-page-ethernet.ui
@@ -163,11 +163,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>
@@ -178,7 +178,7 @@
       </packing>
     </child>
     <child>
-      <object class="GtkVBox" id="ethernet_device_mac_vbox">
+      <object class="GtkVBox" id="ethernet_device_vbox">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <child>
diff --git a/src/connection-editor/ce-page-infiniband.ui b/src/connection-editor/ce-page-infiniband.ui
index 4bb2fba..c5835fe 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="GtkVBox" id="infiniband_device_mac_vbox">
+      <object class="GtkVBox" id="infiniband_device_vbox">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <child>
diff --git a/src/connection-editor/ce-page-wifi.ui b/src/connection-editor/ce-page-wifi.ui
index beaeb9c..b5f6ea5 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="GtkVBox" id="wifi_device_mac_vbox">
+      <object class="GtkVBox" id="wifi_device_vbox">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <child>
@@ -134,11 +134,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 bdd4682..a7b1c3f 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="GtkVBox" id="wimax_device_mac_vbox">
+      <object class="GtkVBox" id="wimax_device_vbox">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <child>
@@ -26,11 +26,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 6a880e8..abd6504 100644
--- a/src/connection-editor/ce-page.c
+++ b/src/connection-editor/ce-page.c
@@ -146,105 +146,280 @@ 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 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);
+
+               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);
+       }
+}
+
+/* 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 *mac, char **mac_list)
+{
+       char **iter, *active_mac = NULL;
+       int i, active_idx = -1;
+
+       for (iter = mac_list, i = 0; iter && *iter; iter++, i++) {
+               gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), *iter);
+               if (mac && *iter && nm_utils_hwaddr_matches (mac, -1, *iter, -1)) {
+                       active_mac = *iter;
+                       active_idx = i;
+               }
+       }
+       _set_active_combo_item (combo, mac, active_mac, active_idx);
+}
+
+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 nm_utils_hwaddr_valid (mac, nm_utils_hwaddr_len (type));
+}
+
+static char **
+_get_device_list (CEPage *self,
+                  GType device_type,
+                  gboolean set_ifname,
+                  const char *mac_property,
+                  gboolean ifname_first)
 {
        const GPtrArray *devices;
-       GPtrArray *macs;
+       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;
 
-       macs = g_ptr_array_new ();
+       interfaces = g_ptr_array_new ();
        devices = nm_client_get_devices (self->client);
        for (i = 0; i < devices->len; i++) {
                NMDevice *dev = g_ptr_array_index (devices, i);
-               const char *iface;
-               char *mac, *item;
+               const char *ifname;
+               char *mac;
+               char *item;
 
                if (!G_TYPE_CHECK_INSTANCE_TYPE (dev, device_type))
                        continue;
 
-               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);
+               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);
+
+       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;
        }
 
-       g_ptr_array_add (macs, NULL);
-       return (char **)g_ptr_array_free (macs, FALSE);
+       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, 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 && nm_utils_hwaddr_matches (mac, -1, first, -1))
+               || (second && nm_utils_hwaddr_matches (mac, -1, second, -1))))
+               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_mac_combo (CEPage *self, GtkComboBox *combo,
-                         const char *current_mac, char **mac_list)
+ce_page_setup_device_combo (CEPage *self,
+                            GtkComboBox *combo,
+                            GType device_type,
+                            const char *ifname,
+                            const char *mac,
+                            const char *mac_property,
+                            gboolean ifname_first)
 {
-       char **iter, *active_mac = NULL;
+       char **iter, *active_item = NULL;
        int i, active_idx = -1;
-       int current_mac_len;
-       GtkWidget *entry;
+       char **device_list;
+       char *item;
+
+       device_list = _get_device_list (self, device_type, TRUE, mac_property, ifname_first);
 
-       if (current_mac)
-               current_mac_len = strlen (current_mac);
+       if (ifname && mac)
+               item = g_strdup_printf ("%s (%s)", ifname, mac);
+       else if (!ifname && !mac)
+               item = NULL;
        else
-               current_mac_len = -1;
+               item = g_strdup (ifname ? ifname : mac);
 
-       for (iter = mac_list, i = 0; iter && *iter; iter++, i++) {
+       for (iter = device_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] == ' ')) {
-                       active_mac = *iter;
+               if (_device_entries_match (ifname, mac, *iter)) {
+                       active_item = *iter;
                        active_idx = i;
                }
        }
+       _set_active_combo_item (combo, item, active_item, active_idx);
 
-       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);
-
-               entry = gtk_bin_get_child (GTK_BIN (combo));
-               if (entry)
-                       gtk_entry_set_text (GTK_ENTRY (entry), active_mac ? active_mac : current_mac);
-       }
+       g_free (item);
+       g_strfreev (device_list);
 }
 
-char *
-ce_page_entry_to_mac (GtkEntry *entry, int type, gboolean *invalid)
+gboolean
+ce_page_device_entry_get (GtkEntry *entry, int type, char **ifname, char **mac)
 {
-       const char *sp, *temp;
-       char *mac;
+       char *first, *second;
+       const char *ifname_tmp = NULL, *mac_tmp = NULL;
+       gboolean valid = TRUE;
 
-       g_return_val_if_fail (entry != NULL, NULL);
-       g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
+       g_return_val_if_fail (entry != NULL, FALSE);
+       g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
 
-       if (invalid)
-               g_return_val_if_fail (*invalid == FALSE, NULL);
+       valid = _device_entry_parse (gtk_entry_get_text (entry), &first, &second);
 
-       temp = gtk_entry_get_text (entry);
-       if (!temp || !*temp)
-               return NULL;
+       if (first) {
+               if (nm_utils_hwaddr_valid (first, nm_utils_hwaddr_len (type)))
+                       mac_tmp = first;
+               else if (nm_utils_iface_valid_name (first))
+                       ifname_tmp = first;
+               else
+                       valid = FALSE;
+       }
+       if (second) {
+               if (nm_utils_hwaddr_valid (second, nm_utils_hwaddr_len (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;
+       }
 
-       sp = strchr (temp, ' ');
-       if (sp)
-               mac = g_strndup (temp, sp - temp);
-       else
-               mac = g_strdup (temp);
+       if (ifname)
+               *ifname = g_strdup (ifname_tmp);
+       if (mac)
+               *mac = g_strdup (mac_tmp);
 
-       if (!nm_utils_hwaddr_valid (mac, nm_utils_hwaddr_len (type))) {
-               g_free (mac);
-               if (invalid)
-                       *invalid = TRUE;
-               return NULL;
-       }
-       return mac;
+       g_free (first);
+       g_free (second);
+
+       return valid;
 }
 
 char *
diff --git a/src/connection-editor/ce-page.h b/src/connection-editor/ce-page.h
index 05595ab..1251aea 100644
--- a/src/connection-editor/ce-page.h
+++ b/src/connection-editor/ce-page.h
@@ -103,14 +103,23 @@ 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);
+                              const char *mac, 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 char *mac,
+                                 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, char **mac);
 
 void ce_page_changed (CEPage *self);
 
-char *ce_page_entry_to_mac (GtkEntry *entry, int type, gboolean *invalid);
-
 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 aa20f06..7ee3004 100644
--- a/src/connection-editor/page-bluetooth.c
+++ b/src/connection-editor/page-bluetooth.c
@@ -131,13 +131,12 @@ static void
 ui_to_setting (CEPageBluetooth *self)
 {
        CEPageBluetoothPrivate *priv = CE_PAGE_BLUETOOTH_GET_PRIVATE (self);
-       char *bdaddr;
+       const char *bdaddr;
 
-       bdaddr = ce_page_entry_to_mac (priv->bdaddr, ARPHRD_ETHER, NULL);
+       bdaddr = gtk_entry_get_text (priv->bdaddr);
        g_object_set (priv->setting,
-                     NM_SETTING_BLUETOOTH_BDADDR, bdaddr,
+                     NM_SETTING_BLUETOOTH_BDADDR, bdaddr && *bdaddr ? bdaddr : NULL,
                      NULL);
-       g_free (bdaddr);
 }
 
 static gboolean
@@ -145,13 +144,9 @@ validate (CEPage *page, NMConnection *connection, GError **error)
 {
        CEPageBluetooth *self = CE_PAGE_BLUETOOTH (page);
        CEPageBluetoothPrivate *priv = CE_PAGE_BLUETOOTH_GET_PRIVATE (self);
-       char *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;
-       g_free (bdaddr);
 
        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 e82c1b9..5363d9a 100644
--- a/src/connection-editor/page-ethernet.c
+++ b/src/connection-editor/page-ethernet.c
@@ -37,8 +37,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;
@@ -68,19 +68,21 @@ 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)\""));
 
-       vbox = GTK_WIDGET (gtk_builder_get_object (builder, "ethernet_device_mac_vbox"));
-       gtk_container_add (GTK_CONTAINER (vbox), GTK_WIDGET (priv->device_mac));
-       gtk_widget_set_halign (GTK_WIDGET (priv->device_mac), GTK_ALIGN_FILL);
-       gtk_widget_show_all (GTK_WIDGET (priv->device_mac));
+       vbox = GTK_WIDGET (gtk_builder_get_object (builder, "ethernet_device_vbox"));
+       gtk_container_add (GTK_CONTAINER (vbox), GTK_WIDGET (priv->device_combo));
+       gtk_widget_set_halign (GTK_WIDGET (priv->device_combo), GTK_ALIGN_FILL);
+       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"));
@@ -106,8 +108,7 @@ populate_ui (CEPageEthernet *self)
        int port_idx = PORT_DEFAULT;
        int speed_idx;
        int mtu_def;
-       char **mac_list;
-       const char *s_mac_str;
+       const char *s_mac, *s_ifname;
 
        /* Port */
        port = nm_setting_wired_get_port (setting);
@@ -154,19 +155,18 @@ 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);
-       s_mac_str = nm_setting_wired_get_mac_address (setting);
-       ce_page_setup_mac_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->device_mac),
-                                s_mac_str, mac_list);
-       g_strfreev (mac_list);
-       g_signal_connect (priv->device_mac, "changed", G_CALLBACK (stuff_changed), self);
+       /* Device ifname/MAC */
+        s_ifname = nm_connection_get_interface_name (CE_PAGE (self)->connection);
+       s_mac = nm_setting_wired_get_mac_address (setting);
+       ce_page_setup_device_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->device_combo),
+                                   NM_TYPE_DEVICE_ETHERNET, s_ifname,
+                                   s_mac, NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS, TRUE);
+       g_signal_connect (priv->device_combo, "changed", G_CALLBACK (stuff_changed), self);
 
        /* Cloned MAC address */
-       s_mac_str = nm_setting_wired_get_cloned_mac_address (setting);
-       if (s_mac_str)
-               gtk_entry_set_text (priv->cloned_mac, s_mac_str);
+       s_mac = nm_setting_wired_get_cloned_mac_address (setting);
+       if (s_mac)
+               gtk_entry_set_text (priv->cloned_mac, s_mac);
        g_signal_connect (priv->cloned_mac, "changed", G_CALLBACK (stuff_changed), self);
 
        /* MTU */
@@ -253,12 +253,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;
        char *device_mac = NULL;
-       char *cloned_mac = NULL;
+       const char *cloned_mac;
        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:
@@ -297,14 +302,17 @@ 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);
-       cloned_mac = ce_page_entry_to_mac (priv->cloned_mac, ARPHRD_ETHER, NULL);
+               ce_page_device_entry_get (GTK_ENTRY (entry), ARPHRD_ETHER, &ifname, &device_mac);
+       cloned_mac = gtk_entry_get_text (priv->cloned_mac);
 
+       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,
+                     NM_SETTING_WIRED_CLONED_MAC_ADDRESS, cloned_mac && *cloned_mac ? cloned_mac : NULL,
                      NM_SETTING_WIRED_PORT, port,
                      NM_SETTING_WIRED_SPEED, speed,
                      NM_SETTING_WIRED_DUPLEX, gtk_toggle_button_get_active (priv->duplex) ? "full" : "half",
@@ -312,8 +320,8 @@ ui_to_setting (CEPageEthernet *self)
                      NM_SETTING_WIRED_MTU, (guint32) gtk_spin_button_get_value_as_int (priv->mtu),
                      NULL);
 
+       g_free (ifname);
        g_free (device_mac);
-       g_free (cloned_mac);
 }
 
 static gboolean
@@ -321,22 +329,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;
-       char *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;
-               g_free (ignore);
        }
 
-       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;
-       g_free (ignore);
 
        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 7cef6b8..a936f44 100644
--- a/src/connection-editor/page-infiniband.c
+++ b/src/connection-editor/page-infiniband.c
@@ -35,7 +35,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;
@@ -54,19 +54,22 @@ 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)\""));
 
-       vbox = GTK_WIDGET (gtk_builder_get_object (builder, "infiniband_device_mac_vbox"));
-       gtk_container_add (GTK_CONTAINER (vbox), GTK_WIDGET (priv->device_mac));
-       gtk_widget_set_halign (GTK_WIDGET (priv->device_mac), GTK_ALIGN_FILL);
-       gtk_widget_show_all (GTK_WIDGET (priv->device_mac));
+       vbox = GTK_WIDGET (gtk_builder_get_object (builder, "infiniband_device_vbox"));
+       gtk_container_add (GTK_CONTAINER (vbox), GTK_WIDGET (priv->device_combo));
+       gtk_widget_set_halign (GTK_WIDGET (priv->device_combo), GTK_ALIGN_FILL);
+       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"));
@@ -86,8 +89,7 @@ populate_ui (CEPageInfiniband *self)
        const char *mode;
        int mode_idx = TRANSPORT_MODE_DATAGRAM;
        int mtu_def;
-       char **mac_list;
-       const char *s_mac_str;
+       const char *s_ifname, *s_mac;
 
        /* Port */
        mode = nm_setting_infiniband_get_transport_mode (setting);
@@ -99,14 +101,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);
-       s_mac_str = nm_setting_infiniband_get_mac_address (setting);
-       ce_page_setup_mac_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->device_mac),
-                                s_mac_str, mac_list);
-       g_strfreev (mac_list);
-       g_signal_connect (priv->device_mac, "changed", G_CALLBACK (stuff_changed), self);
+       /* Device */
+        s_ifname = nm_connection_get_interface_name (CE_PAGE (self)->connection);
+       s_mac = nm_setting_infiniband_get_mac_address (setting);
+       ce_page_setup_device_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->device_combo),
+                                   NM_TYPE_DEVICE_INFINIBAND, s_ifname,
+                                   s_mac, 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);
@@ -172,26 +173,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;
        char *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 = ce_page_entry_to_mac (GTK_ENTRY (entry), ARPHRD_INFINIBAND, NULL);
+               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);
        g_free (device_mac);
 }
 
@@ -200,16 +210,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;
-       char *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;
-               g_free (ignore);
        }
 
        ui_to_setting (self);
diff --git a/src/connection-editor/page-vlan.c b/src/connection-editor/page-vlan.c
index 3a7a147..ca0bdfe 100644
--- a/src/connection-editor/page-vlan.c
+++ b/src/connection-editor/page-vlan.c
@@ -425,7 +425,7 @@ populate_ui (CEPageVlan *self)
                }
        }
        g_signal_connect (priv->parent, "changed", G_CALLBACK (parent_changed), self);
-       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);
 
        if (current_parent)
                priv->last_parent = g_strndup (current_parent, strcspn (current_parent, " "));
@@ -515,7 +515,7 @@ ui_to_setting (CEPageVlan *self)
        CEPageVlanPrivate *priv = CE_PAGE_VLAN_GET_PRIVATE (self);
        NMConnection *connection = CE_PAGE (self)->connection;
        NMSettingConnection *s_con = nm_connection_get_setting_connection (connection);
-       char *cloned_mac = NULL;
+       const char *cloned_mac;
        VlanParent *parent = NULL;
        int active_id, parent_id, vid;
        const char *parent_iface = NULL, *parent_uuid = NULL;
@@ -579,7 +579,9 @@ ui_to_setting (CEPageVlan *self)
                      NULL);
 
        if (hwtype != G_TYPE_NONE) {
-               cloned_mac = ce_page_entry_to_mac (priv->cloned_mac, ARPHRD_ETHER, NULL);
+               cloned_mac = gtk_entry_get_text (priv->cloned_mac);
+               if (cloned_mac && !*cloned_mac)
+                       cloned_mac = NULL;
                mtu_set = g_ascii_isdigit (*gtk_entry_get_text (GTK_ENTRY (priv->mtu)));
                mtu = gtk_spin_button_get_value_as_int (priv->mtu);
 
@@ -594,7 +596,6 @@ ui_to_setting (CEPageVlan *self)
                                      NM_SETTING_WIRED_MTU, (guint32) mtu,
                                      NULL);
 
-                       g_free(cloned_mac);
                } else if (priv->s_hw) {
                        nm_connection_remove_setting (connection, G_OBJECT_TYPE (priv->s_hw));
                        priv->s_hw = NULL;
@@ -609,8 +610,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;
-       char *ignore;
        const char *parent;
        char *parent_iface;
 
@@ -625,10 +624,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;
-       g_free (ignore);
 
        ui_to_setting (self);
 
diff --git a/src/connection-editor/page-wifi.c b/src/connection-editor/page-wifi.c
index 97a49c3..ee935ae 100644
--- a/src/connection-editor/page-wifi.c
+++ b/src/connection-editor/page-wifi.c
@@ -39,8 +39,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;
@@ -84,19 +84,21 @@ 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"));
-
-       vbox = GTK_WIDGET (gtk_builder_get_object (builder, "wifi_device_mac_vbox"));
-       gtk_container_add (GTK_CONTAINER (vbox), GTK_WIDGET (priv->device_mac));
-       gtk_widget_set_halign (GTK_WIDGET (priv->device_mac), GTK_ALIGN_FILL);
-       gtk_widget_show_all (GTK_WIDGET (priv->device_mac));
-
-       /* 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));
+       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)\""));
+
+       vbox = GTK_WIDGET (gtk_builder_get_object (builder, "wifi_device_vbox"));
+       gtk_container_add (GTK_CONTAINER (vbox), GTK_WIDGET (priv->device_combo));
+       gtk_widget_set_halign (GTK_WIDGET (priv->device_combo), GTK_ALIGN_FILL);
+       gtk_widget_show_all (GTK_WIDGET (priv->device_combo));
+
+       /* 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"));
@@ -302,8 +304,7 @@ populate_ui (CEPageWifi *self)
        int tx_power_def;
        int mtu_def;
        char *utf8_ssid;
-       char **mac_list;
-       const char *s_mac_str, *s_bssid_str;
+       const char *s_ifname, *s_mac, *s_bssid;
        GPtrArray *bssid_array;
        char **bssid_list;
        guint32 idx;
@@ -381,25 +382,24 @@ populate_ui (CEPageWifi *self)
                g_ptr_array_add (bssid_array, g_strdup (nm_setting_wireless_get_seen_bssid (setting, idx)));
        g_ptr_array_add (bssid_array, NULL);
        bssid_list = (char **) g_ptr_array_free (bssid_array, FALSE);
-       s_bssid_str = nm_setting_wireless_get_bssid (setting);
+       s_bssid = nm_setting_wireless_get_bssid (setting);
        ce_page_setup_mac_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->bssid),
-                                s_bssid_str, bssid_list);
+                                s_bssid, 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_mac_str = nm_setting_wireless_get_mac_address (setting);
-       ce_page_setup_mac_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->device_mac),
-                                s_mac_str, mac_list);
-       g_strfreev (mac_list);
-       g_signal_connect_swapped (priv->device_mac, "changed", G_CALLBACK (ce_page_changed), self);
+        s_ifname = nm_connection_get_interface_name (CE_PAGE (self)->connection);
+       s_mac = nm_setting_wireless_get_mac_address (setting);
+       ce_page_setup_device_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->device_combo),
+                                   NM_TYPE_DEVICE_WIFI, s_ifname,
+                                   s_mac, NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS, TRUE);
+       g_signal_connect_swapped (priv->device_combo, "changed", G_CALLBACK (ce_page_changed), self);
 
        /* Cloned MAC address */
-       s_mac_str = nm_setting_wireless_get_cloned_mac_address (setting);
-       if (s_mac_str)
-               gtk_entry_set_text (priv->cloned_mac, s_mac_str);
+       s_mac = nm_setting_wireless_get_cloned_mac_address (setting);
+       if (s_mac)
+               gtk_entry_set_text (priv->cloned_mac, s_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));
@@ -490,14 +490,19 @@ static void
 ui_to_setting (CEPageWifi *self)
 {
        CEPageWifiPrivate *priv = CE_PAGE_WIFI_GET_PRIVATE (self);
+       NMSettingConnection *s_con;
        GBytes *ssid;
-       char *bssid = NULL;
+       const char *bssid;
+       char *ifname = NULL;
        char *device_mac = NULL;
-       char *cloned_mac = NULL;
+       const char *cloned_mac;
        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)
@@ -521,17 +526,20 @@ ui_to_setting (CEPageWifi *self)
        entry = gtk_bin_get_child (GTK_BIN (priv->bssid));
        /* 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));
+               bssid = gtk_entry_get_text (GTK_ENTRY (entry));
+       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);
-       cloned_mac = ce_page_entry_to_mac (priv->cloned_mac, ARPHRD_ETHER, NULL);
+               ce_page_device_entry_get (GTK_ENTRY (entry), ARPHRD_ETHER, &ifname, &device_mac);
+       cloned_mac = gtk_entry_get_text (priv->cloned_mac);
 
+       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,
+                     NM_SETTING_WIRELESS_BSSID, bssid && *bssid ? bssid : NULL,
                      NM_SETTING_WIRELESS_MAC_ADDRESS, device_mac,
-                     NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, cloned_mac,
+                     NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, cloned_mac && *cloned_mac ? cloned_mac : NULL,
                      NM_SETTING_WIRELESS_MODE, mode,
                      NM_SETTING_WIRELESS_BAND, band,
                      NM_SETTING_WIRELESS_CHANNEL, gtk_spin_button_get_value_as_int (priv->channel),
@@ -541,9 +549,8 @@ ui_to_setting (CEPageWifi *self)
                      NULL);
 
        g_bytes_unref (ssid);
+       g_free (ifname);
        g_free (device_mac);
-       g_free (cloned_mac);
-       g_free (bssid);
 }
 
 static gboolean
@@ -552,30 +559,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;
-       char *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;
-               g_free (ignore);
        }
 
-       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;
-               g_free (ignore);
        }
 
-       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;
-       g_free (ignore);
 
        ui_to_setting (self);
 
diff --git a/src/connection-editor/page-wimax.c b/src/connection-editor/page-wimax.c
index aff955f..4444d58 100644
--- a/src/connection-editor/page-wimax.c
+++ b/src/connection-editor/page-wimax.c
@@ -33,7 +33,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
@@ -48,19 +48,21 @@ 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"));
-
-       vbox = GTK_WIDGET (gtk_builder_get_object (builder, "wimax_device_mac_vbox"));
-       gtk_container_add (GTK_CONTAINER (vbox), GTK_WIDGET (priv->device_mac));
-       gtk_widget_set_halign (GTK_WIDGET (priv->device_mac), GTK_ALIGN_FILL);
-       gtk_widget_show_all (GTK_WIDGET (priv->device_mac));
-
-       /* 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));
+       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)\""));
+
+       vbox = GTK_WIDGET (gtk_builder_get_object (builder, "wimax_device_vbox"));
+       gtk_container_add (GTK_CONTAINER (vbox), GTK_WIDGET (priv->device_combo));
+       gtk_widget_set_halign (GTK_WIDGET (priv->device_combo), GTK_ALIGN_FILL);
+       gtk_widget_show_all (GTK_WIDGET (priv->device_combo));
+
+       /* 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
@@ -68,20 +70,18 @@ populate_ui (CEPageWimax *self)
 {
        CEPageWimaxPrivate *priv = CE_PAGE_WIMAX_GET_PRIVATE (self);
        NMSettingWimax *setting = priv->setting;
-       char **mac_list;
-       const char *s_mac_str;
+       const char *s_mac, *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_mac_str = nm_setting_wimax_get_mac_address (setting);
-       ce_page_setup_mac_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->device_mac),
-                                s_mac_str, mac_list);
-       g_strfreev (mac_list);
-       g_signal_connect_swapped (priv->device_mac, "changed", G_CALLBACK (ce_page_changed), self);
+        s_ifname = nm_connection_get_interface_name (CE_PAGE (self)->connection);
+       s_mac = nm_setting_wimax_get_mac_address (setting);
+       ce_page_setup_device_combo (CE_PAGE (self), GTK_COMBO_BOX (priv->device_combo),
+                                   NM_TYPE_DEVICE_WIMAX, s_ifname,
+                                   s_mac, NM_DEVICE_WIMAX_HW_ADDRESS, TRUE);
+       g_signal_connect_swapped (priv->device_combo, "changed", G_CALLBACK (ce_page_changed), self);
 }
 
 static void
@@ -136,21 +136,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;
        char *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);
        g_free (device_mac);
 }
 
@@ -160,20 +169,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;
-       char *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;
-               g_free (ignore);
        }
 
        ui_to_setting (self);



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