diff options
author | Dan Williams <dcbw@redhat.com> | 2014-07-23 14:24:58 -0500 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2014-07-23 14:24:58 -0500 |
commit | 69ea2705eceee1c8c1ead77dc4013b3c217a235b (patch) | |
tree | c05e836c5cbd0f606a2a778d1232055ea77fff51 | |
parent | 15734a4ba5a15f0062809e7280136cf99ae6150b (diff) | |
parent | 288bf39e440cdc24b6b06efae4bb6c5407ab575e (diff) | |
download | NetworkManager-69ea2705eceee1c8c1ead77dc4013b3c217a235b.tar.gz |
merge: construct IPv6 addresses using Interface Identifiers (bgo #682623)
-rw-r--r-- | libnm-util/nm-utils.h | 5 | ||||
-rw-r--r-- | src/NetworkManagerUtils.c | 117 | ||||
-rw-r--r-- | src/NetworkManagerUtils.h | 32 | ||||
-rw-r--r-- | src/config/tests/Makefile.am | 1 | ||||
-rw-r--r-- | src/config/tests/nm-test-device.c | 15 | ||||
-rw-r--r-- | src/devices/adsl/nm-device-adsl.c | 15 | ||||
-rw-r--r-- | src/devices/bluetooth/nm-device-bt.c | 10 | ||||
-rw-r--r-- | src/devices/nm-device-private.h | 1 | ||||
-rw-r--r-- | src/devices/nm-device.c | 227 | ||||
-rw-r--r-- | src/devices/nm-device.h | 18 | ||||
-rw-r--r-- | src/devices/wifi/tests/Makefile.am | 1 | ||||
-rw-r--r-- | src/devices/wwan/nm-device-modem.c | 7 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 20 | ||||
-rw-r--r-- | src/rdisc/nm-lndp-rdisc.c | 30 | ||||
-rw-r--r-- | src/rdisc/nm-rdisc.c | 12 | ||||
-rw-r--r-- | src/rdisc/nm-rdisc.h | 6 | ||||
-rw-r--r-- | src/rdisc/tests/rdisc.c | 3 |
17 files changed, 310 insertions, 210 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/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 888141c65c..ed604bf0f4 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -29,6 +29,7 @@ #include <sys/types.h> #include <sys/wait.h> #include <linux/if.h> +#include <linux/if_infiniband.h> #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 <net/ethernet.h> #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/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 0c35bb7ada..c4a98fa3ab 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,21 +479,10 @@ 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)); } /**************************************************************/ -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; -} - static gboolean carrier_update_cb (gpointer user_data) { @@ -629,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-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..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); @@ -324,6 +324,8 @@ static void _set_state_full (NMDevice *device, NMDeviceStateReason reason, gboolean quitting); +static void nm_device_update_hw_address (NMDevice *dev); + /***********************************************************/ static GQuark @@ -573,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) { @@ -2751,6 +2785,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 +2796,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 +3242,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 +3264,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 (), @@ -3356,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); @@ -3597,6 +3640,31 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device } static gboolean +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_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"); + 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); + return TRUE; +} + +static NMActStageReturn addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -3627,34 +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); - - return TRUE; -} - -static void -addrconf6_start_with_link_ready (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - 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); - - 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); + if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { + /* success; wait for the LL address to show up */ + return TRUE; + } - nm_rdisc_start (priv->rdisc); + /* 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 @@ -6923,12 +6971,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) { @@ -6940,68 +6982,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; } -gboolean +static void nm_device_update_hw_address (NMDevice *dev) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev); - gboolean changed = FALSE, permanent = FALSE; - - priv->hw_addr_len = nm_device_get_hw_address_length (dev, &permanent); - - /* If the address can't be changed, don't bother trying */ - if (permanent) - return FALSE; + int ifindex = nm_device_get_ifindex (dev); + const char *iface = nm_device_get_iface (dev); + const guint8 *hwaddr; + gsize hwaddrlen = 0; - if (priv->hw_addr_len) { - int ifindex = nm_device_get_ip_ifindex (dev); - gsize addrlen; - const guint8 *binaddr; + if (ifindex <= 0) + return; - g_return_val_if_fail (ifindex > 0, 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); - binaddr = nm_platform_link_get_address (ifindex, &addrlen); + if (nm_logging_enabled (LOGL_DEBUG, LOGD_HW | LOGD_DEVICE)) { + char *addrstr = nm_utils_hwaddr_ntoa_len (hwaddr, hwaddrlen); - 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 @@ -7107,17 +7127,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_ip_ifindex (dev), &len)) - return len; - else - return 0; -} - /***********************************************************/ #define DEFAULT_AUTOCONNECT TRUE @@ -7364,7 +7373,8 @@ set_property (GObject *object, guint prop_id, { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (object); NMPlatformLink *platform_device; - const char *hw_addr; + const char *hw_addr, *p; + guint count; switch (prop_id) { case PROP_PLATFORM_DEVICE: @@ -7443,16 +7453,21 @@ 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 = g_value_get_string (value); - if (!hw_addr) - break; - if (priv->hw_addr_len == 0) { - g_warn_if_fail (*hw_addr == '\0'); + /* construct only */ + p = hw_addr = g_value_get_string (value); + + /* 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)); @@ -7633,7 +7648,7 @@ 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; + 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 3d45ccf3a9..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" @@ -55,12 +56,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 +117,10 @@ 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); + + gboolean (* get_ip_iface_identifier) (NMDevice *self, NMUtilsIPv6IfaceId *out_iid); guint32 (* get_generic_capabilities) (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/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; 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; - - nladdr = rtnllink ? rtnl_link_get_addr (rtnllink) : NULL; + size_t l = 0; + gconstpointer a = 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 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 <stdlib.h> #include <netinet/in.h> +#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); |