summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--introspection/nm-device.xml10
-rw-r--r--libnm-core/nm-dbus-interface.h4
-rw-r--r--libnm-util/NetworkManager.h4
-rw-r--r--src/devices/nm-device-vlan.c108
-rw-r--r--src/devices/nm-device.h15
-rw-r--r--src/nm-manager.c23
6 files changed, 131 insertions, 33 deletions
diff --git a/introspection/nm-device.xml b/introspection/nm-device.xml
index 7aef2f35b1..71b830f108 100644
--- a/introspection/nm-device.xml
+++ b/introspection/nm-device.xml
@@ -648,6 +648,16 @@
A new connection activation was enqueued.
</tp:docstring>
</tp:enumvalue>
+ <tp:enumvalue suffix="PARENT_CHANGED" value="61">
+ <tp:docstring>
+ The device's parent changed.
+ </tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="PARENT_MANAGED_CHANGED" value="62">
+ <tp:docstring>
+ The device parent's management changed.
+ </tp:docstring>
+ </tp:enumvalue>
</tp:enum>
<tp:struct name="NM_DEVICE_STATE_REASON_STRUCT">
diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h
index 9bab80f354..ccc3b3a9e9 100644
--- a/libnm-core/nm-dbus-interface.h
+++ b/libnm-core/nm-dbus-interface.h
@@ -467,6 +467,8 @@ typedef enum {
* @NM_DEVICE_STATE_REASON_MODEM_AVAILABLE: Modem now ready and available
* @NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT: SIM PIN was incorrect
* @NM_DEVICE_STATE_REASON_NEW_ACTIVATION: New connection activation was enqueued
+ * @NM_DEVICE_STATE_REASON_PARENT_CHANGED: the device's parent changed
+ * @NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED: the device parent's management changed
*
* Device state change reason codes
*
@@ -534,6 +536,8 @@ typedef enum {
NM_DEVICE_STATE_REASON_MODEM_AVAILABLE = 58,
NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT = 59,
NM_DEVICE_STATE_REASON_NEW_ACTIVATION = 60,
+ NM_DEVICE_STATE_REASON_PARENT_CHANGED = 61,
+ NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED = 62,
} NMDeviceStateReason;
diff --git a/libnm-util/NetworkManager.h b/libnm-util/NetworkManager.h
index 5a98b8e496..4fa861e88f 100644
--- a/libnm-util/NetworkManager.h
+++ b/libnm-util/NetworkManager.h
@@ -472,6 +472,8 @@ typedef enum {
* @NM_DEVICE_STATE_REASON_MODEM_AVAILABLE: Modem now ready and available
* @NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT: SIM PIN was incorrect
* @NM_DEVICE_STATE_REASON_NEW_ACTIVATION: New connection activation was enqueued
+ * @NM_DEVICE_STATE_REASON_PARENT_CHANGED: the device's parent changed
+ * @NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED: the device parent's management changed
*
* Device state change reason codes
*
@@ -539,6 +541,8 @@ typedef enum {
NM_DEVICE_STATE_REASON_MODEM_AVAILABLE = 58,
NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT = 59,
NM_DEVICE_STATE_REASON_NEW_ACTIVATION = 60,
+ NM_DEVICE_STATE_REASON_PARENT_CHANGED = 61,
+ NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED = 62,
NM_DEVICE_STATE_REASON_LAST = 0xFFFF
} NMDeviceStateReason;
diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c
index b2a2fbf5f4..5513d73abb 100644
--- a/src/devices/nm-device-vlan.c
+++ b/src/devices/nm-device-vlan.c
@@ -107,6 +107,15 @@ bring_up (NMDevice *dev, gboolean *no_firmware)
/******************************************************************/
+static gboolean
+is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
+{
+ if (!NM_DEVICE_VLAN_GET_PRIVATE (device)->parent)
+ return FALSE;
+
+ return NM_DEVICE_CLASS (nm_device_vlan_parent_class)->is_available (device, flags);
+}
+
static void
parent_state_changed (NMDevice *parent,
NMDeviceState new_state,
@@ -124,9 +133,13 @@ parent_state_changed (NMDevice *parent,
}
static void
-nm_device_vlan_set_parent (NMDeviceVlan *device, NMDevice *parent)
+nm_device_vlan_set_parent (NMDeviceVlan *self, NMDevice *parent, gboolean construct)
{
- NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
+ NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
+ NMDevice *device = NM_DEVICE (self);
+
+ if (parent == priv->parent)
+ return;
if (priv->parent_state_id) {
g_signal_handler_disconnect (priv->parent, priv->parent_state_id);
@@ -140,10 +153,56 @@ nm_device_vlan_set_parent (NMDeviceVlan *device, NMDevice *parent)
"state-changed",
G_CALLBACK (parent_state_changed),
device);
+
+ /* Set parent-dependent unmanaged flag */
+ if (construct) {
+ nm_device_set_initial_unmanaged_flag (device,
+ NM_UNMANAGED_PARENT,
+ !nm_device_get_managed (parent));
+ } else {
+ nm_device_set_unmanaged (device,
+ NM_UNMANAGED_PARENT,
+ !nm_device_get_managed (parent),
+ NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED);
+ }
}
+
+ /* Recheck availability now that the parent has changed */
+ nm_device_queue_recheck_available (self,
+ NM_DEVICE_STATE_REASON_PARENT_CHANGED,
+ NM_DEVICE_STATE_REASON_PARENT_CHANGED);
g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_PARENT);
}
+static gboolean
+component_added (NMDevice *device, GObject *component)
+{
+ NMDeviceVlan *self = NM_DEVICE_VLAN (device);
+ NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
+ NMDevice *added_device;
+ int parent_ifindex = -1;
+
+ if (priv->parent)
+ return FALSE;
+
+ if (!NM_IS_DEVICE (component))
+ return FALSE;
+ added_device = NM_DEVICE (component);
+
+ if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, nm_device_get_ifindex (device), &parent_ifindex, NULL)) {
+ _LOGW (LOGD_VLAN, "failed to get VLAN interface info while checking added component.");
+ return FALSE;
+ }
+
+ if (nm_device_get_ifindex (added_device) != parent_ifindex)
+ return FALSE;
+
+ nm_device_vlan_set_parent (self, added_device, FALSE);
+
+ /* Don't claim parent exclusively */
+ return FALSE;
+}
+
/******************************************************************/
static gboolean
@@ -153,6 +212,9 @@ match_parent (NMDeviceVlan *self, const char *parent)
g_return_val_if_fail (parent != NULL, FALSE);
+ if (!priv->parent)
+ return FALSE;
+
if (nm_utils_is_uuid (parent)) {
NMActRequest *parent_req;
NMConnection *parent_connection;
@@ -309,8 +371,7 @@ update_connection (NMDevice *device, NMConnection *connection)
parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex);
g_assert (parent);
- if (priv->parent != parent)
- nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent);
+ nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent, FALSE);
/* Update parent in the connection; default to parent's interface name */
new_parent = nm_device_get_iface (parent);
@@ -426,12 +487,6 @@ constructed (GObject *object)
if (G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed)
G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed (object);
- if (!priv->parent) {
- _LOGE (LOGD_VLAN, "no parent specified.");
- priv->invalid = TRUE;
- return;
- }
-
itype = nm_platform_link_get_type (NM_PLATFORM_GET, ifindex);
if (itype != NM_LINK_TYPE_VLAN) {
_LOGE (LOGD_VLAN, "failed to get VLAN interface type.");
@@ -445,18 +500,27 @@ constructed (GObject *object)
return;
}
- if ( parent_ifindex < 0
- || parent_ifindex != nm_device_get_ip_ifindex (priv->parent)
- || vlan_id < 0) {
+ if (parent_ifindex < 0 || vlan_id < 0) {
_LOGW (LOGD_VLAN, "VLAN parent ifindex (%d) or VLAN ID (%d) invalid.",
parent_ifindex, priv->vlan_id);
priv->invalid = TRUE;
return;
}
+ if (priv->parent && parent_ifindex != nm_device_get_ip_ifindex (priv->parent)) {
+ _LOGW (LOGD_VLAN, "VLAN parent %s (%d) and parent ifindex %d don't match.",
+ nm_device_get_iface (priv->parent),
+ nm_device_get_ifindex (priv->parent),
+ parent_ifindex);
+ priv->invalid = TRUE;
+ return;
+ }
+
priv->vlan_id = vlan_id;
- _LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s",
- priv->vlan_id, nm_device_get_iface (priv->parent));
+ _LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s (%d)",
+ priv->vlan_id,
+ priv->parent ? nm_device_get_iface (priv->parent) : "unknown",
+ parent_ifindex);
}
static void
@@ -489,7 +553,7 @@ set_property (GObject *object, guint prop_id,
switch (prop_id) {
case PROP_INT_PARENT_DEVICE:
- nm_device_vlan_set_parent (NM_DEVICE_VLAN (object), g_value_get_object (value));
+ nm_device_vlan_set_parent (NM_DEVICE_VLAN (object), g_value_get_object (value), TRUE);
break;
case PROP_VLAN_ID:
priv->vlan_id = g_value_get_uint (value);
@@ -512,7 +576,7 @@ dispose (GObject *object)
}
priv->disposed = TRUE;
- nm_device_vlan_set_parent (self, NULL);
+ nm_device_vlan_set_parent (self, NULL, FALSE);
G_OBJECT_CLASS (nm_device_vlan_parent_class)->dispose (object);
}
@@ -551,6 +615,8 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass)
parent_class->act_stage1_prepare = act_stage1_prepare;
parent_class->ip4_config_pre_commit = ip4_config_pre_commit;
parent_class->deactivate = deactivate;
+ parent_class->is_available = is_available;
+ parent_class->component_added = component_added;
parent_class->check_connection_compatible = check_connection_compatible;
parent_class->complete_connection = complete_connection;
@@ -626,10 +692,6 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
device = NULL;
}
- /* Set initial parent-dependent unmanaged flag */
- if (device)
- nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_PARENT, !nm_device_get_managed (parent));
-
return device;
}
@@ -682,10 +744,6 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
device = NULL;
}
- /* Set initial parent-dependent unmanaged flag */
- if (device)
- nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_PARENT, !nm_device_get_managed (parent));
-
return device;
}
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index f7ba2a5296..e3daa9b615 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -237,6 +237,21 @@ typedef struct {
gboolean (* have_any_ready_slaves) (NMDevice *self,
const GSList *slaves);
+ /**
+ * component_added:
+ * @self: the #NMDevice
+ * @component: the component (device, modem, etc) which was added
+ *
+ * Notifies @self that a new component was added to the Manager. This
+ * may include any kind of %GObject subclass, and the device is expected
+ * to match only specific components they care about, like %NMModem objects
+ * or %NMDevice objects.
+ *
+ * Returns: %TRUE if the component was claimed exclusively and no further
+ * devices should be notified of the new component. %FALSE to indicate
+ * that the component was not exclusively claimed and other devices should
+ * be notified.
+ */
gboolean (* component_added) (NMDevice *self, GObject *component);
gboolean (* owns_iface) (NMDevice *self, const char *iface);
diff --git a/src/nm-manager.c b/src/nm-manager.c
index fe80156712..755b1f1916 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -1776,6 +1776,18 @@ device_ip_iface_changed (NMDevice *device,
}
}
+static gboolean
+notify_component_added (NMManager *self, GObject *component)
+{
+ GSList *iter;
+
+ for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) {
+ if (nm_device_notify_component_added (NM_DEVICE (iter->data), component))
+ return TRUE;
+ }
+ return FALSE;
+}
+
/**
* add_device:
* @self: the #NMManager
@@ -1893,6 +1905,8 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume)
g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
g_object_notify (G_OBJECT (self), NM_MANAGER_DEVICES);
+ notify_component_added (self, G_OBJECT (device));
+
/* New devices might be master interfaces for virtual interfaces; so we may
* need to create new virtual interfaces now.
*/
@@ -1929,14 +1943,7 @@ factory_component_added_cb (NMDeviceFactory *factory,
GObject *component,
gpointer user_data)
{
- NMManager *self = NM_MANAGER (user_data);
- GSList *iter;
-
- for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) {
- if (nm_device_notify_component_added (NM_DEVICE (iter->data), component))
- return TRUE;
- }
- return FALSE;
+ return notify_component_added (NM_MANAGER (user_data), component);
}
#define PLUGIN_PREFIX "libnm-device-plugin-"