From 49844ea55f1cdaec729b5e90c6dd8db6c890b044 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 23 May 2018 11:21:51 +0200 Subject: [PATCH] device: generate pseudo 48-bit address from the WPAN short one If an IEEE 802.15.4 WPAN device has a short address it is to be used to get an interface identifier. --- src/devices/nm-device.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 23c541d1b..023a7676b 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1736,7 +1736,11 @@ static gboolean get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMPlatform *platform = nm_device_get_platform (self); const NMPlatformLink *pllink; + const guint8 *hwaddr; + guint8 pseudo_hwaddr[ETH_ALEN]; + guint hwaddr_len; int ifindex; gboolean success; @@ -1744,7 +1748,7 @@ get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) ifindex = nm_device_get_ip_ifindex (self); g_return_val_if_fail (ifindex > 0, FALSE); - pllink = nm_platform_link_get (nm_device_get_platform (self), ifindex); + pllink = nm_platform_link_get (platform, ifindex); if ( !pllink || NM_IN_SET (pllink->type, NM_LINK_TYPE_NONE, NM_LINK_TYPE_UNKNOWN)) return FALSE; @@ -1754,9 +1758,35 @@ get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) if (pllink->addr.len > NM_UTILS_HWADDR_LEN_MAX) g_return_val_if_reached (FALSE); + hwaddr = pllink->addr.data; + hwaddr_len = pllink->addr.len; + + if (pllink->type == NM_LINK_TYPE_6LOWPAN) { + /* If the underlying IEEE 802.15.4 device has a short address we generate + * a "pseudo 48-bit address" that's to be used in the same fashion as a + * wired Ethernet address. The mechanism is specified in Section 6. of + * RFC 4944 */ + guint16 pan_id; + guint16 short_addr; + + short_addr = nm_platform_wpan_get_short_addr (platform, pllink->parent); + if (short_addr != G_MAXUINT16) { + pan_id = nm_platform_wpan_get_pan_id (platform, pllink->parent); + pseudo_hwaddr[0] = short_addr & 0xff; + pseudo_hwaddr[1] = (short_addr >> 8) & 0xff; + pseudo_hwaddr[2] = 0; + pseudo_hwaddr[3] = 0; + pseudo_hwaddr[4] = pan_id & 0xff; + pseudo_hwaddr[5] = (pan_id >> 8) & 0xff; + + hwaddr = pseudo_hwaddr; + hwaddr_len = G_N_ELEMENTS (pseudo_hwaddr); + } + } + success = nm_utils_get_ipv6_interface_identifier (pllink->type, - pllink->addr.data, - pllink->addr.len, + hwaddr, + hwaddr_len, priv->dev_id, out_iid); if (!success) {