/* * Copyright (C) 2018 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. */ /** * @{ * * @file * @author Martine Lenders */ #include #include "log.h" #include "net/eui48.h" #include "net/ieee802154.h" #include "net/ipv6.h" #include "net/netdev.h" #include "net/l2util.h" #if defined(MODULE_CC110X) || defined(MODULE_NRFMIN) static void _create_eui64_from_short(const uint8_t *addr, size_t addr_len, eui64_t *eui64) { const unsigned offset = sizeof(eui64_t) - addr_len; memset(eui64->uint8, 0, sizeof(eui64->uint8)); eui64->uint8[3] = 0xff; eui64->uint8[4] = 0xfe; memcpy(&eui64->uint8[offset], addr, addr_len); } #endif /* defined(MODULE_CC110X) || defined(MODULE_NRFMIN) */ int l2util_eui64_from_addr(int dev_type, const uint8_t *addr, size_t addr_len, eui64_t *eui64) { switch (dev_type) { #if defined(MODULE_NETDEV_ETH) || defined(MODULE_ESP_NOW) || \ defined(MODULE_NORDIC_SOFTDEVICE_BLE) || defined(MODULE_NIMBLE_NETIF) case NETDEV_TYPE_ETHERNET: case NETDEV_TYPE_ESP_NOW: case NETDEV_TYPE_BLE: if (addr_len == sizeof(eui48_t)) { eui48_to_eui64(eui64, (const eui48_t *)addr); return sizeof(eui64_t); } else { return -EINVAL; } #endif /* defined(MODULE_NETDEV_ETH) || defined(MODULE_ESP_NOW) \ defined(MODULE_NORDIC_SOFTDEVICE_BLE) || defined(MODULE_NIMBLE_NETIF) */ #if defined(MODULE_NETDEV_IEEE802154) || defined(MODULE_XBEE) case NETDEV_TYPE_IEEE802154: switch (addr_len) { /* EUI-64 can *not* be generated from the short address */ case IEEE802154_LONG_ADDRESS_LEN: memcpy(eui64, addr, addr_len); return sizeof(eui64_t); default: return -EINVAL; } #endif /* defined(MODULE_NETDEV_IEEE802154) || defined(MODULE_XBEE) */ #if defined(MODULE_CC110X) || defined(MODULE_NRFMIN) case NETDEV_TYPE_CC110X: case NETDEV_TYPE_NRFMIN: if (addr_len <= 3) { _create_eui64_from_short(addr, addr_len, eui64); return sizeof(eui64_t); } else { return -EINVAL; } #endif /* defined(MODULE_CC110X) || defined(MODULE_NRFMIN) */ default: (void)addr; (void)addr_len; (void)eui64; #ifdef DEVELHELP LOG_ERROR("l2util: can't convert hardware address to EUI-64 " "for device type %d\n", dev_type); #endif /* DEVELHELP */ assert(false); break; } return -ENOTSUP; } int l2util_ipv6_iid_from_addr(int dev_type, const uint8_t *addr, size_t addr_len, eui64_t *iid) { switch (dev_type) { #if defined(MODULE_NETDEV_IEEE802154) || defined(MODULE_XBEE) case NETDEV_TYPE_IEEE802154: if (ieee802154_get_iid(iid, addr, addr_len) != NULL) { return sizeof(eui64_t); } else { return -EINVAL; } #endif /* defined(MODULE_NETDEV_IEEE802154) || defined(MODULE_XBEE) */ #if defined(MODULE_CC110X) || defined(MODULE_NRFMIN) case NETDEV_TYPE_CC110X: case NETDEV_TYPE_NRFMIN: if (addr_len <= 3) { _create_eui64_from_short(addr, addr_len, iid); /* since this address conversion is based on the IEEE * 802.15.4 address conversion for short addresses, the * U/L bit doesn't need to be flipped. * see https://tools.ietf.org/html/rfc6282#section-3.2.2 */ return sizeof(eui64_t); } else { return -EINVAL; } #endif /* defined(MODULE_CC110X) || defined(MODULE_NRFMIN) */ #if defined(MODULE_NORDIC_SOFTDEVICE_BLE) || defined(MODULE_NIMBLE_NETIF) case NETDEV_TYPE_BLE: /* for BLE we don't flip the universal/local flag... */ return l2util_eui64_from_addr(dev_type, addr, addr_len, iid); #endif /* defined(MODULE_NORDIC_SOFTDEVICE_BLE) || defined(MODULE_NIMBLE_NETIF) */ default: { int res = l2util_eui64_from_addr(dev_type, addr, addr_len, iid); if (res == sizeof(eui64_t)) { iid->uint8[0] ^= 0x02; } return res; } } return -ENOTSUP; } int l2util_ipv6_iid_to_addr(int dev_type, const eui64_t *iid, uint8_t *addr) { switch (dev_type) { #if defined(MODULE_NETDEV_ETH) || defined(MODULE_ESP_NOW) case NETDEV_TYPE_ETHERNET: case NETDEV_TYPE_ESP_NOW: eui48_from_ipv6_iid((eui48_t *)addr, iid); return sizeof(eui48_t); #endif /* defined(MODULE_NETDEV_ETH) || defined(MODULE_ESP_NOW) */ #if defined(MODULE_NORDIC_SOFTDEVICE_BLE) || defined(MODULE_NIMBLE_NETIF) case NETDEV_TYPE_BLE: addr[0] = iid->uint8[0]; addr[1] = iid->uint8[1]; addr[2] = iid->uint8[2]; addr[3] = iid->uint8[5]; addr[4] = iid->uint8[6]; addr[5] = iid->uint8[7]; return sizeof(eui48_t); #endif /* defined(MODULE_NORDIC_SOFTDEVICE_BLE) || defined(MODULE_NIMBLE_NETIF) */ #if defined(MODULE_NETDEV_IEEE802154) || defined(MODULE_XBEE) case NETDEV_TYPE_IEEE802154: /* assume address was based on EUI-64 * (see https://tools.ietf.org/html/rfc6775#section-5.2) */ memcpy(addr, iid, sizeof(eui64_t)); addr[0] ^= 0x02; return sizeof(eui64_t); #endif /* defined(MODULE_NETDEV_IEEE802154) || defined(MODULE_XBEE) */ #ifdef MODULE_NRFMIN case NETDEV_TYPE_NRFMIN: addr[0] = iid->uint8[6]; addr[1] = iid->uint8[7]; return sizeof(uint16_t); #endif /* MODULE_NETDEV_IEEE802154 */ #ifdef MODULE_CC110X case NETDEV_TYPE_CC110X: addr[0] = iid->uint8[7]; return sizeof(uint8_t); #endif /* MODULE_CC110X */ default: (void)iid; (void)addr; #ifdef DEVELHELP LOG_ERROR("l2util: can't convert IID to hardware address for " "device type %d\n", dev_type); #endif /* DEVELHELP */ assert(false); break; } return -ENOTSUP; } int l2util_ndp_addr_len_from_l2ao(int dev_type, const ndp_opt_t *opt) { switch (dev_type) { #ifdef MODULE_CC110X case NETDEV_TYPE_CC110X: (void)opt; return sizeof(uint8_t); #endif /* MODULE_CC110X */ #if defined(MODULE_NETDEV_ETH) || defined(MODULE_ESP_NOW) || \ defined(MODULE_NORDIC_SOFTDEVICE_BLE) || defined(MODULE_NIMBLE_NETIF) case NETDEV_TYPE_ETHERNET: case NETDEV_TYPE_ESP_NOW: case NETDEV_TYPE_BLE: /* see https://tools.ietf.org/html/rfc2464#section-6*/ if (opt->len == 1U) { return sizeof(eui48_t); } else { return -EINVAL; } #endif /* defined(MODULE_NETDEV_ETH) || defined(MODULE_ESP_NOW) \ defined(MODULE_NORDIC_SOFTDEVICE_BLE) || defined(MODULE_NIMBLE_NETIF) */ #ifdef MODULE_NRFMIN case NETDEV_TYPE_NRFMIN: (void)opt; return sizeof(uint16_t); #endif /* MODULE_NRFMIN */ #if defined(MODULE_NETDEV_IEEE802154) || defined(MODULE_XBEE) case NETDEV_TYPE_IEEE802154: /* see https://tools.ietf.org/html/rfc4944#section-8 */ switch (opt->len) { case 1U: return IEEE802154_SHORT_ADDRESS_LEN; case 2U: return IEEE802154_LONG_ADDRESS_LEN; default: return -EINVAL; } #endif /* defined(MODULE_NETDEV_IEEE802154) || defined(MODULE_XBEE) */ default: (void)opt; #ifdef DEVELHELP LOG_ERROR("l2util: can't get address length from NDP link-layer " "address option for device type %d\n", dev_type); #endif assert(false); break; } return -ENOTSUP; } /** @} */