summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2014-07-23 14:24:58 -0500
committerDan Williams <dcbw@redhat.com>2014-07-23 14:24:58 -0500
commit69ea2705eceee1c8c1ead77dc4013b3c217a235b (patch)
treec05e836c5cbd0f606a2a778d1232055ea77fff51
parent15734a4ba5a15f0062809e7280136cf99ae6150b (diff)
parent288bf39e440cdc24b6b06efae4bb6c5407ab575e (diff)
downloadNetworkManager-69ea2705eceee1c8c1ead77dc4013b3c217a235b.tar.gz
merge: construct IPv6 addresses using Interface Identifiers (bgo #682623)
-rw-r--r--libnm-util/nm-utils.h5
-rw-r--r--src/NetworkManagerUtils.c117
-rw-r--r--src/NetworkManagerUtils.h32
-rw-r--r--src/config/tests/Makefile.am1
-rw-r--r--src/config/tests/nm-test-device.c15
-rw-r--r--src/devices/adsl/nm-device-adsl.c15
-rw-r--r--src/devices/bluetooth/nm-device-bt.c10
-rw-r--r--src/devices/nm-device-private.h1
-rw-r--r--src/devices/nm-device.c227
-rw-r--r--src/devices/nm-device.h18
-rw-r--r--src/devices/wifi/tests/Makefile.am1
-rw-r--r--src/devices/wwan/nm-device-modem.c7
-rw-r--r--src/platform/nm-linux-platform.c20
-rw-r--r--src/rdisc/nm-lndp-rdisc.c30
-rw-r--r--src/rdisc/nm-rdisc.c12
-rw-r--r--src/rdisc/nm-rdisc.h6
-rw-r--r--src/rdisc/tests/rdisc.c3
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);