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



commit 286168120566e4a543c91a11e8d600bbd6d9c3ca
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

 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..ea50805 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 = NULL;
+       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]