diff --git a/sys/include/net/gnrc/netif.h b/sys/include/net/gnrc/netif.h index 236891c38cd1..37eb8413e63b 100644 --- a/sys/include/net/gnrc/netif.h +++ b/sys/include/net/gnrc/netif.h @@ -46,6 +46,7 @@ #endif #include "net/ndp.h" #include "net/netdev.h" +#include "net/netopt.h" #include "rmutex.h" #ifdef __cplusplus diff --git a/sys/include/net/gnrc/netif/internal.h b/sys/include/net/gnrc/netif/internal.h index 22e31ed08c5c..4a055343aa32 100644 --- a/sys/include/net/gnrc/netif/internal.h +++ b/sys/include/net/gnrc/netif/internal.h @@ -22,6 +22,7 @@ #define NET_GNRC_NETIF_INTERNAL_H #include "net/gnrc/netif.h" +#include "net/netopt.h" #ifdef MODULE_GNRC_IPV6_NIB #include "net/gnrc/ipv6/nib/conf.h" @@ -403,7 +404,37 @@ static inline bool gnrc_netif_is_6lbr(const gnrc_netif_t *netif) #define gnrc_netif_is_6lbr(netif) (false) #endif +/** + * @name Device type based function + * + * These functions' behavior is based around the gnrc_netif_t::device_type of + * an interface. + * + * @attention Special care needs to be taken for those functions when porting + * a new network device type or link-layer protocol: They might + * need adaptions for your port + * @{ + */ +/** + * @brief Get the default link-layer address option for the given + * gnrc_netif_t::device_type of a network interface + * + * @param[in] netif The network interface to get the default link-layer + * address option for. + * + * @return Either @ref NETOPT_ADDRESS or @ref NETOPT_ADDRESS_LONG. + */ +netopt_t gnrc_netif_get_l2addr_opt(const gnrc_netif_t *netif); + #if defined(MODULE_GNRC_IPV6) || defined(DOXYGEN) +/** + * @brief Initialize IPv6 MTU and other packet length related members of + * @ref gnrc_netif_t based on gnrc_netif_t::device_type + * + * @param[in,out] netif The network interface to initialize the MTU for. + */ +void gnrc_netif_ipv6_init_mtu(gnrc_netif_t *netif); + /** * @brief Converts a given hardware address to an IPv6 IID. * @@ -484,11 +515,44 @@ static inline int gnrc_netif_ipv6_get_iid(gnrc_netif_t *netif, eui64_t *iid) (void)iid; return -ENOTSUP; } + +/** + * @brief Derives the length of the link-layer address in an NDP link-layer + * address option from that option's length field and the given device + * type. + * + * @note If an RFC exists that specifies how IPv6 operates over a link-layer, + * this function usually implements the section "Unicast Address + * Mapping". + * + * @see [RFC 4861, section 4.6.1](https://tools.ietf.org/html/rfc4861#section-4.6.1) + * + * @pre `netif->flags & GNRC_NETIF_FLAGS_HAS_L2ADDR` + * + * @attention When `NDEBUG` is not defined, the node fails with an assertion + * instead of returning `-ENOTSUP` + * + * @param[in] netif The network interface @p opt was received on within an NDP + * message. + * @param[in] opt An NDP source/target link-layer address option. + * + * @return Length of the link-layer address in @p opt on success + * @return `-ENOTSUP`, when implementation does not know how to derive the + * length of the link-layer address from @p opt's length field based + * on gnrc_netif_t::device_type of @p netif. + * @return `-EINVAL` if `opt->len` was an invalid value for the given + * gnrc_netif_t::device_type of @p netif. + */ +int gnrc_netif_ndp_addr_len_from_l2ao(gnrc_netif_t *netif, + const ndp_opt_t *opt); #else /* defined(MODULE_GNRC_IPV6) || defined(DOXYGEN) */ -#define gnrc_netif_ipv6_iid_from_addr(netif, addr, addr_len, iid) (-ENOTSUP) -#define gnrc_netif_ipv6_iid_to_addr(netif, iid, addr) (-ENOTSUP) +#define gnrc_netif_ipv6_init_mtu(netif) (void)netif +#define gnrc_netif_ipv6_iid_from_addr(netif, addr, addr_len, iid) (-ENOTSUP) +#define gnrc_netif_ipv6_iid_to_addr(netif, iid, addr) (-ENOTSUP) +#define gnrc_netif_ndp_addr_len_from_l2ao(netif, opt) (-ENOTSUP) #define gnrc_netif_ipv6_get_iid(netif, iid) (-ENOTSUP) #endif /* defined(MODULE_GNRC_IPV6) || defined(DOXYGEN) */ +/** @} */ #ifdef __cplusplus } diff --git a/sys/net/gnrc/netif/gnrc_netif.c b/sys/net/gnrc/netif/gnrc_netif.c index cfab9795f77b..df0085d371dd 100644 --- a/sys/net/gnrc/netif/gnrc_netif.c +++ b/sys/net/gnrc/netif/gnrc_netif.c @@ -1109,27 +1109,8 @@ static void _update_l2addr_from_dev(gnrc_netif_t *netif) { netdev_t *dev = netif->dev; int res; - netopt_t opt = NETOPT_ADDRESS; + netopt_t opt = gnrc_netif_get_l2addr_opt(netif); - switch (netif->device_type) { -#if defined(MODULE_NETDEV_IEEE802154) || defined(MODULE_XBEE) \ - || defined(MODULE_NORDIC_SOFTDEVICE_BLE) - case NETDEV_TYPE_BLE: - case NETDEV_TYPE_IEEE802154: { - uint16_t tmp; - - res = dev->driver->get(dev, NETOPT_SRC_LEN, &tmp, sizeof(tmp)); - assert(res == sizeof(tmp)); - netif->l2addr_len = (uint8_t)tmp; - if (tmp == IEEE802154_LONG_ADDRESS_LEN) { - opt = NETOPT_ADDRESS_LONG; - } - } - break; -#endif - default: - break; - } res = dev->driver->get(dev, opt, netif->l2addr, sizeof(netif->l2addr)); if (res != -ENOTSUP) { @@ -1155,60 +1136,7 @@ static void _init_from_device(gnrc_netif_t *netif) (void)res; assert(res == sizeof(tmp)); netif->device_type = (uint8_t)tmp; - switch (netif->device_type) { -#if defined(MODULE_NETDEV_IEEE802154) || defined(MODULE_NRFMIN) || \ - defined(MODULE_XBEE) || defined(MODULE_ESP_NOW) || \ - defined(MODULE_GNRC_SIXLOENC) - case NETDEV_TYPE_IEEE802154: - case NETDEV_TYPE_NRFMIN: -#ifdef MODULE_GNRC_SIXLOWPAN_IPHC - netif->flags |= GNRC_NETIF_FLAGS_6LO_HC; -#endif - /* intentionally falls through */ - case NETDEV_TYPE_ESP_NOW: -#ifdef MODULE_GNRC_IPV6 - res = dev->driver->get(dev, NETOPT_MAX_PACKET_SIZE, &tmp, sizeof(tmp)); - assert(res == sizeof(tmp)); -#ifdef MODULE_GNRC_SIXLOWPAN - netif->ipv6.mtu = IPV6_MIN_MTU; - netif->sixlo.max_frag_size = tmp; -#else - netif->ipv6.mtu = tmp; -#endif -#endif - break; -#endif /* MODULE_NETDEV_IEEE802154 */ -#ifdef MODULE_NETDEV_ETH - case NETDEV_TYPE_ETHERNET: -#ifdef MODULE_GNRC_IPV6 - netif->ipv6.mtu = ETHERNET_DATA_LEN; -#endif -#if defined(MODULE_GNRC_SIXLOWPAN_IPHC) && defined(MODULE_GNRC_SIXLOENC) - netif->flags |= GNRC_NETIF_FLAGS_6LO_HC; -#endif - break; -#endif -#ifdef MODULE_NORDIC_SOFTDEVICE_BLE - case NETDEV_TYPE_BLE: - netif->ipv6.mtu = IPV6_MIN_MTU; -#ifdef MODULE_GNRC_SIXLOWPAN_IPHC - netif->flags |= GNRC_NETIF_FLAGS_6LO_HC; -#endif - break; -#endif - default: -#ifdef MODULE_GNRC_IPV6 - res = dev->driver->get(dev, NETOPT_MAX_PACKET_SIZE, &tmp, sizeof(tmp)); - if (res < 0) { - /* assume maximum possible transition unit */ - netif->ipv6.mtu = UINT16_MAX; - } - else { - netif->ipv6.mtu = tmp; - } -#endif - break; - } + gnrc_netif_ipv6_init_mtu(netif); _update_l2addr_from_dev(netif); } diff --git a/sys/net/gnrc/netif/gnrc_netif_device_type.c b/sys/net/gnrc/netif/gnrc_netif_device_type.c index a44fdc3a3b1c..031a0474dbeb 100644 --- a/sys/net/gnrc/netif/gnrc_netif_device_type.c +++ b/sys/net/gnrc/netif/gnrc_netif_device_type.c @@ -17,11 +17,111 @@ #include #include "log.h" +#ifdef MODULE_GNRC_IPV6 +#include "net/ipv6.h" +#endif #include "net/gnrc/netif.h" #include "net/eui48.h" +#include "net/ethernet.h" #include "net/ieee802154.h" +netopt_t gnrc_netif_get_l2addr_opt(const gnrc_netif_t *netif) +{ + netopt_t res = NETOPT_ADDRESS; + + switch (netif->device_type) { +#if defined(MODULE_NETDEV_IEEE802154) || defined(MODULE_XBEE) || \ + defined(MODULE_NORDIC_SOFTDEVICE_BLE) + case NETDEV_TYPE_IEEE802154: + case NETDEV_TYPE_BLE: { + netdev_t *dev = netif->dev; + int r; + uint16_t tmp; + + r = dev->driver->get(dev, NETOPT_SRC_LEN, &tmp, sizeof(tmp)); + assert(r == sizeof(tmp)); + assert(r <= ((int)UINT8_MAX)); + (void)r; + if (tmp == IEEE802154_LONG_ADDRESS_LEN) { + res = NETOPT_ADDRESS_LONG; + } + } + break; +#endif + default: + break; + } + return res; +} + +#ifdef MODULE_GNRC_IPV6 +void gnrc_netif_ipv6_init_mtu(gnrc_netif_t *netif) +{ +#ifdef MODULE_GNRC_IPV6 + netdev_t *dev = netif->dev; + int res; + uint16_t tmp; + + switch (netif->device_type) { +#if defined(MODULE_NETDEV_IEEE802154) || defined(MODULE_NRFMIN) || \ + defined(MODULE_XBEE) || defined(MODULE_ESP_NOW) || \ + defined(MODULE_GNRC_SIXLOENC) + case NETDEV_TYPE_IEEE802154: + case NETDEV_TYPE_NRFMIN: +#ifdef MODULE_GNRC_SIXLOWPAN_IPHC + netif->flags |= GNRC_NETIF_FLAGS_6LO_HC; +#endif + /* intentionally falls through */ + case NETDEV_TYPE_ESP_NOW: + res = dev->driver->get(dev, NETOPT_MAX_PACKET_SIZE, + &tmp, sizeof(tmp)); + assert(res == sizeof(tmp)); +#ifdef MODULE_GNRC_SIXLOWPAN + netif->ipv6.mtu = IPV6_MIN_MTU; + netif->sixlo.max_frag_size = tmp; +#else + netif->ipv6.mtu = tmp; +#endif + break; +#endif /* defined(MODULE_NETDEV_IEEE802154) || defined(MODULE_NRFMIN) || \ + * defined(MODULE_XBEE) || defined(MODULE_ESP_NOW) */ +#ifdef MODULE_NETDEV_ETH + case NETDEV_TYPE_ETHERNET: #ifdef MODULE_GNRC_IPV6 + netif->ipv6.mtu = ETHERNET_DATA_LEN; +#endif +#if defined(MODULE_GNRC_SIXLOWPAN_IPHC) && defined(MODULE_GNRC_SIXLOENC) + netif->flags |= GNRC_NETIF_FLAGS_6LO_HC; +#endif + break; +#endif +#ifdef MODULE_NORDIC_SOFTDEVICE_BLE + case NETDEV_TYPE_BLE: + netif->ipv6.mtu = IPV6_MIN_MTU; +#ifdef MODULE_GNRC_SIXLOWPAN_IPHC + netif->flags |= GNRC_NETIF_FLAGS_6LO_HC; +#endif + break; +#endif + default: +#ifdef DEVELHELP + LOG_DEBUG("gnrc_netif: getting MTU from device for interface %i\n", + netif->pid); +#endif + res = dev->driver->get(dev, NETOPT_MAX_PACKET_SIZE, + &tmp, sizeof(tmp)); + if (res < 0) { + /* assume maximum possible transition unit */ + netif->ipv6.mtu = UINT16_MAX; + } + else { + netif->ipv6.mtu = tmp; + } + break; + } +#endif +} + #if defined(MODULE_CC110X) || defined(MODULE_NRFMIN) static void _create_iid_from_short(const uint8_t *addr, size_t addr_len, eui64_t *iid) @@ -148,6 +248,56 @@ int gnrc_netif_ipv6_iid_to_addr(const gnrc_netif_t *netif, const eui64_t *iid, } return -ENOTSUP; } + +int gnrc_netif_ndp_addr_len_from_l2ao(gnrc_netif_t *netif, + const ndp_opt_t *opt) +{ + assert(netif->flags & GNRC_NETIF_FLAGS_HAS_L2ADDR); + switch (netif->device_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) + case NETDEV_TYPE_ETHERNET: + case NETDEV_TYPE_ESP_NOW: + /* see https://tools.ietf.org/html/rfc2464#section-6*/ + if (opt->len == 1U) { + return ETHERNET_ADDR_LEN; + } + else { + return -EINVAL; + } +#endif /* defined(MODULE_NETDEV_ETH) || defined(MODULE_ESP_NOW) */ +#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("gnrc_netif: can't get address length from NDP link-layer " + "address option on interface %u\n", netif->pid); +#endif + assert(false); + break; + } + return -ENOTSUP; +} #endif /* MODULE_GNRC_IPV6 */ /** @} */ diff --git a/sys/net/gnrc/network_layer/ipv6/nib/_nib-arsm.c b/sys/net/gnrc/network_layer/ipv6/nib/_nib-arsm.c index c2d37650a44f..ca0e2f0ff5ff 100644 --- a/sys/net/gnrc/network_layer/ipv6/nib/_nib-arsm.c +++ b/sys/net/gnrc/network_layer/ipv6/nib/_nib-arsm.c @@ -30,18 +30,6 @@ static char addr_str[IPV6_ADDR_MAX_STR_LEN]; -/** - * @brief Determines supposed link-layer address from interface and option - * length - * - * @param[in] netif A network interface. - * @param[in] opt A SL2AO or TL2AO. - * - * @return The length of the L2 address carried in @p opt. - */ -static inline unsigned _get_l2addr_len(gnrc_netif_t *netif, - const ndp_opt_t *opt); - void _snd_ns(const ipv6_addr_t *tgt, gnrc_netif_t *netif, const ipv6_addr_t *src, const ipv6_addr_t *dst) { @@ -104,10 +92,10 @@ void _handle_sl2ao(gnrc_netif_t *netif, const ipv6_hdr_t *ipv6, { assert(netif != NULL); _nib_onl_entry_t *nce = _nib_onl_get(&ipv6->src, netif->pid); - unsigned l2addr_len; + int l2addr_len; - l2addr_len = _get_l2addr_len(netif, sl2ao); - if (l2addr_len == 0U) { + l2addr_len = gnrc_netif_ndp_addr_len_from_l2ao(netif, sl2ao); + if (l2addr_len < 0) { DEBUG("nib: Unexpected SL2AO length. Ignoring SL2AO\n"); return; } @@ -174,43 +162,6 @@ void _handle_sl2ao(gnrc_netif_t *netif, const ipv6_hdr_t *ipv6, } } -static inline unsigned _get_l2addr_len(gnrc_netif_t *netif, - const ndp_opt_t *opt) -{ - switch (netif->device_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) - case NETDEV_TYPE_ETHERNET: - case NETDEV_TYPE_ESP_NOW: - (void)opt; - return ETHERNET_ADDR_LEN; -#endif /* defined(MODULE_NETDEV_ETH) || defined(MODULE_ESP_NOW) */ -#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: - switch (opt->len) { - case 1U: - return IEEE802154_SHORT_ADDRESS_LEN; - case 2U: - return IEEE802154_LONG_ADDRESS_LEN; - default: - return 0U; - } -#endif /* defined(MODULE_NETDEV_IEEE802154) || defined(MODULE_XBEE) */ - default: - (void)opt; - return 0U; - } -} - #if GNRC_IPV6_NIB_CONF_ARSM /** * @brief Calculates exponential back-off for retransmission timer for @@ -379,13 +330,13 @@ void _probe_nbr(_nib_onl_entry_t *nbr, bool reset) void _handle_adv_l2(gnrc_netif_t *netif, _nib_onl_entry_t *nce, const icmpv6_hdr_t *icmpv6, const ndp_opt_t *tl2ao) { - unsigned l2addr_len = 0; + int l2addr_len = 0; assert(nce != NULL); assert(netif != NULL); if (tl2ao != NULL) { - l2addr_len = _get_l2addr_len(netif, tl2ao); - if (l2addr_len == 0U) { + l2addr_len = gnrc_netif_ndp_addr_len_from_l2ao(netif, tl2ao); + if (l2addr_len < 0) { DEBUG("nib: Unexpected TL2AO length. Ignoring TL2AO\n"); return; }