From 4dbaac4ba24ebc8b257fffe5197cc8e362804a58 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 24 Sep 2014 16:58:07 -0500 Subject: [PATCH] core: create devices first and realize them later Unrealized devices aren't backed by kernel resources and so won't know all of their attributes. That means three things: 1) they must update their attributes when they become realized 2) they must clear those attributes when unrealized 3) they must be looser in checking compatible connections until they are realized This requires that the setup() function be split into two parts, start & finish, because finish must be run after add_device() Also, we can simplify whether to pay attention to 'recheck-assume', which is now dependent on priv->is_nm_owned, because the only case where NM should *not* listen for the 'recheck-assume' signal is when the device is a software device created by NM itself. That logic was previously spread across the callers of add_device() but is now consolidated into nm-manager.c::device_realized() and nm-device.c::nm_device_create_and_realize(). --- src/devices/nm-device-bridge.c | 2 +- src/devices/nm-device-ethernet.c | 6 +- src/devices/nm-device-generic.c | 6 +- src/devices/nm-device-infiniband.c | 2 +- src/devices/nm-device-ip-tunnel.c | 64 +++--- src/devices/nm-device-tun.c | 42 ++-- src/devices/nm-device-vlan.c | 34 +-- src/devices/nm-device-vxlan.c | 6 +- src/devices/nm-device.c | 117 ++++++----- src/devices/nm-device.h | 23 +- src/devices/wifi/nm-device-wifi.c | 6 +- src/nm-active-connection.c | 8 +- src/nm-manager.c | 323 ++++++++++++++++------------- 13 files changed, 358 insertions(+), 281 deletions(-) diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index b54b2e0a01..2a2f234c16 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -97,7 +97,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) return FALSE; mac_address = nm_setting_bridge_get_mac_address (s_bridge); - if (mac_address) { + if (mac_address && nm_device_is_real (device)) { const char *hw_addr; hw_addr = nm_device_get_hw_address (device); diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index fe45536609..6f0c3e8881 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -305,9 +305,9 @@ nm_device_ethernet_init (NMDeviceEthernet *self) } static void -setup (NMDevice *device, NMPlatformLink *plink) +setup_start (NMDevice *device, NMPlatformLink *plink) { - NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->setup (device, plink); + NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->setup_start (device, plink); g_object_notify (G_OBJECT (device), NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS); } @@ -1716,7 +1716,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) object_class->set_property = set_property; parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->setup = setup; + parent_class->setup_start = setup_start; parent_class->check_connection_compatible = check_connection_compatible; parent_class->complete_connection = complete_connection; parent_class->new_default_connection = new_default_connection; diff --git a/src/devices/nm-device-generic.c b/src/devices/nm-device-generic.c index 37eae35bdc..70ae48c678 100644 --- a/src/devices/nm-device-generic.c +++ b/src/devices/nm-device-generic.c @@ -61,13 +61,13 @@ get_type_description (NMDevice *device) } static void -setup (NMDevice *device, NMPlatformLink *plink) +setup_start (NMDevice *device, NMPlatformLink *plink) { NMDeviceGeneric *self = NM_DEVICE_GENERIC (device); NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE (self); int ifindex; - NM_DEVICE_CLASS (nm_device_generic_parent_class)->setup (device, plink); + NM_DEVICE_CLASS (nm_device_generic_parent_class)->setup_start (device, plink); g_clear_pointer (&priv->type_description, g_free); ifindex = nm_device_get_ip_ifindex (NM_DEVICE (self)); @@ -203,7 +203,7 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass) object_class->get_property = get_property; object_class->set_property = set_property; - parent_class->setup = setup; + parent_class->setup_start = setup_start; parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->get_type_description = get_type_description; parent_class->check_connection_compatible = check_connection_compatible; diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index a647245f63..e0c3c62d76 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -149,7 +149,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) if (!s_infiniband) return FALSE; - if (s_infiniband) { + if (nm_device_is_real (device)) { const char *mac; mac = nm_setting_infiniband_get_mac_address (s_infiniband); diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c index 4cf2a689f6..64c3a52146 100644 --- a/src/devices/nm-device-ip-tunnel.c +++ b/src/devices/nm-device-ip-tunnel.c @@ -503,41 +503,43 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) if (!s_ip_tunnel) return FALSE; - /* Check parent interface; could be an interface name or a UUID */ - parent = nm_setting_ip_tunnel_get_parent (s_ip_tunnel); - if (parent) { - if (!match_parent (priv->parent, parent)) - return FALSE; - } - if (nm_setting_ip_tunnel_get_mode (s_ip_tunnel) != priv->mode) return FALSE; - if (!address_equal_pp (priv->addr_family, - nm_setting_ip_tunnel_get_local (s_ip_tunnel), - priv->local)) - return FALSE; + if (nm_device_is_real (device)) { + /* Check parent interface; could be an interface name or a UUID */ + parent = nm_setting_ip_tunnel_get_parent (s_ip_tunnel); + if (parent) { + if (!match_parent (priv->parent, parent)) + return FALSE; + } - if (!address_equal_pp (priv->addr_family, - nm_setting_ip_tunnel_get_remote (s_ip_tunnel), - priv->remote)) - return FALSE; - - if (nm_setting_ip_tunnel_get_ttl (s_ip_tunnel) != priv->ttl) - return FALSE; - - if (nm_setting_ip_tunnel_get_tos (s_ip_tunnel) != priv->tos) - return FALSE; - - if (priv->addr_family == AF_INET) { - if (nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel) != priv->path_mtu_discovery) - return FALSE; - } else { - if (nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel) != priv->encap_limit) + if (!address_equal_pp (priv->addr_family, + nm_setting_ip_tunnel_get_local (s_ip_tunnel), + priv->local)) return FALSE; - if (nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel) != priv->flow_label) + if (!address_equal_pp (priv->addr_family, + nm_setting_ip_tunnel_get_remote (s_ip_tunnel), + priv->remote)) return FALSE; + + if (nm_setting_ip_tunnel_get_ttl (s_ip_tunnel) != priv->ttl) + return FALSE; + + if (nm_setting_ip_tunnel_get_tos (s_ip_tunnel) != priv->tos) + return FALSE; + + if (priv->addr_family == AF_INET) { + if (nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel) != priv->path_mtu_discovery) + return FALSE; + } else { + if (nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel) != priv->encap_limit) + return FALSE; + + if (nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel) != priv->flow_label) + return FALSE; + } } return TRUE; @@ -751,9 +753,9 @@ create_and_realize (NMDevice *device, } static void -setup (NMDevice *device, NMPlatformLink *plink) +setup_start (NMDevice *device, NMPlatformLink *plink) { - NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->setup (device, plink); + NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->setup_start (device, plink); update_properties (device); } @@ -847,7 +849,7 @@ nm_device_ip_tunnel_class_init (NMDeviceIPTunnelClass *klass) device_class->check_connection_compatible = check_connection_compatible; device_class->create_and_realize = create_and_realize; device_class->realize = realize; - device_class->setup = setup; + device_class->setup_start = setup_start; device_class->unrealize = unrealize; device_class->connection_type = NM_SETTING_IP_TUNNEL_SETTING_NAME; diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index 214b227030..46d4d391e8 100644 --- a/src/devices/nm-device-tun.c +++ b/src/devices/nm-device-tun.c @@ -226,6 +226,13 @@ realize (NMDevice *device, NMPlatformLink *plink, GError **error) return TRUE; } +static void +setup_start (NMDevice *device, NMPlatformLink *plink) +{ + NM_DEVICE_CLASS (nm_device_tun_parent_class)->setup_start (device, plink); + reload_tun_properties (device); +} + static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection) { @@ -235,8 +242,6 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) NMSettingTun *s_tun; gint64 user, group; - reload_tun_properties (self); - if (!NM_DEVICE_CLASS (nm_device_tun_parent_class)->check_connection_compatible (device, connection)) return FALSE; @@ -244,23 +249,25 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) if (!s_tun) return FALSE; - mode = tun_mode_from_string (priv->mode); - if (mode != nm_setting_tun_get_mode (s_tun)) - return FALSE; + if (nm_device_is_real (device)) { + mode = tun_mode_from_string (priv->mode); + if (mode != nm_setting_tun_get_mode (s_tun)) + return FALSE; - user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); - group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1); + user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); + group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1); - if (user != priv->props.owner) - return FALSE; - if (group != priv->props.group) - return FALSE; - if (nm_setting_tun_get_pi (s_tun) == priv->props.no_pi) - return FALSE; - if (nm_setting_tun_get_vnet_hdr (s_tun) != priv->props.vnet_hdr) - return FALSE; - if (nm_setting_tun_get_multi_queue (s_tun) != priv->props.multi_queue) - return FALSE; + if (user != priv->props.owner) + return FALSE; + if (group != priv->props.group) + return FALSE; + if (nm_setting_tun_get_pi (s_tun) == priv->props.no_pi) + return FALSE; + if (nm_setting_tun_get_vnet_hdr (s_tun) != priv->props.vnet_hdr) + return FALSE; + if (nm_setting_tun_get_multi_queue (s_tun) != priv->props.multi_queue) + return FALSE; + } return TRUE; } @@ -367,6 +374,7 @@ nm_device_tun_class_init (NMDeviceTunClass *klass) device_class->check_connection_compatible = check_connection_compatible; device_class->create_and_realize = create_and_realize; device_class->realize = realize; + device_class->setup_start = setup_start; device_class->unrealize = unrealize; device_class->update_connection = update_connection; diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index 0f7b0d9f80..58263c5d0c 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -148,12 +148,12 @@ nm_device_vlan_set_parent (NMDeviceVlan *self, NMDevice *parent) } static void -setup (NMDevice *device, NMPlatformLink *plink) +setup_start (NMDevice *device, NMPlatformLink *plink) { NMDeviceVlan *self = NM_DEVICE_VLAN (device); NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - NM_DEVICE_CLASS (nm_device_vlan_parent_class)->setup (device, plink); + NM_DEVICE_CLASS (nm_device_vlan_parent_class)->setup_start (device, plink); _LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s", priv->vlan_id, nm_device_get_iface (priv->parent)); @@ -311,6 +311,9 @@ notify_new_device_added (NMDevice *device, NMDevice *new_device) if (priv->parent) return; + if (!nm_device_is_real (device)) + return; + plnk = nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, nm_device_get_ifindex (device), &plink); if (!plnk) { _LOGW (LOGD_VLAN, "failed to get VLAN interface info while checking added component."); @@ -397,18 +400,21 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) if (!s_vlan) return FALSE; - if (nm_setting_vlan_get_id (s_vlan) != priv->vlan_id) - return FALSE; + /* Before the device is realized some properties will not be set */ + if (nm_device_is_real (device)) { + if (nm_setting_vlan_get_id (s_vlan) != priv->vlan_id) + return FALSE; - /* Check parent interface; could be an interface name or a UUID */ - parent = nm_setting_vlan_get_parent (s_vlan); - if (parent) { - if (!match_parent (NM_DEVICE_VLAN (device), parent)) - return FALSE; - } else { - /* Parent could be a MAC address in an NMSettingWired */ - if (!match_hwaddr (device, connection, TRUE)) - return FALSE; + /* Check parent interface; could be an interface name or a UUID */ + parent = nm_setting_vlan_get_parent (s_vlan); + if (parent) { + if (!match_parent (NM_DEVICE_VLAN (device), parent)) + return FALSE; + } else { + /* Parent could be a MAC address in an NMSettingWired */ + if (!match_hwaddr (device, connection, TRUE)) + return FALSE; + } } /* Ensure the interface name matches. If not specified we assume a match @@ -672,7 +678,7 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass) parent_class->create_and_realize = create_and_realize; parent_class->realize = realize; - parent_class->setup = setup; + parent_class->setup_start = setup_start; parent_class->unrealize = unrealize; parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->bring_up = bring_up; diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c index f52d81e0a7..65b3950dd4 100644 --- a/src/devices/nm-device-vxlan.c +++ b/src/devices/nm-device-vxlan.c @@ -133,11 +133,11 @@ link_changed (NMDevice *device, NMPlatformLink *info) } static void -setup (NMDevice *device, NMPlatformLink *plink) +setup_start (NMDevice *device, NMPlatformLink *plink) { g_assert (plink->type == NM_LINK_TYPE_VXLAN); - NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->setup (device, plink); + NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->setup_start (device, plink); update_properties (device); } @@ -247,7 +247,7 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass) object_class->get_property = get_property; device_class->link_changed = link_changed; - device_class->setup = setup; + device_class->setup_start = setup_start; device_class->unrealize = unrealize; /* properties */ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index f9607685fd..63df7b71aa 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -556,7 +556,7 @@ nm_device_get_iface (NMDevice *self) int nm_device_get_ifindex (NMDevice *self) { - g_return_val_if_fail (self != NULL, 0); + g_return_val_if_fail (NM_IS_DEVICE (self), 0); return NM_DEVICE_GET_PRIVATE (self)->ifindex; } @@ -1152,8 +1152,7 @@ nm_device_release_one_slave (NMDevice *self, NMDevice *slave, gboolean configure static gboolean can_unmanaged_external_down (NMDevice *self) { - return nm_device_is_software (self) - && !nm_device_get_is_nm_owned (self); + return nm_device_is_software (self) && !NM_DEVICE_GET_PRIVATE (self)->is_nm_owned; } /** @@ -1385,23 +1384,31 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier) } static void -device_set_master (NMDevice *self, int ifindex) +device_recheck_slave_status (NMDevice *self, NMPlatformLink *plink) { - NMDevice *master; NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - master = nm_manager_get_device_by_ifindex (nm_manager_get (), ifindex); - if (master && NM_DEVICE_GET_CLASS (master)->enslave_slave) { - g_clear_object (&priv->master); - priv->master = g_object_ref (master); - nm_device_master_add_slave (master, self, FALSE); - } else if (master) { - _LOGI (LOGD_DEVICE, "enslaved to non-master-type device %s; ignoring", - nm_device_get_iface (master)); - } else { - _LOGW (LOGD_DEVICE, "enslaved to unknown device %d %s", - ifindex, - nm_platform_link_get_name (NM_PLATFORM_GET, ifindex)); + g_return_if_fail (plink != NULL); + + if (priv->enslaved && plink->master != nm_device_get_ifindex (priv->master)) + nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + + if (plink->master && !priv->enslaved) { + NMDevice *master; + + master = nm_manager_get_device_by_ifindex (nm_manager_get (), plink->master); + if (master && NM_DEVICE_GET_CLASS (master)->enslave_slave) { + g_clear_object (&priv->master); + priv->master = g_object_ref (master); + nm_device_master_add_slave (master, self, FALSE); + } else if (master) { + _LOGI (LOGD_DEVICE, "enslaved to non-master-type device %s; ignoring", + nm_device_get_iface (master)); + } else { + _LOGW (LOGD_DEVICE, "enslaved to unknown device %d %s", + plink->master, + nm_platform_link_get_name (NM_PLATFORM_GET, plink->master)); + } } } @@ -1449,6 +1456,12 @@ device_link_changed (NMDevice *self) g_object_notify (G_OBJECT (self), NM_DEVICE_MTU); } + if (info.driver && g_strcmp0 (priv->driver, info.driver) != 0) { + g_free (priv->driver); + priv->driver = g_strdup (info.driver); + g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER); + } + if (info.name[0] && strcmp (priv->iface, info.name) != 0) { _LOGI (LOGD_DEVICE, "interface index %d renamed iface from '%s' to '%s'", priv->ifindex, priv->iface, info.name); @@ -1471,15 +1484,6 @@ device_link_changed (NMDevice *self) nm_device_emit_recheck_auto_activate (self); } - /* Update slave status for external changes */ - if (priv->enslaved && info.master != nm_device_get_ifindex (priv->master)) - nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); - if (info.master && !priv->enslaved) { - device_set_master (self, info.master); - if (priv->master) - nm_device_enslave_slave (priv->master, self, NULL); - } - if (priv->rdisc && nm_platform_link_get_ipv6_token (NM_PLATFORM_GET, priv->ifindex, &token_iid)) { _LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface); if (nm_rdisc_set_iid (priv->rdisc, token_iid)) @@ -1562,6 +1566,7 @@ device_link_changed (NMDevice *self) if (emit_link_initialized) g_signal_emit (self, signals[LINK_INITIALIZED], 0); + device_recheck_slave_status (self, &info); return G_SOURCE_REMOVE; } @@ -1635,7 +1640,8 @@ link_changed (NMDevice *self, NMPlatformLink *info) * @plink: an existing platform link or %NULL * @error: location to store error, or %NULL * - * Initializes and sets up the device using existing backing resources. + * Initializes and sets up the device using existing backing resources. Before + * the device is ready for use nm_device_setup_finish() must be called. * * Returns: %TRUE on success, %FALSE on error */ @@ -1648,7 +1654,7 @@ nm_device_realize (NMDevice *self, NMPlatformLink *plink, GError **error) return FALSE; } - NM_DEVICE_GET_CLASS (self)->setup (self, plink); + NM_DEVICE_GET_CLASS (self)->setup_start (self, plink); return TRUE; } @@ -1671,15 +1677,20 @@ nm_device_create_and_realize (NMDevice *self, NMDevice *parent, GError **error) { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMPlatformLink plink = { .type = NM_LINK_TYPE_UNKNOWN }; + /* Must be set before device is realized */ + priv->is_nm_owned = !nm_platform_link_get_by_ifname (NM_PLATFORM_GET, priv->iface); + /* Create any resources the device needs */ if (NM_DEVICE_GET_CLASS (self)->create_and_realize) { if (!NM_DEVICE_GET_CLASS (self)->create_and_realize (self, connection, parent, &plink, error)) return FALSE; } - NM_DEVICE_GET_CLASS (self)->setup (self, (plink.type != NM_LINK_TYPE_UNKNOWN) ? &plink : NULL); + NM_DEVICE_GET_CLASS (self)->setup_start (self, (plink.type != NM_LINK_TYPE_UNKNOWN) ? &plink : NULL); + nm_device_setup_finish (self, (plink.type != NM_LINK_TYPE_UNKNOWN) ? &plink : NULL); g_return_val_if_fail (nm_device_check_connection_compatible (self, connection), TRUE); return TRUE; @@ -1742,7 +1753,7 @@ check_carrier (NMDevice *self) } static void -setup (NMDevice *self, NMPlatformLink *plink) +setup_start (NMDevice *self, NMPlatformLink *plink) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); static guint32 id = 0; @@ -1751,6 +1762,7 @@ setup (NMDevice *self, NMPlatformLink *plink) g_return_if_fail (priv->ip_ifindex <= 0); g_return_if_fail (priv->ip_iface == NULL); + /* Balanced by a thaw in nm_device_setup_finish() */ g_object_freeze_notify (G_OBJECT (self)); if (plink) { @@ -1759,7 +1771,7 @@ setup (NMDevice *self, NMPlatformLink *plink) } if (priv->ifindex > 0) { - _LOGD (LOGD_DEVICE, "setup(): %s, kernel ifindex %d", G_OBJECT_TYPE_NAME (self), priv->ifindex); + _LOGD (LOGD_DEVICE, "setup_start(): %s, kernel ifindex %d", G_OBJECT_TYPE_NAME (self), priv->ifindex); priv->physical_port_id = nm_platform_link_get_physical_port_id (NM_PLATFORM_GET, priv->ifindex); g_object_notify (G_OBJECT (self), NM_DEVICE_PHYSICAL_PORT_ID); @@ -1844,17 +1856,29 @@ setup (NMDevice *self, NMPlatformLink *plink) g_object_notify (G_OBJECT (self), NM_DEVICE_CAPABILITIES); - /* Enslave ourselves */ - if (priv->ifindex > 0) { - int master = nm_platform_link_get_master (NM_PLATFORM_GET, priv->ifindex); - - if (master > 0) - device_set_master (self, master); - } - priv->real = TRUE; +} + +static void +setup_finish (NMDevice *self, NMPlatformLink *plink) +{ + if (plink) { + update_device_from_platform_link (self, plink); + device_recheck_slave_status (self, plink); + } +} + +void +nm_device_setup_finish (NMDevice *self, NMPlatformLink *plink) +{ + NM_DEVICE_GET_CLASS (self)->setup_finish (self, plink); + + NM_DEVICE_GET_PRIVATE (self)->real = TRUE; g_object_notify (G_OBJECT (self), NM_DEVICE_REAL); + nm_device_recheck_available_connections (self); + + /* Balanced by a freeze in setup_start() */ g_object_thaw_notify (G_OBJECT (self)); } @@ -2810,7 +2834,8 @@ nm_device_check_connection_compatible (NMDevice *self, NMConnection *connection) static gboolean nm_device_can_assume_connections (NMDevice *self) { - return !!NM_DEVICE_GET_CLASS (self)->update_connection; + return !!NM_DEVICE_GET_CLASS (self)->update_connection + && !NM_DEVICE_GET_PRIVATE (self)->is_nm_owned; } /** @@ -6547,14 +6572,6 @@ nm_device_get_is_nm_owned (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->is_nm_owned; } -void -nm_device_set_nm_owned (NMDevice *self) -{ - g_return_if_fail (NM_IS_DEVICE (self)); - - NM_DEVICE_GET_PRIVATE (self)->is_nm_owned = TRUE; -} - /* * delete_on_deactivate_link_delete * @@ -8461,6 +8478,7 @@ _nm_device_check_connection_available (NMDevice *self, && nm_device_get_unmanaged (self, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT)) return FALSE; if ( state < NM_DEVICE_STATE_DISCONNECTED + && !nm_device_is_software (self) && ( ( !NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER) && !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) || ( NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER) @@ -10324,7 +10342,8 @@ nm_device_class_init (NMDeviceClass *klass) klass->check_connection_compatible = check_connection_compatible; klass->check_connection_available = check_connection_available; klass->can_unmanaged_external_down = can_unmanaged_external_down; - klass->setup = setup; + klass->setup_start = setup_start; + klass->setup_finish = setup_finish; klass->unrealize = unrealize; klass->is_up = is_up; klass->bring_up = bring_up; diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index c185184a79..268ed06294 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -174,14 +174,28 @@ typedef struct { GError **error); /** - * setup(): + * setup_start(): * @self: the #NMDevice * @plink: the #NMPlatformLink if backed by a kernel netdevice * * Update the device from backing resource properties (like hardware - * addresses, carrier states, driver/firmware info, etc). + * addresses, carrier states, driver/firmware info, etc). This function + * should only change properties for this device, and should not perform + * any tasks that affect other interfaces (like master/slave or parent/child + * stuff). */ - void (*setup) (NMDevice *self, NMPlatformLink *plink); + void (*setup_start) (NMDevice *self, NMPlatformLink *plink); + + /** + * setup_finish(): + * @self: the #NMDevice + * @plink: the #NMPlatformLink if backed by a kernel netdevice + * + * Update the device's master/slave or parent/child relationships from + * backing resource properties. After this function finishes, the device + * is ready for network connectivity. + */ + void (*setup_finish) (NMDevice *self, NMPlatformLink *plink); /** * unrealize(): @@ -466,7 +480,6 @@ void nm_device_set_unmanaged_initial (NMDevice *device, gboolean unmanaged); gboolean nm_device_get_is_nm_owned (NMDevice *device); -void nm_device_set_nm_owned (NMDevice *device); gboolean nm_device_has_capability (NMDevice *self, NMDeviceCapabilities caps); @@ -477,6 +490,8 @@ gboolean nm_device_create_and_realize (NMDevice *self, NMConnection *connection, NMDevice *parent, GError **error); +void nm_device_setup_finish (NMDevice *self, + NMPlatformLink *plink); gboolean nm_device_unrealize (NMDevice *device, gboolean remove_resources, GError **error); diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 70bb6d628a..bb73e8c456 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -424,9 +424,9 @@ periodic_update_cb (gpointer user_data) } static void -setup (NMDevice *device, NMPlatformLink *plink) +setup_start (NMDevice *device, NMPlatformLink *plink) { - NM_DEVICE_CLASS (nm_device_wifi_parent_class)->setup (device, plink); + NM_DEVICE_CLASS (nm_device_wifi_parent_class)->setup_start (device, plink); g_object_notify (G_OBJECT (device), NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS); } @@ -3040,7 +3040,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) object_class->dispose = dispose; object_class->finalize = finalize; - parent_class->setup = setup; + parent_class->setup_start = setup_start; parent_class->bring_up = bring_up; parent_class->can_auto_connect = can_auto_connect; parent_class->is_available = is_available; diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index aa892cc711..609e645e0a 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -598,17 +598,17 @@ master_state_cb (NMActiveConnection *master, gpointer user_data) { NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data); - NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); NMActiveConnectionState master_state = nm_active_connection_get_state (master); + NMDevice *master_device = nm_active_connection_get_device (master); check_master_ready (self); _LOGD ("master ActiveConnection [%p] state now '%s' (%d)", master, state_to_string (master_state), master_state); - if ( master_state >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING - && !priv->master_ready) { - /* Master failed without ever creating its device */ + if ( master_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATING + && (!master_device || !nm_device_is_real (master_device))) { + /* Master failed without ever creating or realizing its device */ if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed) NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed (self); } diff --git a/src/nm-manager.c b/src/nm-manager.c index 5c6bdb2a14..eb0ec6fffc 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -58,7 +58,7 @@ #include "nmdbus-manager.h" #include "nmdbus-device.h" -static void add_device (NMManager *self, NMDevice *device, gboolean try_assume); +static void add_device (NMManager *self, NMDevice *device); static NMActiveConnection *_new_active_connection (NMManager *self, NMConnection *connection, @@ -487,8 +487,11 @@ find_device_by_ip_iface (NMManager *self, const gchar *iface) g_return_val_if_fail (iface != NULL, NULL); for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = g_slist_next (iter)) { - if (g_strcmp0 (nm_device_get_ip_iface (NM_DEVICE (iter->data)), iface) == 0) - return NM_DEVICE (iter->data); + NMDevice *candidate = iter->data; + + if ( nm_device_is_real (candidate) + && g_strcmp0 (nm_device_get_ip_iface (candidate), iface) == 0) + return candidate; } return NULL; } @@ -840,6 +843,8 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection) NMDevice *parent, *first_compatible = NULL; GSList *iter; + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + factory = nm_device_factory_manager_find_factory_for_connection (connection); if (!factory) return NULL; @@ -849,7 +854,7 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection) return NULL; /* Try as an interface name */ - parent = find_device_by_ip_iface (self, parent_name); + parent = find_device_by_iface (self, parent_name); if (parent) return parent; @@ -964,10 +969,9 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMDeviceFactory *factory; - GSList *iter; - char *iface = NULL; + GSList *connections, *iter; + gs_free char *iface = NULL; NMDevice *device = NULL, *parent = NULL; - gboolean nm_owned = FALSE; g_return_val_if_fail (NM_IS_MANAGER (self), NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); @@ -989,7 +993,7 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "interface name '%s' already created", iface); - goto out; + return NULL; } } @@ -1003,79 +1007,61 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError NM_MANAGER_ERROR_FAILED, "NetworkManager plugin for '%s' unavailable", nm_connection_get_connection_type (connection)); - goto out; + return NULL; } - nm_owned = !nm_platform_link_get_by_ifname (NM_PLATFORM_GET, iface); - device = nm_device_factory_create_device (factory, iface, NULL, connection, NULL, error); - if (device) { + if (!device) + return NULL; + + add_device (self, device); + + /* Add device takes a reference that NMManager still owns, so it's + * safe to unref here and still return @device. + */ + g_object_unref (device); + + /* Create backing resources if the device has any autoconnect connections */ + connections = nm_settings_get_connections (priv->settings); + for (iter = connections; iter; iter = g_slist_next (iter)) { + NMConnection *candidate = iter->data; + NMSettingConnection *s_con; + + if (!nm_device_check_connection_compatible (device, candidate)) + continue; + + s_con = nm_connection_get_setting_connection (candidate); + g_assert (s_con); + if (!nm_setting_connection_get_autoconnect (s_con)) + continue; + + /* Create any backing resources the device needs */ if (!nm_device_create_and_realize (device, connection, parent, error)) { - g_clear_object (&device); - goto out; + remove_device (self, device, FALSE, TRUE); + device = NULL; } - - if (nm_owned) - nm_device_set_nm_owned (device); - - /* If it was created by NM there's no connection to assume, but if it - * previously existed there might be one. - */ - add_device (self, device, !nm_owned); - - /* Add device takes a reference that NMManager still owns, so it's - * safe to unref here and still return @device. - */ - g_object_unref (device); + break; } -out: - g_free (iface); return device; } -static void -system_create_virtual_devices (NMManager *self) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GSList *iter, *connections; - - nm_log_dbg (LOGD_CORE, "creating virtual devices..."); - - connections = nm_settings_get_connections (priv->settings); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMConnection *connection = iter->data; - - /* We only create a virtual interface if the connection can autoconnect */ - if ( nm_connection_is_virtual (connection) - && nm_settings_connection_can_autoconnect (NM_SETTINGS_CONNECTION (connection))) - system_create_virtual_device (self, connection, NULL); - } - g_slist_free (connections); -} - static void connection_added (NMSettings *settings, - NMSettingsConnection *settings_connection, + NMConnection *connection, NMManager *manager) { - NMConnection *connection = NM_CONNECTION (settings_connection); - - if (nm_connection_is_virtual (connection)) { - NMSettingConnection *s_con = nm_connection_get_setting_connection (connection); - - g_assert (s_con); - if (nm_setting_connection_get_autoconnect (s_con)) - system_create_virtual_device (manager, connection, NULL); - } + if (nm_connection_is_virtual (connection)) + system_create_virtual_device (manager, connection, NULL); } static void connection_changed (NMSettings *settings, - NMSettingsConnection *connection, + NMConnection *connection, NMManager *manager) { - /* FIXME: Some virtual devices may need to be updated in the future. */ + if (nm_connection_is_virtual (connection)) + system_create_virtual_device (manager, connection, NULL); } static void @@ -1590,17 +1576,25 @@ assume_connection (NMManager *self, NMDevice *device, NMSettingsConnection *conn return TRUE; } +static gboolean +can_start_device (NMManager *self, NMDevice *device) +{ + return nm_device_is_real (device) + && !manager_sleeping (self) + && !nm_device_get_unmanaged (device, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT); +} + static gboolean recheck_assume_connection (NMDevice *device, gpointer user_data) { NMManager *self = NM_MANAGER (user_data); NMSettingsConnection *connection; - gboolean was_unmanaged = FALSE, success, generated; + gboolean was_unmanaged = FALSE, success, generated = FALSE; NMDeviceState state; - if (manager_sleeping (self)) - return FALSE; - if (nm_device_get_unmanaged (device, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT)) + g_return_val_if_fail (!nm_device_get_is_nm_owned (device), FALSE); + + if (!can_start_device (self, device)) return FALSE; state = nm_device_get_state (device); @@ -1671,26 +1665,51 @@ device_ip_iface_changed (NMDevice *device, } } +static void +device_realized (NMDevice *device, + GParamSpec *pspec, + NMManager *self) +{ + int ifindex; + gboolean assumed = FALSE; + + /* Loopback device never gets managed */ + ifindex = nm_device_get_ifindex (device); + if (ifindex > 0 && nm_platform_link_get_type (NM_PLATFORM_GET, ifindex) == NM_LINK_TYPE_LOOPBACK) + return; + + if (!can_start_device (self, device)) + return; + + if (!nm_device_get_is_nm_owned (device)) { + assumed = recheck_assume_connection (device, self); + g_signal_connect (device, NM_DEVICE_RECHECK_ASSUME, + G_CALLBACK (recheck_assume_connection), self); + } + + if (!assumed && nm_device_get_managed (device)) { + nm_device_state_changed (device, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_REASON_NOW_MANAGED); + } +} + /** * add_device: * @self: the #NMManager * @device: the #NMDevice to add - * @try_assume: %TRUE if existing connection (if any) should be assumed * * If successful, this function will increase the references count of @device. * Callers should decrease the reference count. */ static void -add_device (NMManager *self, NMDevice *device, gboolean try_assume) +add_device (NMManager *self, NMDevice *device) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - const char *iface, *driver, *type_desc; + const char *iface, *type_desc; const GSList *unmanaged_specs; - gboolean user_unmanaged, sleeping; - gboolean enabled = FALSE; RfKillType rtype; GSList *iter, *remove = NULL; - gboolean connection_assumed = FALSE; int ifindex; const char *dbus_path; @@ -1738,6 +1757,9 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume) g_signal_connect (device, "notify::" NM_DEVICE_IP_IFACE, G_CALLBACK (device_ip_iface_changed), self); + g_signal_connect (device, "notify::" NM_DEVICE_REAL, + G_CALLBACK (device_realized), + self); if (priv->startup) { g_signal_connect (device, "notify::" NM_DEVICE_HAS_PENDING_ACTION, @@ -1752,52 +1774,29 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume) rtype = nm_device_get_rfkill_type (device); if (rtype != RFKILL_TYPE_UNKNOWN) { nm_manager_rfkill_update (self, rtype); - enabled = radio_enabled_for_type (self, rtype, TRUE); - nm_device_set_enabled (device, enabled); + nm_device_set_enabled (device, radio_enabled_for_type (self, rtype, TRUE)); } iface = nm_device_get_iface (device); g_assert (iface); - type_desc = nm_device_get_type_desc (device); g_assert (type_desc); - driver = nm_device_get_driver (device); - if (!driver) - driver = "unknown"; - nm_log_info (LOGD_HW, "(%s): new %s device (carrier: %s, driver: '%s', ifindex: %d)", - iface, type_desc, - nm_device_has_capability (device, NM_DEVICE_CAP_CARRIER_DETECT) - ? (nm_device_has_carrier (device) ? "ON" : "OFF") - : "UNKNOWN", - driver, nm_device_get_ifindex (device)); + + nm_log_info (LOGD_HW, "(%s): new %s device", iface, type_desc); unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings); - user_unmanaged = nm_device_spec_match_list (device, unmanaged_specs); - nm_device_set_unmanaged_initial (device, NM_UNMANAGED_USER, user_unmanaged); - - sleeping = manager_sleeping (self); - nm_device_set_unmanaged_initial (device, NM_UNMANAGED_INTERNAL, sleeping); + nm_device_set_unmanaged_initial (device, + NM_UNMANAGED_USER, + nm_device_spec_match_list (device, unmanaged_specs)); + nm_device_set_unmanaged_initial (device, + NM_UNMANAGED_INTERNAL, + manager_sleeping (self)); dbus_path = nm_exported_object_export (NM_EXPORTED_OBJECT (device)); nm_log_dbg (LOGD_DEVICE, "(%s): exported as %s", nm_device_get_iface (device), dbus_path); nm_device_finish_init (device); - if (try_assume) { - connection_assumed = recheck_assume_connection (device, self); - g_signal_connect (device, NM_DEVICE_RECHECK_ASSUME, - G_CALLBACK (recheck_assume_connection), self); - } - - if (!connection_assumed && nm_device_get_managed (device)) { - nm_device_state_changed (device, - NM_DEVICE_STATE_UNAVAILABLE, - NM_DEVICE_STATE_REASON_NOW_MANAGED); - } - - /* Try to generate a default connection. If this fails because the link is - * not initialized, we will retry again in device_link_initialized_cb(). - */ nm_settings_device_added (priv->settings, device); g_signal_emit (self, signals[DEVICE_ADDED], 0, device); g_object_notify (G_OBJECT (self), NM_MANAGER_DEVICES); @@ -1808,11 +1807,6 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume) if (d != device) nm_device_notify_new_device_added (d, device); } - - /* New devices might be master interfaces for virtual interfaces; so we may - * need to create new virtual interfaces now. - */ - system_create_virtual_devices (self); } /*******************************************************************/ @@ -1824,9 +1818,10 @@ factory_device_added_cb (NMDeviceFactory *factory, { GError *error = NULL; - if (nm_device_realize (device, NULL, &error)) - add_device (NM_MANAGER (user_data), device, TRUE); - else { + if (nm_device_realize (device, NULL, &error)) { + add_device (NM_MANAGER (user_data), device); + nm_device_setup_finish (device, NULL); + } else { nm_log_warn (LOGD_DEVICE, "(%s): failed to realize device: %s", nm_device_get_iface (device), error->message); g_error_free (error); @@ -1881,6 +1876,26 @@ platform_link_added (NMManager *self, if (nm_manager_get_device_by_ifindex (self, ifindex)) return; + device = find_device_by_iface (self, plink->name); + if (device) { + if (!nm_device_is_real (device)) { + if (nm_device_realize (device, plink, &error)) + nm_device_setup_finish (device, plink); + else { + nm_log_warn (LOGD_DEVICE, "(%s): %s", plink->name, error->message); + g_clear_error (&error); + remove_device (self, device, FALSE, FALSE); + } + return; + } else if (!nm_device_realize (device, plink, &error)) { + nm_log_warn (LOGD_HW, "%s: factory failed to create device: %s", + plink->name, error->message); + g_clear_error (&error); + return; + } + return; + } + /* Try registered device factories */ factory = nm_device_factory_manager_find_factory_for_link_type (plink->type); if (factory) { @@ -1917,10 +1932,11 @@ platform_link_added (NMManager *self, if (device) { if (nm_plugin_missing) nm_device_set_nm_plugin_missing (device, TRUE); - if (nm_device_realize (device, plink, &error)) - add_device (self, device, plink->type != NM_LINK_TYPE_LOOPBACK); - else { - nm_log_warn (LOGD_HW, "%s: failed to realize device: %s", + if (nm_device_realize (device, plink, &error)) { + add_device (self, device); + nm_device_setup_finish (device, plink); + } else { + nm_log_warn (LOGD_DEVICE, "%s: failed to realize device: %s", plink->name, error->message); g_clear_error (&error); } @@ -1954,17 +1970,21 @@ _platform_link_cb_idle (PlatformLinkCbData *data) device = nm_manager_get_device_by_ifindex (self, data->ifindex); if (device) { if (nm_device_is_software (device)) { + /* Software devices stick around until their connection is removed */ if (!nm_device_unrealize (device, FALSE, &error)) { nm_log_warn (LOGD_DEVICE, "(%s): failed to unrealize: %s", - nm_device_get_iface (device), - error->message); + nm_device_get_iface (device), + error->message); g_clear_error (&error); + remove_device (self, device, FALSE, TRUE); } + } else { + /* Hardware devices always get removed when their kernel link is gone */ + remove_device (self, device, FALSE, TRUE); } - remove_device (self, device, FALSE, TRUE); } + g_object_remove_weak_pointer (G_OBJECT (self), (gpointer *) &data->self); } - g_object_remove_weak_pointer (G_OBJECT (self), (gpointer *) &data->self); } g_slice_free (PlatformLinkCbData, data); return G_SOURCE_REMOVE; @@ -2079,7 +2099,8 @@ impl_manager_get_devices (NMManager *self, const char *path; path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (iter->data)); - if (path) + if ( path + && nm_device_is_real (iter->data)) paths[i++] = path; } paths[i++] = NULL; @@ -2181,7 +2202,7 @@ find_master (NMManager *self, const char *master; NMDevice *master_device = NULL; NMSettingsConnection *master_connection = NULL; - GSList *iter, *connections = NULL; + GSList *iter; s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); @@ -2191,7 +2212,7 @@ find_master (NMManager *self, return TRUE; /* success, but no master */ /* Try as an interface name first */ - master_device = find_device_by_ip_iface (self, master); + master_device = find_device_by_iface (self, master); if (master_device) { if (master_device == device) { g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, @@ -2223,23 +2244,6 @@ find_master (NMManager *self, break; } } - } else { - /* Might be a virtual interface that hasn't been created yet, so - * look through the interface names of connections that require - * virtual interfaces and see if one of their virtual interface - * names matches the master. - */ - connections = nm_manager_get_activatable_connections (self); - for (iter = connections; iter && !master_connection; iter = g_slist_next (iter)) { - NMSettingsConnection *candidate = iter->data; - char *vname; - - vname = get_virtual_iface_name (self, NM_CONNECTION (candidate), NULL, NULL); - if (g_strcmp0 (master, vname) == 0 && is_compatible_with_slave (NM_CONNECTION (candidate), connection)) - master_connection = candidate; - g_free (vname); - } - g_slist_free (connections); } } @@ -2333,7 +2337,7 @@ ensure_master_active_connection (NMManager *self, /* If the device is disconnected, find a compatible connection and * activate it on the device. */ - if (master_state == NM_DEVICE_STATE_DISCONNECTED) { + if (master_state == NM_DEVICE_STATE_DISCONNECTED || !nm_device_is_real (master_device)) { GSList *connections; g_assert (master_connection == NULL); @@ -2394,9 +2398,11 @@ ensure_master_active_connection (NMManager *self, continue; found_device = TRUE; - master_state = nm_device_get_state (candidate); - if (master_state != NM_DEVICE_STATE_DISCONNECTED) - continue; + if (!nm_device_is_software (candidate)) { + master_state = nm_device_get_state (candidate); + if (nm_device_is_real (candidate) && master_state != NM_DEVICE_STATE_DISCONNECTED) + continue; + } master_ac = nm_manager_activate_connection (self, master_connection, @@ -2683,6 +2689,17 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * return FALSE; } + /* Create any backing resources the device needs */ + if (!nm_device_is_real (device)) { + NMDevice *parent; + + parent = find_parent_device_for_connection (self, (NMConnection *) connection); + if (!nm_device_create_and_realize (device, (NMConnection *) connection, parent, error)) { + g_prefix_error (error, "%s failed to create resources: ", nm_device_get_iface (device)); + return FALSE; + } + } + /* Try to find the master connection/device if the connection has a dependency */ if (!find_master (self, applied, device, &master_connection, &master_device, &master_ac, @@ -3086,7 +3103,7 @@ validate_activation_request (NMManager *self, if (!iface) goto error; - device = find_device_by_ip_iface (self, iface); + device = find_device_by_iface (self, iface); g_free (iface); } } @@ -4209,6 +4226,7 @@ gboolean nm_manager_start (NMManager *self, GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + GSList *iter, *connections; guint i; if (!nm_settings_start (priv->settings, error)) @@ -4256,11 +4274,14 @@ nm_manager_start (NMManager *self, GError **error) /* Load VPN plugins */ priv->vpn_manager = g_object_ref (nm_vpn_manager_get ()); - /* - * Connections added before the manager is started do not emit + /* Connections added before the manager is started do not emit * connection-added signals thus devices have to be created manually. */ - system_create_virtual_devices (self); + nm_log_dbg (LOGD_CORE, "creating virtual devices..."); + connections = nm_settings_get_connections (priv->settings); + for (iter = connections; iter; iter = iter->next) + connection_added (priv->settings, NM_CONNECTION (iter->data), self); + g_slist_free (connections); priv->devices_inited = TRUE; @@ -5067,6 +5088,12 @@ nm_manager_init (NMManager *manager) priv->metered = NM_METERED_UNKNOWN; } +static gboolean +device_is_real (GObject *device, gpointer user_data) +{ + return nm_device_is_real (NM_DEVICE (device)); +} + static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) @@ -5139,7 +5166,7 @@ get_property (GObject *object, guint prop_id, g_value_set_boolean (value, priv->sleeping); break; case PROP_DEVICES: - nm_utils_g_value_set_object_path_array (value, priv->devices, NULL, NULL); + nm_utils_g_value_set_object_path_array (value, priv->devices, device_is_real, NULL); break; case PROP_METERED: g_value_set_uint (value, priv->metered);