static inline kernel_pid_t _next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len, kernel_pid_t iface, ipv6_addr_t *dst, gnrc_pktsnip_t *pkt) { kernel_pid_t found_iface; #if defined(MODULE_GNRC_SIXLOWPAN_ND) (void)pkt; found_iface = gnrc_sixlowpan_nd_next_hop_l2addr(l2addr, l2addr_len, iface, dst); if (found_iface > KERNEL_PID_UNDEF) { return found_iface; } #endif #if defined(MODULE_GNRC_NDP_NODE) found_iface = gnrc_ndp_node_next_hop_l2addr(l2addr, l2addr_len, iface, dst, pkt); #elif !defined(MODULE_GNRC_SIXLOWPAN_ND) && defined(MODULE_GNRC_IPV6_NC) (void)pkt; gnrc_ipv6_nc_t *nc = gnrc_ipv6_nc_get(iface, dst); found_iface = gnrc_ipv6_nc_get_l2_addr(l2addr, l2addr_len, nc); #elif !defined(MODULE_GNRC_SIXLOWPAN_ND) found_iface = KERNEL_PID_UNDEF; (void)l2addr; (void)l2addr_len; (void)iface; (void)dst; (void)pkt; *l2addr_len = 0; #endif return found_iface; }
static void test_ipv6_nc_get_l2_addr__NULL_entry(void) { gnrc_ipv6_nc_t *entry = NULL; uint8_t l2_addr[GNRC_IPV6_NC_L2_ADDR_MAX]; uint8_t l2_addr_len = 0; TEST_ASSERT_EQUAL_INT(KERNEL_PID_UNDEF, gnrc_ipv6_nc_get_l2_addr(l2_addr, &l2_addr_len, entry)); }
static void test_ipv6_nc_get_l2_addr__unreachable(void) { ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; gnrc_ipv6_nc_t *entry = NULL; uint8_t l2_addr[GNRC_IPV6_NC_L2_ADDR_MAX]; uint8_t l2_addr_len = 0; test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ TEST_ASSERT_NOT_NULL((entry = gnrc_ipv6_nc_get(KERNEL_PID_UNDEF, &addr))); entry->flags = (GNRC_IPV6_NC_STATE_INCOMPLETE << GNRC_IPV6_NC_STATE_POS); TEST_ASSERT_EQUAL_INT(KERNEL_PID_UNDEF, gnrc_ipv6_nc_get_l2_addr(l2_addr, &l2_addr_len, entry)); }
kernel_pid_t gnrc_sixlowpan_nd_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len, kernel_pid_t iface, ipv6_addr_t *dst) { ipv6_addr_t *next_hop = NULL; gnrc_ipv6_nc_t *nc_entry = NULL; #ifdef MODULE_FIB kernel_pid_t fib_iface; ipv6_addr_t next_hop_actual; /* FIB copies address into this variable */ /* don't look-up link local addresses in FIB */ if ((next_hop == NULL) && !ipv6_addr_is_link_local(dst)) { size_t next_hop_size = sizeof(ipv6_addr_t); uint32_t next_hop_flags = 0; if ((next_hop == NULL) && (fib_get_next_hop(&gnrc_ipv6_fib_table, &fib_iface, next_hop_actual.u8, &next_hop_size, &next_hop_flags, (uint8_t *)dst, sizeof(ipv6_addr_t), 0) >= 0) && (next_hop_size == sizeof(ipv6_addr_t))) { next_hop = &next_hop_actual; } } #endif #ifdef MODULE_GNRC_SIXLOWPAN_ND_ROUTER /* next hop determination: https://tools.ietf.org/html/rfc6775#section-6.5.4 */ nc_entry = gnrc_ipv6_nc_get(iface, dst); #ifdef MODULE_FIB if ((next_hop != NULL) && (nc_entry == NULL)) { nc_entry = gnrc_ipv6_nc_get(fib_iface, dst); } #endif /* if NCE found */ if (nc_entry != NULL) { gnrc_ipv6_netif_t *ipv6_if = gnrc_ipv6_netif_get(nc_entry->iface); /* and interface is not 6LoWPAN */ if (!((ipv6_if == NULL) || (ipv6_if->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) || /* or entry is registered */ (gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_REGISTERED)) { next_hop = dst; } } #endif /* next hop determination according to: https://tools.ietf.org/html/rfc6775#section-5.6 */ if ((next_hop == NULL) && ipv6_addr_is_link_local(dst)) { /* prefix is "on-link" */ /* multicast is not handled here anyway so we don't need to check that */ next_hop = dst; } else if (next_hop == NULL) { /* prefix is off-link */ next_hop = gnrc_ndp_internal_default_router(); } /* no routers found */ if (next_hop == NULL) { return KERNEL_PID_UNDEF; } /* address resolution of next_hop: https://tools.ietf.org/html/rfc6775#section-5.7 */ if ((nc_entry == NULL) || (next_hop != dst)) { /* get if not gotten from previous check */ nc_entry = gnrc_ipv6_nc_get(iface, next_hop); } /* If a (non-tentative) NCE for this destination exist, we can use even for * link-local addresses. This should be only the case for 6LBRs. */ if ((ipv6_addr_is_link_local(next_hop)) && ((nc_entry == NULL) || (gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_TENTATIVE))) { /* in case of a border router there is no sensible way for address resolution * if the interface is not given */ #ifdef MODULE_GNRC_SIXLOWPAN_ND_BORDER_ROUTER /* if no interface is specified it is impossible to resolve the * link-layer address for a link-local address on a 6LBR */ if (iface == KERNEL_PID_UNDEF) { return KERNEL_PID_UNDEF; } #endif kernel_pid_t ifs[GNRC_NETIF_NUMOF]; size_t ifnum = gnrc_netif_get(ifs); /* we don't need address resolution, the EUI-64 is in next_hop's IID */ *l2addr_len = sizeof(eui64_t); memcpy(l2addr, &next_hop->u8[8], sizeof(eui64_t)); _revert_iid(l2addr); if (iface == KERNEL_PID_UNDEF) { for (unsigned i = 0; i < ifnum; i++) { gnrc_ipv6_netif_t *ipv6_if = gnrc_ipv6_netif_get(ifs[i]); if ((ipv6_if != NULL) && (ipv6_if->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN)) { /* always take the first 6LoWPAN interface we can find */ return ifs[i]; } } } return iface; } if ((gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_TENTATIVE)) { return KERNEL_PID_UNDEF; } else { if (gnrc_ipv6_nc_get_state(nc_entry) == GNRC_IPV6_NC_STATE_STALE) { gnrc_ndp_internal_set_state(nc_entry, GNRC_IPV6_NC_STATE_DELAY); } } return gnrc_ipv6_nc_get_l2_addr(l2addr, l2addr_len, nc_entry); }