From 7f771d0a05fd691b2965bc8ae91a6aa9a6453a53 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 10 Apr 2014 18:02:52 -0500 Subject: [PATCH 1/6] core: use IP interface hardware address for IP-level operations The IP interface may have its own hardware address (like the net port for WWAN devices) and that's the hardware address that must be used for DHCP and IPv6 SLAAC, not the hardware address (if any) of the NMDevice itself. This patch does change the NMDevice hardware address property to always be the Device's hardware address, instead of the IP interface hardware address. This means that ADSL and WWAN will no longer change their hardware address to the hardware address of their IP interface. But in all these cases, the hardware address is non-existent (PPP) or transient and meaningless (WWAN/ADSL). --- src/devices/adsl/nm-device-adsl.c | 10 +--------- src/devices/nm-device-private.h | 1 - src/devices/nm-device.c | 33 ++++++++++++++++++++----------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c index 0c35bb7ada..627594c378 100644 --- a/src/devices/adsl/nm-device-adsl.c +++ b/src/devices/adsl/nm-device-adsl.c @@ -142,9 +142,6 @@ set_nas_iface (NMDeviceAdsl *self, int idx, const char *name) g_warn_if_fail (priv->nas_ifname == NULL); priv->nas_ifname = g_strdup (name); - - /* Update NAS interface's MAC address */ - nm_device_update_hw_address (NM_DEVICE (self)); } static gboolean @@ -482,9 +479,6 @@ deactivate (NMDevice *device) priv->nas_ifindex = -1; g_free (priv->nas_ifname); priv->nas_ifname = NULL; - - /* Poke NMDevice to notice that our hw_address is no longer valid */ - nm_device_update_hw_address (NM_DEVICE (self)); } /**************************************************************/ @@ -492,9 +486,7 @@ deactivate (NMDevice *device) static guint get_hw_address_length (NMDevice *device, gboolean *out_permanent) { - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (device); - - return priv->nas_ifname ? ETH_ALEN : 0; + return 0; } static gboolean diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index 24bb0b3362..c1f1c799bf 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -52,7 +52,6 @@ gboolean nm_device_bring_up (NMDevice *self, gboolean wait, gboolean *no_firmwar void nm_device_take_down (NMDevice *self, gboolean block); -gboolean nm_device_update_hw_address (NMDevice *self); gboolean nm_device_set_hw_addr (NMDevice *device, const guint8 *addr, const char *detail, guint64 hw_log_domain); diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index b3de5580f5..0558fd47ba 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -324,6 +324,8 @@ static void _set_state_full (NMDevice *device, NMDeviceStateReason reason, gboolean quitting); +static gboolean nm_device_update_hw_address (NMDevice *dev); + /***********************************************************/ static GQuark @@ -2751,6 +2753,8 @@ dhcp4_start (NMDevice *self, { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMSettingIP4Config *s_ip4; + const guint8 *hw_addr; + size_t hw_addr_len = 0; GByteArray *tmp = NULL; s_ip4 = nm_connection_get_setting_ip4_config (connection); @@ -2760,9 +2764,10 @@ dhcp4_start (NMDevice *self, g_object_unref (priv->dhcp4_config); priv->dhcp4_config = nm_dhcp4_config_new (); - if (priv->hw_addr_len) { - tmp = g_byte_array_sized_new (priv->hw_addr_len); - g_byte_array_append (tmp, priv->hw_addr, priv->hw_addr_len); + hw_addr = nm_platform_link_get_address (nm_device_get_ip_ifindex (self), &hw_addr_len); + if (hw_addr_len) { + tmp = g_byte_array_sized_new (hw_addr_len); + g_byte_array_append (tmp, hw_addr, hw_addr_len); } /* Begin DHCP on the interface */ @@ -3205,6 +3210,8 @@ dhcp6_start (NMDevice *self, NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; GByteArray *tmp = NULL; + const guint8 *hw_addr; + size_t hw_addr_len = 0; if (!connection) { connection = nm_device_get_connection (self); @@ -3225,9 +3232,10 @@ dhcp6_start (NMDevice *self, priv->dhcp6_ip6_config = NULL; } - if (priv->hw_addr_len) { - tmp = g_byte_array_sized_new (priv->hw_addr_len); - g_byte_array_append (tmp, priv->hw_addr, priv->hw_addr_len); + hw_addr = nm_platform_link_get_address (nm_device_get_ip_ifindex (self), &hw_addr_len); + if (hw_addr_len) { + tmp = g_byte_array_sized_new (hw_addr_len); + g_byte_array_append (tmp, hw_addr, hw_addr_len); } priv->dhcp6_client = nm_dhcp_manager_start_ip6 (nm_dhcp_manager_get (), @@ -3639,12 +3647,15 @@ static void addrconf6_start_with_link_ready (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + const guint8 *hw_addr; + size_t hw_addr_len = 0; g_assert (priv->rdisc); /* FIXME: what if interface has no lladdr, like PPP? */ - if (priv->hw_addr_len) - nm_rdisc_set_lladdr (priv->rdisc, (const char *) priv->hw_addr, priv->hw_addr_len); + hw_addr = nm_platform_link_get_address (nm_device_get_ip_ifindex (self), &hw_addr_len); + if (hw_addr_len) + nm_rdisc_set_lladdr (priv->rdisc, (const char *) hw_addr, hw_addr_len); nm_device_ipv6_sysctl_set (self, "accept_ra", "1"); nm_device_ipv6_sysctl_set (self, "accept_ra_defrtr", "0"); @@ -6946,7 +6957,7 @@ nm_device_get_hw_address (NMDevice *dev, guint *out_len) return priv->hw_addr; } -gboolean +static gboolean nm_device_update_hw_address (NMDevice *dev) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev); @@ -6959,7 +6970,7 @@ nm_device_update_hw_address (NMDevice *dev) return FALSE; if (priv->hw_addr_len) { - int ifindex = nm_device_get_ip_ifindex (dev); + int ifindex = nm_device_get_ifindex (dev); gsize addrlen; const guint8 *binaddr; @@ -7112,7 +7123,7 @@ get_hw_address_length (NMDevice *dev, gboolean *out_permanent) { size_t len; - if (nm_platform_link_get_address (nm_device_get_ip_ifindex (dev), &len)) + if (nm_platform_link_get_address (nm_device_get_ifindex (dev), &len)) return len; else return 0; From ac4fafe7a42a522c8b82b5d09802ab40ba504b7d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 13 Jun 2014 15:47:29 +0200 Subject: [PATCH 2/6] platform: assert against the maximum length of link_get_address() Signed-off-by: Thomas Haller --- libnm-util/nm-utils.h | 5 ++--- src/devices/nm-device.c | 7 +++++-- src/platform/nm-linux-platform.c | 18 ++++++++++++++---- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/libnm-util/nm-utils.h b/libnm-util/nm-utils.h index 23944ad1aa..896b3e92a8 100644 --- a/libnm-util/nm-utils.h +++ b/libnm-util/nm-utils.h @@ -129,9 +129,8 @@ gboolean nm_utils_wifi_is_channel_valid (guint32 channel, const char *band); /** * NM_UTILS_HWADDR_LEN_MAX: * - * The maximum length of a hardware address of a type known by - * nm_utils_hwaddr_len() or nm_utils_hwaddr_aton(). This can be used - * as the size of the buffer passed to nm_utils_hwaddr_aton(). + * The maximum length of hardware addresses handled by NetworkManager itself, + * nm_utils_hwaddr_len(), and nm_utils_hwaddr_aton(). */ #define NM_UTILS_HWADDR_LEN_MAX 20 /* INFINIBAND_ALEN */ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 0558fd47ba..b048571e5a 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -7376,7 +7376,8 @@ set_property (GObject *object, guint prop_id, NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (object); NMPlatformLink *platform_device; const char *hw_addr; - + guint hw_addr_len; + switch (prop_id) { case PROP_PLATFORM_DEVICE: platform_device = g_value_get_pointer (value); @@ -7454,7 +7455,9 @@ set_property (GObject *object, guint prop_id, priv->is_master = g_value_get_boolean (value); break; case PROP_HW_ADDRESS: - priv->hw_addr_len = nm_device_get_hw_address_length (NM_DEVICE (object), NULL); + hw_addr_len = nm_device_get_hw_address_length (NM_DEVICE (object), NULL); + g_return_if_fail (hw_addr_len <= NM_UTILS_HWADDR_LEN_MAX); + priv->hw_addr_len = hw_addr_len; hw_addr = g_value_get_string (value); if (!hw_addr) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 6c8d3fd77d..a920980596 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -2527,13 +2527,23 @@ link_get_address (NMPlatform *platform, int ifindex, size_t *length) { auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex); struct nl_addr *nladdr; + size_t l = 0; + gconstpointer a = NULL; - nladdr = rtnllink ? rtnl_link_get_addr (rtnllink) : NULL; + if (rtnllink && + (nladdr = rtnl_link_get_addr (rtnllink))) { + l = nl_addr_get_len (nladdr); + if (l > NM_UTILS_HWADDR_LEN_MAX) { + if (length) + *length = 0; + g_return_val_if_reached (NULL); + } else if (l > 0) + a = nl_addr_get_binary_addr (nladdr); + } if (length) - *length = nladdr ? nl_addr_get_len (nladdr) : 0; - - return nladdr ? nl_addr_get_binary_addr (nladdr) : NULL; + *length = l; + return a; } static gboolean From 27f91d054c19ad357fbbd11f59f473a638890df4 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 14 Jul 2014 17:59:45 -0500 Subject: [PATCH 3/6] core: simplify hardware address reading We no longer need a class method for reading the hardware address length, for a couple reasons: 1) Using the IP interface hardware address for IP operations now makes NMDevice's priv->hw_addr_len constant. So there's no reason to re-read it all the time. 2) get_hw_address_length() is now only used for determining whether the hardware address is permanent, and that only mattered for Bluetooth. Since Bluetooth interfaces have a bogus interface name, they will never have a valid ifindex, and thus nm_platform_link_get_address() would be useless. So instead of using the 'permanent' stuff, just don't bother updating the hardware address if the NMDevice's ifindex isn't valid, and let subclasses pass the initial hardware address at device creation. This also works correctly for NMDevice classes that previously implemented get_hw_address_length() like ADSL and WWAN, since those too will never have a valid ifindex or a valid hardware address. 3) Reading the device's hardware address length just ended up calling nm_platform_link_get_address() for most devices anyway, so nm_device_update_hw_address() would effectively read the link address twice (once to read the length, the second time to read the actual address). Let's just read the address once. --- src/config/tests/nm-test-device.c | 15 ---- src/devices/adsl/nm-device-adsl.c | 7 -- src/devices/bluetooth/nm-device-bt.c | 10 --- src/devices/nm-device.c | 109 +++++++++------------------ src/devices/nm-device.h | 15 ++-- src/devices/wwan/nm-device-modem.c | 7 -- 6 files changed, 43 insertions(+), 120 deletions(-) diff --git a/src/config/tests/nm-test-device.c b/src/config/tests/nm-test-device.c index fcfc63a7db..aeac6137c4 100644 --- a/src/config/tests/nm-test-device.c +++ b/src/config/tests/nm-test-device.c @@ -52,10 +52,6 @@ constructor (GType type, static void constructed (GObject *object) { - NMDevice *device = NM_DEVICE (object); - - nm_device_update_hw_address (device); - g_object_class->constructed (object); } @@ -71,19 +67,10 @@ finalize (GObject *object) g_object_class->finalize (object); } -static guint -get_hw_address_length (NMDevice *dev, gboolean *out_permanent) -{ - if (out_permanent) - *out_permanent = TRUE; - return ETH_ALEN; -} - static void nm_test_device_class_init (NMTestDeviceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); g_object_class = g_type_class_peek (G_TYPE_OBJECT); @@ -91,8 +78,6 @@ nm_test_device_class_init (NMTestDeviceClass *klass) object_class->constructed = constructed; object_class->dispose = dispose; object_class->finalize = finalize; - - device_class->get_hw_address_length = get_hw_address_length; } NMDevice * diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c index 627594c378..c4a98fa3ab 100644 --- a/src/devices/adsl/nm-device-adsl.c +++ b/src/devices/adsl/nm-device-adsl.c @@ -483,12 +483,6 @@ deactivate (NMDevice *device) /**************************************************************/ -static guint -get_hw_address_length (NMDevice *device, gboolean *out_permanent) -{ - return 0; -} - static gboolean carrier_update_cb (gpointer user_data) { @@ -621,7 +615,6 @@ nm_device_adsl_class_init (NMDeviceAdslClass *klass) parent_class->check_connection_compatible = check_connection_compatible; parent_class->complete_connection = complete_connection; - parent_class->get_hw_address_length = get_hw_address_length; parent_class->act_stage2_config = act_stage2_config; parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; parent_class->deactivate = deactivate; diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c index e9c14e837d..9d59344933 100644 --- a/src/devices/bluetooth/nm-device-bt.c +++ b/src/devices/bluetooth/nm-device-bt.c @@ -111,15 +111,6 @@ guint32 nm_device_bt_get_capabilities (NMDeviceBt *self) return NM_DEVICE_BT_GET_PRIVATE (self)->capabilities; } -static guint -get_hw_address_length (NMDevice *device, gboolean *out_permanent) -{ - /* HW address is the Bluetooth HW address of the remote device */ - if (out_permanent) - *out_permanent = TRUE; /* the bdaddr of the remote device will never change */ - return ETH_ALEN; -} - static guint32 get_connection_bt_type (NMConnection *connection) { @@ -1207,7 +1198,6 @@ nm_device_bt_class_init (NMDeviceBtClass *klass) object_class->dispose = dispose; object_class->finalize = finalize; - device_class->get_hw_address_length = get_hw_address_length; device_class->can_auto_connect = can_auto_connect; device_class->deactivate = deactivate; device_class->act_stage2_config = act_stage2_config; diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index b048571e5a..f638f09b95 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -324,7 +324,7 @@ static void _set_state_full (NMDevice *device, NMDeviceStateReason reason, gboolean quitting); -static gboolean nm_device_update_hw_address (NMDevice *dev); +static void nm_device_update_hw_address (NMDevice *dev); /***********************************************************/ @@ -6934,12 +6934,6 @@ nm_device_get_state (NMDevice *device) /***********************************************************/ /* NMConfigDevice interface related stuff */ -static guint -nm_device_get_hw_address_length (NMDevice *dev, gboolean *out_permanent) -{ - return NM_DEVICE_GET_CLASS (dev)->get_hw_address_length (dev, out_permanent); -} - const guint8 * nm_device_get_hw_address (NMDevice *dev, guint *out_len) { @@ -6951,68 +6945,46 @@ nm_device_get_hw_address (NMDevice *dev, guint *out_len) if (out_len) *out_len = priv->hw_addr_len; - if (priv->hw_addr_len == 0) - return NULL; - else - return priv->hw_addr; + return priv->hw_addr_len ? priv->hw_addr : NULL; } -static gboolean +static void nm_device_update_hw_address (NMDevice *dev) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev); - gboolean changed = FALSE, permanent = FALSE; + int ifindex = nm_device_get_ifindex (dev); + const char *iface = nm_device_get_iface (dev); + const guint8 *hwaddr; + gsize hwaddrlen = 0; - priv->hw_addr_len = nm_device_get_hw_address_length (dev, &permanent); + if (ifindex <= 0) + return; - /* If the address can't be changed, don't bother trying */ - if (permanent) - return FALSE; + hwaddr = nm_platform_link_get_address (ifindex, &hwaddrlen); + g_assert (hwaddrlen <= sizeof (priv->hw_addr)); + if (hwaddrlen) { + if (hwaddrlen != priv->hw_addr_len || memcmp (priv->hw_addr, hwaddr, hwaddrlen)) { + memcpy (priv->hw_addr, hwaddr, hwaddrlen); - if (priv->hw_addr_len) { - int ifindex = nm_device_get_ifindex (dev); - gsize addrlen; - const guint8 *binaddr; + if (nm_logging_enabled (LOGL_DEBUG, LOGD_HW | LOGD_DEVICE)) { + char *addrstr = nm_utils_hwaddr_ntoa_len (hwaddr, hwaddrlen); - g_return_val_if_fail (ifindex > 0, FALSE); - - binaddr = nm_platform_link_get_address (ifindex, &addrlen); - - if (addrlen != priv->hw_addr_len) { - nm_log_err (LOGD_HW | LOGD_DEVICE, - "(%s): hardware address is wrong length (got %zd, expected %d)", - nm_device_get_iface (dev), addrlen, priv->hw_addr_len); - } else { - changed = !!memcmp (priv->hw_addr, binaddr, addrlen); - if (changed) { - char *addrstr = nm_utils_hwaddr_ntoa_len (binaddr, priv->hw_addr_len); - - memcpy (priv->hw_addr, binaddr, addrlen); - nm_log_dbg (LOGD_HW | LOGD_DEVICE, - "(%s): hardware address is %s", - nm_device_get_iface (dev), addrstr); + nm_log_dbg (LOGD_HW | LOGD_DEVICE, "(%s): hardware address now %s", iface, addrstr); g_free (addrstr); - g_object_notify (G_OBJECT (dev), NM_DEVICE_HW_ADDRESS); } + g_object_notify (G_OBJECT (dev), NM_DEVICE_HW_ADDRESS); } } else { - int i; - - /* hw_addr_len is now 0; see if hw_addr was already empty */ - for (i = 0; i < sizeof (priv->hw_addr) && !changed; i++) { - if (priv->hw_addr[i]) - changed = TRUE; - } - if (changed) { + /* Invalid or no hardware address */ + if (priv->hw_addr_len != 0) { memset (priv->hw_addr, 0, sizeof (priv->hw_addr)); nm_log_dbg (LOGD_HW | LOGD_DEVICE, "(%s): previous hardware address is no longer valid", - nm_device_get_iface (dev)); + iface); g_object_notify (G_OBJECT (dev), NM_DEVICE_HW_ADDRESS); } } - - return changed; + priv->hw_addr_len = hwaddrlen; } gboolean @@ -7118,17 +7090,6 @@ spec_match_list (NMDevice *device, const GSList *specs) return matched; } -static guint -get_hw_address_length (NMDevice *dev, gboolean *out_permanent) -{ - size_t len; - - if (nm_platform_link_get_address (nm_device_get_ifindex (dev), &len)) - return len; - else - return 0; -} - /***********************************************************/ #define DEFAULT_AUTOCONNECT TRUE @@ -7375,9 +7336,9 @@ set_property (GObject *object, guint prop_id, { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (object); NMPlatformLink *platform_device; - const char *hw_addr; - guint hw_addr_len; - + const char *hw_addr, *p; + guint count; + switch (prop_id) { case PROP_PLATFORM_DEVICE: platform_device = g_value_get_pointer (value); @@ -7455,18 +7416,21 @@ set_property (GObject *object, guint prop_id, priv->is_master = g_value_get_boolean (value); break; case PROP_HW_ADDRESS: - hw_addr_len = nm_device_get_hw_address_length (NM_DEVICE (object), NULL); - g_return_if_fail (hw_addr_len <= NM_UTILS_HWADDR_LEN_MAX); - priv->hw_addr_len = hw_addr_len; + /* construct only */ + p = hw_addr = g_value_get_string (value); - hw_addr = g_value_get_string (value); - if (!hw_addr) - break; - if (priv->hw_addr_len == 0) { - g_warn_if_fail (*hw_addr == '\0'); + /* Hardware address length is the number of ':' plus 1 */ + count = 1; + while (p && *p) { + if (*p++ == ':') + count++; + } + if (count < ETH_ALEN || count > NM_UTILS_HWADDR_LEN_MAX) { + g_warn_if_fail (!hw_addr || *hw_addr == '\0'); break; } + priv->hw_addr_len = count; if (!nm_utils_hwaddr_aton_len (hw_addr, priv->hw_addr, priv->hw_addr_len)) { g_warning ("Could not parse hw-address '%s'", hw_addr); memset (priv->hw_addr, 0, sizeof (priv->hw_addr)); @@ -7647,7 +7611,6 @@ nm_device_class_init (NMDeviceClass *klass) klass->bring_up = bring_up; klass->take_down = take_down; klass->carrier_changed = carrier_changed; - klass->get_hw_address_length = get_hw_address_length; /* Properties */ g_object_class_install_property diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 3d45ccf3a9..871764531f 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -55,12 +55,13 @@ #define NM_DEVICE_AVAILABLE_CONNECTIONS "available-connections" #define NM_DEVICE_PHYSICAL_PORT_ID "physical-port-id" #define NM_DEVICE_MTU "mtu" -#define NM_DEVICE_TYPE_DESC "type-desc" /* Internal only */ -#define NM_DEVICE_RFKILL_TYPE "rfkill-type" /* Internal only */ -#define NM_DEVICE_IFINDEX "ifindex" /* Internal only */ -#define NM_DEVICE_IS_MASTER "is-master" /* Internal only */ -#define NM_DEVICE_MASTER "master" /* Internal only */ -#define NM_DEVICE_HW_ADDRESS "hw-address" /* Internal only */ +#define NM_DEVICE_HW_ADDRESS "hw-address" + +#define NM_DEVICE_TYPE_DESC "type-desc" /* Internal only */ +#define NM_DEVICE_RFKILL_TYPE "rfkill-type" /* Internal only */ +#define NM_DEVICE_IFINDEX "ifindex" /* Internal only */ +#define NM_DEVICE_IS_MASTER "is-master" /* Internal only */ +#define NM_DEVICE_MASTER "master" /* Internal only */ #define NM_DEVICE_HAS_PENDING_ACTION "has-pending-action" /* Internal only */ /* Internal signals */ @@ -115,10 +116,8 @@ typedef struct { /* Carrier state (IFF_LOWER_UP) */ void (*carrier_changed) (NMDevice *, gboolean carrier); - void (* update_hw_address) (NMDevice *self); void (* update_permanent_hw_address) (NMDevice *self); void (* update_initial_hw_address) (NMDevice *self); - guint (* get_hw_address_length) (NMDevice *self, gboolean *out_permanent); guint32 (* get_generic_capabilities) (NMDevice *self); diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index 156c3abc8d..98ff610229 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -290,12 +290,6 @@ device_state_changed (NMDevice *device, } } -static guint -get_hw_address_length (NMDevice *device, gboolean *out_permanent) -{ - return 0; -} - static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection) { @@ -596,7 +590,6 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass) object_class->get_property = get_property; object_class->set_property = set_property; - device_class->get_hw_address_length = get_hw_address_length; device_class->check_connection_compatible = check_connection_compatible; device_class->check_connection_available = check_connection_available; device_class->complete_connection = complete_connection; From e2270040c0a25bee1549dda9054cca482b896819 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 10 Apr 2014 15:29:45 -0500 Subject: [PATCH 4/6] core: use Interface Identifiers for IPv6 SLAAC addresses Ethernet-like interfaces aren't the only type of interfaces that can run IPv6 but the rdisc code only returns an address if the interface's hardware address is 6 bytes. Interface types like PPP (rfc5072) and IPoIB (rfc4391) have their own specifications for constructing IPv6 addresses and we should honor those. So instead of expecting a MAC address, let each device subclass generate an Interface Identifier and use that for rdisc instead. --- src/NetworkManagerUtils.c | 117 +++++++++++++++++++++++++++++ src/NetworkManagerUtils.h | 32 ++++++++ src/config/tests/Makefile.am | 1 + src/devices/nm-device.c | 45 +++++++++-- src/devices/nm-device.h | 3 + src/devices/wifi/tests/Makefile.am | 1 + src/rdisc/nm-lndp-rdisc.c | 30 +------- src/rdisc/nm-rdisc.c | 12 +-- src/rdisc/nm-rdisc.h | 6 +- src/rdisc/tests/rdisc.c | 3 - 10 files changed, 203 insertions(+), 47 deletions(-) diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 888141c65c..ed604bf0f4 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "NetworkManagerUtils.h" #include "nm-utils.h" @@ -1596,3 +1597,119 @@ nm_utils_is_specific_hostname (const char *name) return FALSE; } +/******************************************************************/ + +/* Returns the "u" (universal/local) bit value for a Modified EUI-64 */ +static gboolean +get_gre_eui64_u_bit (guint32 addr) +{ + static const struct { + guint32 mask; + guint32 result; + } items[] = { + { 0xff000000 }, { 0x7f000000 }, /* IPv4 loopback */ + { 0xf0000000 }, { 0xe0000000 }, /* IPv4 multicast */ + { 0xffffff00 }, { 0xe0000000 }, /* IPv4 local multicast */ + { 0xffffffff }, { INADDR_BROADCAST }, /* limited broadcast */ + { 0xff000000 }, { 0x00000000 }, /* zero net */ + { 0xff000000 }, { 0x0a000000 }, /* private 10 (RFC3330) */ + { 0xfff00000 }, { 0xac100000 }, /* private 172 */ + { 0xffff0000 }, { 0xc0a80000 }, /* private 192 */ + { 0xffff0000 }, { 0xa9fe0000 }, /* IPv4 link-local */ + { 0xffffff00 }, { 0xc0586300 }, /* anycast 6-to-4 */ + { 0xffffff00 }, { 0xc0000200 }, /* test 192 */ + { 0xfffe0000 }, { 0xc6120000 }, /* test 198 */ + }; + guint i; + + for (i = 0; i < G_N_ELEMENTS (items); i++) { + if ((addr & htonl (items[i].mask)) == htonl (items[i].result)) + return 0x00; /* "local" scope */ + } + return 0x02; /* "universal" scope */ +} + +/** + * nm_utils_get_ipv6_interface_identifier: + * @link_type: the hardware link type + * @hwaddr: the hardware address of the interface + * @hwaddr_len: the length (in bytes) of @hwaddr + * @out_iid: on success, filled with the interface identifier; on failure + * zeroed out + * + * Constructs an interface identifier in "Modified EUI-64" format which is + * suitable for constructing IPv6 addresses. Note that the identifier is + * not obscured in any way (eg, RFC3041). + * + * Returns: %TRUE if the interface identifier could be constructed, %FALSE if + * if could not be constructed. + */ +gboolean +nm_utils_get_ipv6_interface_identifier (NMLinkType link_type, + const guint8 *hwaddr, + guint hwaddr_len, + NMUtilsIPv6IfaceId *out_iid) +{ + guint32 addr; + + g_return_val_if_fail (hwaddr != NULL, FALSE); + g_return_val_if_fail (hwaddr_len > 0, FALSE); + g_return_val_if_fail (out_iid != NULL, FALSE); + + out_iid->id = 0; + + switch (link_type) { + case NM_LINK_TYPE_INFINIBAND: + /* Use the port GUID per http://tools.ietf.org/html/rfc4391#section-8, + * making sure to set the 'u' bit to 1. The GUID is the lower 64 bits + * of the IPoIB interface's hardware address. + */ + g_return_val_if_fail (hwaddr_len == INFINIBAND_ALEN, FALSE); + memcpy (out_iid->id_u8, hwaddr + INFINIBAND_ALEN - 8, 8); + out_iid->id_u8[0] |= 0x02; + return TRUE; + case NM_LINK_TYPE_GRE: + case NM_LINK_TYPE_GRETAP: + /* Hardware address is the network-endian IPv4 address */ + g_return_val_if_fail (hwaddr_len == 4, FALSE); + addr = * (guint32 *) hwaddr; + out_iid->id_u8[0] = get_gre_eui64_u_bit (addr); + out_iid->id_u8[1] = 0x00; + out_iid->id_u8[2] = 0x5E; + out_iid->id_u8[3] = 0xFE; + memcpy (out_iid->id_u8 + 4, &addr, 4); + return TRUE; + default: + if (hwaddr_len == ETH_ALEN) { + /* Translate 48-bit MAC address to a 64-bit Modified EUI-64. See + * http://tools.ietf.org/html/rfc4291#appendix-A + */ + out_iid->id_u8[0] = hwaddr[0] ^ 0x02; + out_iid->id_u8[1] = hwaddr[1]; + out_iid->id_u8[2] = hwaddr[2]; + out_iid->id_u8[3] = 0xff; + out_iid->id_u8[4] = 0xfe; + out_iid->id_u8[5] = hwaddr[3]; + out_iid->id_u8[6] = hwaddr[4]; + out_iid->id_u8[7] = hwaddr[5]; + return TRUE; + } + break; + } + return FALSE; +} + +void +nm_utils_ipv6_addr_set_interface_identfier (struct in6_addr *addr, + const NMUtilsIPv6IfaceId iid) +{ + memcpy (addr->s6_addr + 8, &iid.id_u8, 8); +} + +void +nm_utils_ipv6_interface_identfier_get_from_addr (NMUtilsIPv6IfaceId *iid, + const struct in6_addr *addr) +{ + memcpy (iid, addr->s6_addr + 8, 8); +} + diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index f1cd62a263..6e80069f57 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -27,6 +27,7 @@ #include #include "nm-connection.h" +#include "nm-platform.h" gboolean nm_ethernet_address_is_valid (const struct ether_addr *test_addr); @@ -131,4 +132,35 @@ const char *nm_utils_ip6_property_path (const char *ifname, const char *property gboolean nm_utils_is_specific_hostname (const char *name); +/* IPv6 Interface Identifer helpers */ + +/** + * NMUtilsIPv6IfaceId: + * @id: convenience member for validity checking; never use directly + * @id_u8: the 64-bit Interface Identifier + * + * Holds a 64-bit IPv6 Interface Identifier. The IID is a sequence of bytes + * and should not normally be treated as a %guint64, but this is done for + * convenience of validity checking and initialization. + */ +typedef struct { + union { + guint64 id; + guint8 id_u8[8]; + }; +} NMUtilsIPv6IfaceId; + +#define NM_UTILS_IPV6_IFACE_ID_INIT { .id = 0 }; + +gboolean nm_utils_get_ipv6_interface_identifier (NMLinkType link_type, + const guint8 *hwaddr, + guint len, + NMUtilsIPv6IfaceId *out_iid); + +void nm_utils_ipv6_addr_set_interface_identfier (struct in6_addr *addr, + const NMUtilsIPv6IfaceId iid); + +void nm_utils_ipv6_interface_identfier_get_from_addr (NMUtilsIPv6IfaceId *iid, + const struct in6_addr *addr); + #endif /* NETWORK_MANAGER_UTILS_H */ diff --git a/src/config/tests/Makefile.am b/src/config/tests/Makefile.am index dc0f308bab..31ce724395 100644 --- a/src/config/tests/Makefile.am +++ b/src/config/tests/Makefile.am @@ -5,6 +5,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/ \ -I$(top_srcdir)/src/config \ -I$(top_srcdir)/src/devices \ + -I${top_srcdir}/src/platform \ -DG_LOG_DOMAIN=\""NetworkManager"\" \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index f638f09b95..f9b65929f6 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -575,6 +575,38 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface) g_free (old_ip_iface); } +static gboolean +get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) +{ + NMLinkType link_type; + const guint8 *hwaddr = NULL; + size_t hwaddr_len = 0; + int ifindex; + gboolean success; + + /* If we get here, we *must* have a kernel netdev, which implies an ifindex */ + ifindex = nm_device_get_ip_ifindex (self); + g_assert (ifindex); + + link_type = nm_platform_link_get_type (ifindex); + g_return_val_if_fail (link_type > NM_LINK_TYPE_UNKNOWN, 0); + + hwaddr = nm_platform_link_get_address (ifindex, &hwaddr_len); + if (!hwaddr_len) + return FALSE; + + success = nm_utils_get_ipv6_interface_identifier (link_type, + hwaddr, + hwaddr_len, + out_iid); + if (!success) { + nm_log_warn (LOGD_HW, "(%s): failed to generate interface identifier " + "for link type %u hwaddr_len %zu", + nm_device_get_ip_iface (self), link_type, hwaddr_len); + } + return success; +} + const char * nm_device_get_driver (NMDevice *self) { @@ -3647,15 +3679,14 @@ static void addrconf6_start_with_link_ready (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const guint8 *hw_addr; - size_t hw_addr_len = 0; + NMUtilsIPv6IfaceId iid; g_assert (priv->rdisc); - /* FIXME: what if interface has no lladdr, like PPP? */ - hw_addr = nm_platform_link_get_address (nm_device_get_ip_ifindex (self), &hw_addr_len); - if (hw_addr_len) - nm_rdisc_set_lladdr (priv->rdisc, (const char *) hw_addr, hw_addr_len); + if (NM_DEVICE_GET_CLASS (self)->get_ip_iface_identifier (self, &iid)) + nm_rdisc_set_iid (priv->rdisc, iid); + else + nm_log_warn (LOGD_IP6, "(%s): failed to get interface identifier", nm_device_get_ip_iface (self)); nm_device_ipv6_sysctl_set (self, "accept_ra", "1"); nm_device_ipv6_sysctl_set (self, "accept_ra_defrtr", "0"); @@ -3664,7 +3695,6 @@ addrconf6_start_with_link_ready (NMDevice *self) priv->rdisc_config_changed_sigid = g_signal_connect (priv->rdisc, NM_RDISC_CONFIG_CHANGED, G_CALLBACK (rdisc_config_changed), self); - nm_rdisc_start (priv->rdisc); } @@ -7611,6 +7641,7 @@ nm_device_class_init (NMDeviceClass *klass) klass->bring_up = bring_up; klass->take_down = take_down; klass->carrier_changed = carrier_changed; + klass->get_ip_iface_identifier = get_ip_iface_identifier; /* Properties */ g_object_class_install_property diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 871764531f..ed0c06a7be 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -30,6 +30,7 @@ #include "nm-types.h" #include "nm-connection.h" #include "nm-rfkill-manager.h" +#include "NetworkManagerUtils.h" /* Properties */ #define NM_DEVICE_UDI "udi" @@ -119,6 +120,8 @@ typedef struct { void (* update_permanent_hw_address) (NMDevice *self); void (* update_initial_hw_address) (NMDevice *self); + gboolean (* get_ip_iface_identifier) (NMDevice *self, NMUtilsIPv6IfaceId *out_iid); + guint32 (* get_generic_capabilities) (NMDevice *self); gboolean (* is_available) (NMDevice *self); diff --git a/src/devices/wifi/tests/Makefile.am b/src/devices/wifi/tests/Makefile.am index 7cdd149650..4b9b9dc242 100644 --- a/src/devices/wifi/tests/Makefile.am +++ b/src/devices/wifi/tests/Makefile.am @@ -3,6 +3,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/libnm-util \ -I$(top_builddir)/libnm-util \ -I$(top_srcdir)/src/logging \ + -I${top_srcdir}/src/platform \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/devices/wifi \ -I$(top_builddir)/src \ diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/rdisc/nm-lndp-rdisc.c index 0f0a00e86c..87934e65a8 100644 --- a/src/rdisc/nm-lndp-rdisc.c +++ b/src/rdisc/nm-lndp-rdisc.c @@ -433,43 +433,18 @@ translate_preference (enum ndp_route_preference preference) } } -static void -fill_address_from_mac (struct in6_addr *address, const char *mac) -{ - unsigned char *identifier = address->s6_addr + 8; - - if (!mac) - return; - - /* Translate 48-bit MAC address to a 64-bit modified interface identifier - * and write it to the second half of the IPv6 address. - * - * See http://tools.ietf.org/html/rfc3513#page-21 - */ - memcpy (identifier, mac, 3); - identifier[0] ^= 0x02; - identifier[3] = 0xff; - identifier[4] = 0xfe; - memcpy (identifier + 5, mac + 3, 3); -} - static int receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) { NMRDisc *rdisc = (NMRDisc *) user_data; NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); NMRDiscConfigMap changed = 0; - size_t lladdrlen = 0; - const char *lladdr = NULL; struct ndp_msgra *msgra = ndp_msgra (msg); NMRDiscGateway gateway; guint32 now = nm_utils_get_monotonic_timestamp_s (); int offset; int hop_limit; - if (rdisc->lladdr) - lladdr = g_bytes_get_data (rdisc->lladdr, &lladdrlen); - /* Router discovery is subject to the following RFC documents: * * http://tools.ietf.org/html/rfc4861 @@ -542,7 +517,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) /* Address */ if (ndp_msg_opt_prefix_flag_auto_addr_conf (msg, offset)) { - if (route.plen == 64 && lladdrlen == 6) { + if (route.plen == 64 && rdisc->iid.id) { memset (&address, 0, sizeof (address)); address.address = route.network; address.timestamp = now; @@ -551,7 +526,8 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) if (address.preferred > address.lifetime) address.preferred = address.lifetime; - fill_address_from_mac (&address.address, lladdr); + /* Add the Interface Identifier to the lower 64 bits */ + nm_utils_ipv6_addr_set_interface_identfier (&address.address, rdisc->iid); if (add_address (rdisc, &address)) changed |= NM_RDISC_CONFIG_ADDRESSES; diff --git a/src/rdisc/nm-rdisc.c b/src/rdisc/nm-rdisc.c index 1682924c2a..d3dc14a194 100644 --- a/src/rdisc/nm-rdisc.c +++ b/src/rdisc/nm-rdisc.c @@ -40,11 +40,11 @@ static guint signals[LAST_SIGNAL] = { 0 }; /******************************************************************/ void -nm_rdisc_set_lladdr (NMRDisc *rdisc, const char *addr, size_t addrlen) +nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid) { - if (rdisc->lladdr) - g_bytes_unref (rdisc->lladdr); - rdisc->lladdr = addr ? g_bytes_new (addr, addrlen) : NULL; + g_return_if_fail (NM_IS_RDISC (rdisc)); + + rdisc->iid = iid; } void @@ -152,7 +152,6 @@ nm_rdisc_init (NMRDisc *rdisc) rdisc->routes = g_array_new (FALSE, FALSE, sizeof (NMRDiscRoute)); rdisc->dns_servers = g_array_new (FALSE, FALSE, sizeof (NMRDiscDNSServer)); rdisc->dns_domains = g_array_new (FALSE, FALSE, sizeof (NMRDiscDNSDomain)); - rdisc->lladdr = NULL; rdisc->hop_limit = 64; } @@ -167,9 +166,6 @@ nm_rdisc_finalize (GObject *object) g_array_unref (rdisc->routes); g_array_unref (rdisc->dns_servers); g_array_unref (rdisc->dns_domains); - - if (rdisc->lladdr) - g_bytes_unref (rdisc->lladdr); } static void diff --git a/src/rdisc/nm-rdisc.h b/src/rdisc/nm-rdisc.h index fba06bc215..642e7c9670 100644 --- a/src/rdisc/nm-rdisc.h +++ b/src/rdisc/nm-rdisc.h @@ -26,6 +26,8 @@ #include #include +#include "NetworkManagerUtils.h" + #define NM_TYPE_RDISC (nm_rdisc_get_type ()) #define NM_RDISC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_RDISC, NMRDisc)) #define NM_RDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_RDISC, NMRDiscClass)) @@ -110,7 +112,7 @@ typedef struct { int ifindex; char *ifname; - GBytes *lladdr; + NMUtilsIPv6IfaceId iid; gint32 max_addresses; gint32 rtr_solicitations; gint32 rtr_solicitation_interval; @@ -133,7 +135,7 @@ typedef struct { GType nm_rdisc_get_type (void); -void nm_rdisc_set_lladdr (NMRDisc *rdisc, const char *addr, size_t addrlen); +void nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid); void nm_rdisc_start (NMRDisc *rdisc); #endif /* NM_RDISC_H */ diff --git a/src/rdisc/tests/rdisc.c b/src/rdisc/tests/rdisc.c index 1fdf5b67a5..26237093df 100644 --- a/src/rdisc/tests/rdisc.c +++ b/src/rdisc/tests/rdisc.c @@ -37,7 +37,6 @@ main (int argc, char **argv) NMRDisc *(*new) (int ifindex, const char *ifname); int ifindex = 1; const char *ifname; - char mac[6] = { 0x02, 0xaa, 0xbb, 0xcc, 0xdd, 0xee }; #if !GLIB_CHECK_VERSION (2, 35, 0) g_type_init (); @@ -69,8 +68,6 @@ main (int argc, char **argv) if (!rdisc) return EXIT_FAILURE; - nm_rdisc_set_lladdr (rdisc, mac, 6); - nm_rdisc_start (rdisc); g_main_loop_run (loop); From 05e99e24a133409d454bacaa4d2cf22e02ea3c25 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 22 Jul 2014 16:20:36 -0500 Subject: [PATCH 5/6] trivial: move addrconf6_start_with_link_ready() above caller --- src/devices/nm-device.c | 46 ++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index f9b65929f6..5422c1115d 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -3636,6 +3636,29 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device nm_device_activate_schedule_ip6_config_result (device); } +static void +addrconf6_start_with_link_ready (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMUtilsIPv6IfaceId iid; + + g_assert (priv->rdisc); + + if (NM_DEVICE_GET_CLASS (self)->get_ip_iface_identifier (self, &iid)) + nm_rdisc_set_iid (priv->rdisc, iid); + else + nm_log_warn (LOGD_IP6, "(%s): failed to get interface identifier", nm_device_get_ip_iface (self)); + + nm_device_ipv6_sysctl_set (self, "accept_ra", "1"); + nm_device_ipv6_sysctl_set (self, "accept_ra_defrtr", "0"); + nm_device_ipv6_sysctl_set (self, "accept_ra_pinfo", "0"); + nm_device_ipv6_sysctl_set (self, "accept_ra_rtr_pref", "0"); + + priv->rdisc_config_changed_sigid = g_signal_connect (priv->rdisc, NM_RDISC_CONFIG_CHANGED, + G_CALLBACK (rdisc_config_changed), self); + nm_rdisc_start (priv->rdisc); +} + static gboolean addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) { @@ -3675,29 +3698,6 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) return TRUE; } -static void -addrconf6_start_with_link_ready (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMUtilsIPv6IfaceId iid; - - g_assert (priv->rdisc); - - if (NM_DEVICE_GET_CLASS (self)->get_ip_iface_identifier (self, &iid)) - nm_rdisc_set_iid (priv->rdisc, iid); - else - nm_log_warn (LOGD_IP6, "(%s): failed to get interface identifier", nm_device_get_ip_iface (self)); - - nm_device_ipv6_sysctl_set (self, "accept_ra", "1"); - nm_device_ipv6_sysctl_set (self, "accept_ra_defrtr", "0"); - nm_device_ipv6_sysctl_set (self, "accept_ra_pinfo", "0"); - nm_device_ipv6_sysctl_set (self, "accept_ra_rtr_pref", "0"); - - priv->rdisc_config_changed_sigid = g_signal_connect (priv->rdisc, NM_RDISC_CONFIG_CHANGED, - G_CALLBACK (rdisc_config_changed), self); - nm_rdisc_start (priv->rdisc); -} - static void addrconf6_cleanup (NMDevice *self) { From 288bf39e440cdc24b6b06efae4bb6c5407ab575e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 22 Jul 2014 16:24:07 -0500 Subject: [PATCH 6/6] core: fail IPv6 router discovery if IID cannot be generated If the IID cannot be generated, the IPv6 address resulting from the combination of an advertised prefix and 64-bits of zero is both wrong and quite likely to clash with some other machine on the network that doesn't implement IPv6 quite right either. Require an valid interface identifier. If NetworkManager doesn't know how to generate one, then we should fix NM to do so. --- src/devices/nm-device.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 5422c1115d..ee6c3862ea 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -315,7 +315,7 @@ static gboolean nm_device_master_add_slave (NMDevice *dev, NMDevice *slave, gboo static void nm_device_slave_notify_enslave (NMDevice *dev, gboolean success); static void nm_device_slave_notify_release (NMDevice *dev, NMDeviceStateReason reason); -static void addrconf6_start_with_link_ready (NMDevice *self); +static gboolean addrconf6_start_with_link_ready (NMDevice *self); static gboolean nm_device_get_default_unmanaged (NMDevice *device); @@ -3396,9 +3396,12 @@ linklocal6_complete (NMDevice *self) nm_log_dbg (LOGD_DEVICE, "[%s] linklocal6: waiting for link-local addresses successful, continue with method %s", nm_device_get_iface (self), method); - if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) - addrconf6_start_with_link_ready (self); - else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0) + if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) { + if (!addrconf6_start_with_link_ready (self)) { + /* Time out IPv6 instead of failing the entire activation */ + nm_device_activate_schedule_ip6_config_timeout (self); + } + } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0) nm_device_activate_schedule_ip6_config_result (self); else g_return_if_fail (FALSE); @@ -3636,7 +3639,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device nm_device_activate_schedule_ip6_config_result (device); } -static void +static gboolean addrconf6_start_with_link_ready (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -3644,10 +3647,11 @@ addrconf6_start_with_link_ready (NMDevice *self) g_assert (priv->rdisc); - if (NM_DEVICE_GET_CLASS (self)->get_ip_iface_identifier (self, &iid)) - nm_rdisc_set_iid (priv->rdisc, iid); - else + if (!NM_DEVICE_GET_CLASS (self)->get_ip_iface_identifier (self, &iid)) { nm_log_warn (LOGD_IP6, "(%s): failed to get interface identifier", nm_device_get_ip_iface (self)); + return FALSE; + } + nm_rdisc_set_iid (priv->rdisc, iid); nm_device_ipv6_sysctl_set (self, "accept_ra", "1"); nm_device_ipv6_sysctl_set (self, "accept_ra_defrtr", "0"); @@ -3657,9 +3661,10 @@ addrconf6_start_with_link_ready (NMDevice *self) priv->rdisc_config_changed_sigid = g_signal_connect (priv->rdisc, NM_RDISC_CONFIG_CHANGED, G_CALLBACK (rdisc_config_changed), self); nm_rdisc_start (priv->rdisc); + return TRUE; } -static gboolean +static NMActStageReturn addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -3690,12 +3695,14 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) /* ensure link local is ready... */ ret = linklocal6_start (self); - if (ret == NM_ACT_STAGE_RETURN_SUCCESS) - addrconf6_start_with_link_ready (self); - else - g_return_val_if_fail (ret == NM_ACT_STAGE_RETURN_POSTPONE, TRUE); + if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { + /* success; wait for the LL address to show up */ + return TRUE; + } - return TRUE; + /* success; already have the LL address; kick off router discovery */ + g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); + return addrconf6_start_with_link_ready (self); } static void