When a slave is activated, it waits for the master device to appear. Once
the master is present, it acquires a reference which is released again
when the slave is deactivated.

Signed-off-by: Thomas Graf <[email protected]>
---
 src/nm-device.c  |    3 +++
 src/nm-manager.c |   18 ++++++++++++++++++
 src/nm-manager.h |    4 ++++
 src/nm-policy.c  |   50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 75 insertions(+), 0 deletions(-)

diff --git a/src/nm-device.c b/src/nm-device.c
index 6142243..89c5000 100644
--- a/src/nm-device.c
+++ b/src/nm-device.c
@@ -3388,6 +3388,9 @@ finalize (GObject *object)
        if (priv->dhcp_anycast_address)
                g_byte_array_free (priv->dhcp_anycast_address, TRUE);
 
+       /* release master reference it still exists */
+       nm_device_set_master (self, NULL);
+
        G_OBJECT_CLASS (nm_device_parent_class)->finalize (object);
 }
 
diff --git a/src/nm-manager.c b/src/nm-manager.c
index b930f17..83a20dd 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -367,6 +367,24 @@ nm_manager_get_device_by_path (NMManager *manager, const 
char *path)
        return NULL;
 }
 
+NMDevice *
+nm_manager_get_device_by_master (NMManager *manager, const char *master, const 
char *driver)
+{
+       GSList *iter;
+
+       g_return_val_if_fail (master != NULL, NULL);
+
+       for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = 
iter->next) {
+               NMDevice *device = NM_DEVICE (iter->data);
+
+               if (!strcmp (nm_device_get_iface (device), master) &&
+                   (!driver || !strcmp (nm_device_get_driver (device), 
driver)))
+                       return device;
+       }
+
+       return NULL;
+}
+
 static gboolean
 manager_sleeping (NMManager *self)
 {
diff --git a/src/nm-manager.h b/src/nm-manager.h
index 22bfca9..ccf5364 100644
--- a/src/nm-manager.h
+++ b/src/nm-manager.h
@@ -83,6 +83,10 @@ void nm_manager_start (NMManager *manager);
 
 GSList *nm_manager_get_devices (NMManager *manager);
 
+NMDevice *nm_manager_get_device_by_master (NMManager *manager,
+                                          const char *master,
+                                          const char *driver);
+
 const char * nm_manager_activate_connection (NMManager *manager,
                                              NMConnection *connection,
                                              const char *specific_object,
diff --git a/src/nm-policy.c b/src/nm-policy.c
index 02292f7..69ab0ef 100644
--- a/src/nm-policy.c
+++ b/src/nm-policy.c
@@ -708,6 +708,33 @@ activate_data_free (ActivateData *data)
        g_free (data);
 }
 
+static NMActStageReturn
+check_master_dependency (NMManager *manager, NMDevice *device, NMConnection 
*connection)
+{
+       NMSettingConnection *s_con;
+       NMDevice *master_device;
+       const char *master;
+
+       s_con = (NMSettingConnection *) nm_connection_get_setting (connection, 
NM_TYPE_SETTING_CONNECTION);
+       g_assert (s_con);
+
+       master = nm_setting_connection_get_master (s_con);
+
+       /* no master defined, proceed with activation */
+       if (!master)
+               return NM_ACT_STAGE_RETURN_SUCCESS;
+
+       master_device = nm_manager_get_device_by_master (manager, master, NULL);
+
+       /* If master device is not yet present, postpone activation until later 
*/
+       if (!master_device)
+               return NM_ACT_STAGE_RETURN_POSTPONE;
+
+       nm_device_set_master (device, master_device);
+
+       return NM_ACT_STAGE_RETURN_SUCCESS;
+}
+
 static gboolean
 auto_activate_device (gpointer user_data)
 {
@@ -763,6 +790,28 @@ auto_activate_device (gpointer user_data)
        best_connection = nm_device_get_best_auto_connection (data->device, 
connections, &specific_object);
        if (best_connection) {
                GError *error = NULL;
+               NMActStageReturn ret;
+
+               ret = check_master_dependency (data->policy->manager, 
data->device, best_connection);
+               switch (ret) {
+               case NM_ACT_STAGE_RETURN_SUCCESS:
+                       break;
+
+               case NM_ACT_STAGE_RETURN_POSTPONE:
+                       nm_log_info (LOGD_DEVICE, "Connection '%s' 
auto-activation postponed: master not available",
+                                    nm_connection_get_id (best_connection));
+                       goto postpone;
+
+               case NM_ACT_STAGE_RETURN_STOP:
+               case NM_ACT_STAGE_RETURN_FAILURE:
+                       /* Avoid further retries and postpone activation */
+                       set_connection_auto_retries (best_connection, 0);
+
+                       nm_log_info (LOGD_DEVICE, "Connection '%s' 
auto-activation not allowed due to master dependency",
+                                    nm_connection_get_id (best_connection));
+
+                       goto postpone;
+               }
 
                nm_log_info (LOGD_DEVICE, "Auto-activating connection '%s'.",
                             nm_connection_get_id (best_connection));
@@ -778,6 +827,7 @@ auto_activate_device (gpointer user_data)
                }
        }
 
+ postpone:
        g_slist_free (connections);
 
  out:
-- 
1.7.6

_______________________________________________
networkmanager-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/networkmanager-list

Reply via email to