diff --git a/drivers/ng_at86rf2xx/ng_at86rf2xx_netdev.c b/drivers/ng_at86rf2xx/ng_at86rf2xx_netdev.c index 793c289ee2..dce3ce320f 100644 --- a/drivers/ng_at86rf2xx/ng_at86rf2xx_netdev.c +++ b/drivers/ng_at86rf2xx/ng_at86rf2xx_netdev.c @@ -19,6 +19,7 @@ * @} */ +#include "net/eui64.h" #include "net/ng_ieee802154.h" #include "net/ng_netbase.h" #include "ng_at86rf2xx.h" @@ -400,6 +401,20 @@ static int _get(ng_netdev_t *device, ng_netconf_opt_t opt, *((uint16_t *)val) = dev->pan; return sizeof(uint16_t); + case NETCONF_OPT_IPV6_IID: + if (max_len < sizeof(eui64_t)) { + return -EOVERFLOW; + } + if (dev->options & NG_AT86RF2XX_OPT_SRC_ADDR_LONG) { + uint64_t addr = ng_at86rf2xx_get_addr_long(dev); + ng_ieee802154_get_iid(val, (uint8_t *)&addr, 8); + } + else { + uint16_t addr = ng_at86rf2xx_get_addr_short(dev); + ng_ieee802154_get_iid(val, (uint8_t *)&addr, 2); + } + return sizeof(eui64_t); + case NETCONF_OPT_PROTO: if (max_len < sizeof(ng_nettype_t)) { return -EOVERFLOW; diff --git a/drivers/xbee/xbee.c b/drivers/xbee/xbee.c index 93277a49ee..eec23d15e1 100644 --- a/drivers/xbee/xbee.c +++ b/drivers/xbee/xbee.c @@ -25,6 +25,8 @@ #include "xbee.h" #include "hwtimer.h" #include "msg.h" +#include "net/eui64.h" +#include "net/ng_ieee802154.h" #include "periph/cpuid.h" #define ENABLE_DEBUG (0) @@ -620,6 +622,18 @@ static int _get(ng_netdev_t *netdev, ng_netconf_opt_t opt, *((uint16_t *)value) = 2; } return sizeof(uint16_t); + case NETCONF_OPT_IPV6_IID: + if (max_len < sizeof(eui64_t)) { + return -EOVERFLOW; + } + if (dev->addr_flags & XBEE_ADDR_FLAGS_LONG) { + ng_ieee802154_get_iid(value, (uint8_t *)&dev->addr_long, 8); + } + else { + ng_ieee802154_get_iid(value, (uint8_t *)&dev->addr_short, 2); + } + + return sizeof(eui64_t); case NETCONF_OPT_CHANNEL: return _get_channel(dev, (uint8_t *)value, max_len); case NETCONF_OPT_MAX_PACKET_SIZE: diff --git a/sys/include/net/eui64.h b/sys/include/net/eui64.h new file mode 100644 index 0000000000..5a68c8692e --- /dev/null +++ b/sys/include/net/eui64.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup net_eui64 IEEE EUI-64 identifier + * @ingroup net + * @brief Type definiton of the IEEE EUI-64 identifier + * @see + * IEEE, "Guidelines for 64-bit Global Identifier (EUI-64)" + * + * @{ + * + * @file + * @brief EUI-64 data type definition + * + * @author Martine Lenders + * @author Oliver Hahm + */ +#ifndef EUI64_H_ +#define EUI64_H_ + +#include +#include "byteorder.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Data type to represent an EUI-64. + */ +typedef union { + network_uint64_t uint64; /**< represented as 64 bit value */ + uint8_t uint8[8]; /**< split into 8 8-bit words. */ + network_uint16_t uint16[4]; /**< split into 4 16-bit words. */ +} eui64_t; + +#ifdef __cplusplus +} +#endif + +#endif /* EUI64_H_ */ +/** @} */ diff --git a/sys/include/net/ng_ethernet.h b/sys/include/net/ng_ethernet.h index 7cef7730bc..3d6ab91d69 100644 --- a/sys/include/net/ng_ethernet.h +++ b/sys/include/net/ng_ethernet.h @@ -22,7 +22,10 @@ #ifndef NG_ETHERNET_H_ #define NG_ETHERNET_H_ +#include + #include "net/ng_ethernet/hdr.h" +#include "net/eui64.h" #ifdef __cplusplus extern "C" { @@ -46,6 +49,29 @@ extern "C" { #define NG_ETHERNET_MAX_LEN (NG_ETHERNET_FRAME_LEN + \ NG_ETHERNET_FCS_LEN) +/** + * @brief Generates an IPv6 interface identifier from a 48-bit MAC address. + * + * @see + * RFC 2464, section 4 + * + * + * @param[out] eui64 The resulting EUI-64. + * @param[in] mac A 48-bit MAC address. Is expected to be at least + * @ref NG_ETHERNET_ADDR_LEN long. + */ +static inline void ng_ethernet_get_iid(eui64_t *eui64, uint8_t *mac) +{ + eui64->uint8[0] = mac[0] ^ 0x02; + eui64->uint8[1] = mac[1]; + eui64->uint8[2] = mac[2]; + eui64->uint8[3] = 0xff; + eui64->uint8[4] = 0xfe; + eui64->uint8[5] = mac[3]; + eui64->uint8[6] = mac[4]; + eui64->uint8[7] = mac[5]; +} + #ifdef __cplusplus } #endif diff --git a/sys/include/net/ng_ieee802154.h b/sys/include/net/ng_ieee802154.h index 374c87a544..459d281e23 100644 --- a/sys/include/net/ng_ieee802154.h +++ b/sys/include/net/ng_ieee802154.h @@ -21,8 +21,9 @@ #ifndef NG_IEEE802154_H_ #define NG_IEEE802154_H_ -#include -#include "byteorder.h" +#include + +#include "net/eui64.h" #ifdef __cplusplus extern "C" { @@ -62,13 +63,62 @@ extern "C" { /** @} */ /** - * @brief Data type to represent an EUI-64. + * @brief Generates an IPv6 interface identifier from an IEEE 802.15.4 address. + * + * @see + * RFC 4944, section 6 + * + * @see + * RFC 6282, section 3.2.2 + * + * + * @param[out] eui64 The resulting EUI-64. + * @param[in] addr An IEEE 802.15.4 address. + * @param[in] addr_len The length of @p addr. Must be 2 (short address), + * 4 (PAN ID + short address), or 8 (long address). + * + * @return Copy of @p eui64 on success. + * @return NULL, if @p addr_len was of illegal length. */ -typedef union { - le_uint64_t uint64; /**< represented as 64 bit value */ - uint8_t uint8[8]; /**< split into 8 8-bit words. */ - le_uint16_t uint16[4]; /**< split into 4 16-bit words. */ -} eui64_t ; +static inline eui64_t *ng_ieee802154_get_iid(eui64_t *eui64, uint8_t *addr, + size_t addr_len) +{ + int i = 0; + + eui64->uint8[0] = eui64->uint8[1] = 0; + + switch (addr_len) { + case 8: + eui64->uint8[0] = addr[i++] ^ 0x02; + eui64->uint8[1] = addr[i++]; + eui64->uint8[2] = addr[i++]; + eui64->uint8[3] = addr[i++]; + eui64->uint8[4] = addr[i++]; + eui64->uint8[5] = addr[i++]; + eui64->uint8[6] = addr[i++]; + eui64->uint8[7] = addr[i++]; + break; + + case 4: + eui64->uint8[0] = addr[i++] ^ 0x02; + eui64->uint8[1] = addr[i++]; + + case 2: + eui64->uint8[2] = 0; + eui64->uint8[3] = 0xff; + eui64->uint8[4] = 0xfe; + eui64->uint8[5] = 0; + eui64->uint8[6] = addr[i++]; + eui64->uint8[7] = addr[i++]; + break; + + default: + return NULL; + } + + return eui64; +} + #ifdef __cplusplus } diff --git a/sys/include/net/ng_netconf.h b/sys/include/net/ng_netconf.h index 26b3fd17bb..1071156524 100644 --- a/sys/include/net/ng_netconf.h +++ b/sys/include/net/ng_netconf.h @@ -55,6 +55,22 @@ typedef enum { * Examples for this include the PAN ID in IEEE 802.15.4 */ NETCONF_OPT_NID, + + /** + * @brief get the IPv6 interface identifier of a network interface as + * eui64_t. + * + * @see + * RFC 4291, section 2.5.1 + * + * + * The generation of the interface identifier is dependent on the link-layer. + * Please refer to the appropriate IPv6 over `` specification for + * further implementation details (such as + * RFC 2464 or + * RFC 4944). + */ + NETCONF_OPT_IPV6_IID, NETCONF_OPT_TX_POWER, /**< get/set the output power for radio * devices in dBm as int16_t in host byte * order */ diff --git a/sys/net/link_layer/ng_netdev_eth/ng_netdev_eth.c b/sys/net/link_layer/ng_netdev_eth/ng_netdev_eth.c index 4b19012fd7..db08d7e68e 100644 --- a/sys/net/link_layer/ng_netdev_eth/ng_netdev_eth.c +++ b/sys/net/link_layer/ng_netdev_eth/ng_netdev_eth.c @@ -29,6 +29,7 @@ #include #include "byteorder.h" +#include "net/eui64.h" #include "net/ng_ethernet.h" #include "net/ng_ethertype.h" #include "net/ng_netdev.h" @@ -198,6 +199,21 @@ static inline int _get_addr_len(uint16_t *value, size_t max_len) return sizeof(uint16_t); } +static inline int _get_iid(ng_netdev_eth_t *netdev, eui64_t *value, size_t max_len) +{ + if (max_len < sizeof(eui64_t)) { + /* value buffer not big enough */ + return -EOVERFLOW; + } + + dev_eth_t *dev = netdev->ethdev; + uint8_t addr[NG_ETHERNET_ADDR_LEN]; + dev->driver->get_mac_addr(dev, addr); + ng_ethernet_get_iid(value, addr); + + return sizeof(eui64_t); +} + static inline int _get_max_pkt_sz(uint16_t *value, size_t max_len) { if (max_len != sizeof(uint16_t)) { @@ -244,6 +260,10 @@ static int _get(ng_netdev_t *dev, ng_netconf_opt_t opt, void *value, DEBUG("address length\n"); return _get_addr_len(value, max_len); + case NETCONF_OPT_IPV6_IID: + DEBUG("IPv6 IID\n"); + return _get_iid((ng_netdev_eth_t *)dev, value, max_len); + case NETCONF_OPT_MAX_PACKET_SIZE: DEBUG("maximum packet size\n"); return _get_max_pkt_sz(value, max_len); diff --git a/sys/net/network_layer/ng_ipv6/netif/ng_ipv6_netif.c b/sys/net/network_layer/ng_ipv6/netif/ng_ipv6_netif.c index 8594d1de02..6a4d57df1c 100644 --- a/sys/net/network_layer/ng_ipv6/netif/ng_ipv6_netif.c +++ b/sys/net/network_layer/ng_ipv6/netif/ng_ipv6_netif.c @@ -20,6 +20,7 @@ #include "kernel_types.h" #include "mutex.h" +#include "net/eui64.h" #include "net/ng_ipv6/addr.h" #include "net/ng_ndp.h" #include "net/ng_netapi.h" @@ -445,62 +446,6 @@ ng_ipv6_addr_t *ng_ipv6_netif_find_best_src_addr(kernel_pid_t pid, const ng_ipv6 return _match_prefix(pid, dest, true); } -/* TODO: put this somewhere more central and L2 protocol dependent */ -#define IID_LEN (8) - -static bool _hwaddr_to_iid(uint8_t *iid, const uint8_t *hwaddr, size_t hwaddr_len) -{ - uint8_t i = 0; - - memset(iid, 0, IID_LEN); - - switch (hwaddr_len) { - case 8: - iid[0] = hwaddr[i++]; - iid[0] ^= 0x02; - iid[1] = hwaddr[i++]; - iid[2] = hwaddr[i++]; - iid[3] = hwaddr[i++]; - iid[4] = hwaddr[i++]; - iid[5] = hwaddr[i++]; - iid[6] = hwaddr[i++]; - iid[7] = hwaddr[i++]; - break; - - case 6: - iid[0] = hwaddr[i++]; - iid[0] ^= 0x02; - iid[1] = hwaddr[i++]; - iid[2] = hwaddr[i++]; - iid[3] = 0xff; - iid[4] = 0xfe; - iid[5] = hwaddr[i++]; - iid[6] = hwaddr[i++]; - iid[7] = hwaddr[i++]; - break; - - case 4: - iid[0] = hwaddr[i++]; - iid[0] ^= 0x02; - iid[1] = hwaddr[i++]; - - case 2: - iid[6] = hwaddr[i++]; - - case 1: - iid[3] = 0xff; - iid[4] = 0xfe; - iid[7] = hwaddr[i++]; - break; - - default: - DEBUG("Unknown hardware address length\n"); - return false; - } - - return true; -} - void ng_ipv6_netif_init_by_dev(void) { kernel_pid_t ifs[NG_NETIF_NUMOF]; @@ -508,11 +453,8 @@ void ng_ipv6_netif_init_by_dev(void) for (size_t i = 0; i < ifnum; i++) { ng_ipv6_addr_t addr; - uint16_t hwaddr_len = 0; - uint8_t hwaddr[NG_NETIF_HDR_L2ADDR_MAX_LEN]; - bool try_long = false; + eui64_t iid; ng_ipv6_netif_t *ipv6_if = ng_ipv6_netif_get(ifs[i]); - int res = 0; if (ipv6_if == NULL) { continue; @@ -532,25 +474,14 @@ void ng_ipv6_netif_init_by_dev(void) #endif - if ((ng_netapi_get(ifs[i], NETCONF_OPT_SRC_LEN, 0, &hwaddr_len, - sizeof(hwaddr_len)) != -ENOTSUP) && - (hwaddr_len == 8)) { - try_long = true; + if ((ng_netapi_get(ifs[i], NETCONF_OPT_IPV6_IID, 0, &iid, + sizeof(eui64_t)) < 0)) { + continue; } - if ((try_long && ((res = ng_netapi_get(ifs[i], NETCONF_OPT_ADDRESS_LONG, 0, - &hwaddr, sizeof(hwaddr))) > 0)) || - ((res = ng_netapi_get(ifs[i], NETCONF_OPT_ADDRESS, 0, &hwaddr, - sizeof(hwaddr))) > 0)) { - uint8_t iid[IID_LEN]; - hwaddr_len = (uint16_t)res; - - if (_hwaddr_to_iid(iid, hwaddr, hwaddr_len)) { - ng_ipv6_addr_set_aiid(&addr, iid); - ng_ipv6_addr_set_link_local_prefix(&addr); - _add_addr_to_entry(ipv6_if, &addr, 64, 0); - } - } + ng_ipv6_addr_set_aiid(&addr, iid.uint8); + ng_ipv6_addr_set_link_local_prefix(&addr); + _add_addr_to_entry(ipv6_if, &addr, 64, 0); mutex_unlock(&ipv6_if->mutex); } diff --git a/sys/net/network_layer/ng_sixlowpan/iphc/ng_sixlowpan_iphc.c b/sys/net/network_layer/ng_sixlowpan/iphc/ng_sixlowpan_iphc.c index babdfeb593..a9e5e13ea1 100644 --- a/sys/net/network_layer/ng_sixlowpan/iphc/ng_sixlowpan_iphc.c +++ b/sys/net/network_layer/ng_sixlowpan/iphc/ng_sixlowpan_iphc.c @@ -15,6 +15,7 @@ #include #include "byteorder.h" +#include "net/ng_ieee802154.h" #include "net/ng_ipv6/hdr.h" #include "net/ng_netbase.h" #include "net/ng_sixlowpan/ctx.h" @@ -67,39 +68,9 @@ #define IPHC_M_DAC_DAM_M_8 (0x0b) #define IPHC_M_DAC_DAM_M_UC_PREFIX (0x0c) -static network_uint64_t _init_iid(uint8_t *l2addr, size_t l2addr_len) -{ - network_uint64_t res = { 0 }; - - if (l2addr_len <= 4) { - res = byteorder_htonll(0x000000fffe000000); - - if (l2addr_len == 1) { - res.u8[7] = l2addr[0]; - } - else if (l2addr_len == 2) { - res.u8[6] = l2addr[0]; - res.u8[7] = l2addr[1]; - } - else if (l2addr_len == 4) { - res.u8[0] = l2addr[0]; - res.u8[1] = l2addr[1]; - res.u8[6] = l2addr[2]; - res.u8[7] = l2addr[3]; - } - } - else if (l2addr_len == 8) { - network_uint64_t *l2addr_u64 = (network_uint64_t *)l2addr; - res = *l2addr_u64; - res.u8[0] ^= 0x02; /* swap local/universal bit */ - } - - return res; -} - static inline bool _context_overlaps_iid(ng_sixlowpan_ctx_t *ctx, ng_ipv6_addr_t *addr, - network_uint64_t *iid) + eui64_t *iid) { uint8_t byte_mask[] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01}; @@ -111,11 +82,11 @@ static inline bool _context_overlaps_iid(ng_sixlowpan_ctx_t *ctx, ((ctx->prefix_len > 64) && /* otherwise, if bigger than 64-bit */ /* compare bytes until prefix length with IID */ (memcmp(&(addr->u8[(ctx->prefix_len / 8) + 1]), - &(iid->u8[(ctx->prefix_len / 8) - 7]), + &(iid->uint8[(ctx->prefix_len / 8) - 7]), sizeof(network_uint64_t) - ((ctx->prefix_len / 8) - 7)) == 0) && /* compare bits at prefix length with IID */ (addr->u8[(ctx->prefix_len / 8)] & byte_mask[ctx->prefix_len % 8]) == - (iid->u8[(ctx->prefix_len / 8) - 8] & byte_mask[ctx->prefix_len % 8]))); + (iid->uint8[(ctx->prefix_len / 8) - 8] & byte_mask[ctx->prefix_len % 8]))); } bool ng_sixlowpan_iphc_decode(ng_pktsnip_t *pkt) @@ -230,9 +201,10 @@ bool ng_sixlowpan_iphc_decode(ng_pktsnip_t *pkt) break; case IPHC_SAC_SAM_L2: + ng_ieee802154_get_iid((eui64_t *)(&ipv6_hdr->src.u64[1]), + ng_netif_hdr_get_src_addr(netif_hdr), + netif_hdr->src_l2addr_len); ng_ipv6_addr_set_link_local_prefix(&ipv6_hdr->src); - ipv6_hdr->src.u64[1] = _init_iid(ng_netif_hdr_get_src_addr(netif_hdr), - netif_hdr->src_l2addr_len); break; case IPHC_SAC_SAM_UNSPEC: @@ -256,8 +228,9 @@ bool ng_sixlowpan_iphc_decode(ng_pktsnip_t *pkt) break; case IPHC_SAC_SAM_CTX_L2: - ipv6_hdr->src.u64[1] = _init_iid(ng_netif_hdr_get_src_addr(netif_hdr), - netif_hdr->src_l2addr_len); + ng_ieee802154_get_iid((eui64_t *)(&ipv6_hdr->src.u64[1]), + ng_netif_hdr_get_src_addr(netif_hdr), + netif_hdr->src_l2addr_len); ng_ipv6_addr_init_prefix(&ipv6_hdr->src, &ctx->prefix, ctx->prefix_len); break; @@ -303,9 +276,10 @@ bool ng_sixlowpan_iphc_decode(ng_pktsnip_t *pkt) break; case IPHC_M_DAC_DAM_U_L2: + ng_ieee802154_get_iid((eui64_t *)(&ipv6_hdr->dst.u64[1]), + ng_netif_hdr_get_dst_addr(netif_hdr), + netif_hdr->dst_l2addr_len); ng_ipv6_addr_set_link_local_prefix(&ipv6_hdr->dst); - ipv6_hdr->dst.u64[1] = _init_iid(ng_netif_hdr_get_src_addr(netif_hdr), - netif_hdr->src_l2addr_len); break; case IPHC_M_DAC_DAM_U_CTX_64: @@ -325,8 +299,9 @@ bool ng_sixlowpan_iphc_decode(ng_pktsnip_t *pkt) break; case IPHC_M_DAC_DAM_U_CTX_L2: - ipv6_hdr->dst.u64[1] = _init_iid(ng_netif_hdr_get_src_addr(netif_hdr), - netif_hdr->src_l2addr_len); + ng_ieee802154_get_iid((eui64_t *)(&ipv6_hdr->dst.u64[1]), + ng_netif_hdr_get_dst_addr(netif_hdr), + netif_hdr->dst_l2addr_len); ng_ipv6_addr_init_prefix(&ipv6_hdr->dst, &ctx->prefix, ctx->prefix_len); break; @@ -520,38 +495,24 @@ bool ng_sixlowpan_iphc_encode(ng_pktsnip_t *pkt) } if ((src_ctx != NULL) || ng_ipv6_addr_is_link_local(&(ipv6_hdr->src))) { - uint16_t l2src_len = 0; - uint8_t l2src[8]; + eui64_t iid; - if (netif_hdr->src_l2addr_len > 0) { - l2src_len = netif_hdr->src_l2addr_len; - memcpy(l2src, ng_netif_hdr_get_src_addr(netif_hdr), l2src_len); + if ((netif_hdr->src_l2addr_len == 2) || + (netif_hdr->src_l2addr_len == 4) || + (netif_hdr->src_l2addr_len == 8)) { + ng_ieee802154_get_iid(&iid, ng_netif_hdr_get_src_addr(netif_hdr), + netif_hdr->src_l2addr_len); + addr_comp = true; } else { - bool try_long = false; - - if ((ng_netapi_get(netif_hdr->if_pid, NETCONF_OPT_ADDR_LEN, 0, - &l2src_len, sizeof(l2src_len)) >= 0) && - (l2src_len >= 8)) { - try_long = true; + if (ng_netapi_get(netif_hdr->if_pid, NETCONF_OPT_IPV6_IID, 0, + &iid, sizeof(eui64_t)) >= 0) { + addr_comp = true; } - - if ((!try_long) || (ng_netapi_get(netif_hdr->if_pid, - NETCONF_OPT_ADDRESS_LONG, 0, - &l2src, sizeof(l2src)) < 0)) { - if (ng_netapi_get(netif_hdr->if_pid, NETCONF_OPT_ADDRESS, - 0, &l2src, sizeof(l2src)) < 0) { - l2src_len = 0; - } - } - } - if (l2src_len > 0) { - network_uint64_t iid = _init_iid(l2src, l2src_len); - - if ((memcmp(ipv6_hdr->src.u64 + 1, &iid, - sizeof(network_uint64_t)) == 0) || + if (addr_comp) { + if ((ipv6_hdr->src.u64[1].u64 == iid.uint64.u64) || _context_overlaps_iid(src_ctx, &ipv6_hdr->src, &iid)) { /* 0 bits. The address is derived from link-layer address */ iphc_hdr[IPHC2_IDX] |= IPHC_SAC_SAM_L2; @@ -569,8 +530,6 @@ bool ng_sixlowpan_iphc_encode(ng_pktsnip_t *pkt) memcpy(iphc_hdr + inline_pos, ipv6_hdr->src.u64 + 1, 8); inline_pos += 8; } - - addr_comp = true; } } @@ -647,10 +606,12 @@ bool ng_sixlowpan_iphc_encode(ng_pktsnip_t *pkt) } else if (((dst_ctx != NULL) || ng_ipv6_addr_is_link_local(&ipv6_hdr->dst)) && (netif_hdr->dst_l2addr_len > 0)) { - network_uint64_t iid = _init_iid(ng_netif_hdr_get_dst_addr(netif_hdr), - netif_hdr->dst_l2addr_len); + eui64_t iid; - if ((memcmp(&(ipv6_hdr->dst.u8[8]), &iid, sizeof(uint64_t)) == 0) || + ng_ieee802154_get_iid(&iid, ng_netif_hdr_get_dst_addr(netif_hdr), + netif_hdr->dst_l2addr_len); + + if ((ipv6_hdr->dst.u64[1].u64 == iid.uint64.u64) || _context_overlaps_iid(dst_ctx, &(ipv6_hdr->dst), &iid)) { /* 0 bits. The address is derived using the link-layer address */ iphc_hdr[IPHC2_IDX] |= IPHC_M_DAC_DAM_U_L2;