/* * @brief call get next hop with invalid parameters * It is expected to receive -EINVAL on calling get_next_hop() */ static void test_fib_18_get_next_hop_invalid_parameters(void) { size_t add_buf_size = 16; /* includes space for terminating \0 */ char addr_dst[] = "Test address 13"; char addr_expect[] = "Test address 02"; kernel_pid_t iface_id = KERNEL_PID_UNDEF; uint32_t next_hop_flags = 0; char addr_nxt[add_buf_size]; size_t entries = 20; _fill_FIB_multiple(entries, 11); int ret = fib_get_next_hop(&test_fib_table, NULL, NULL, NULL, NULL,NULL, add_buf_size - 1, 0x13); TEST_ASSERT_EQUAL_INT(-EINVAL, ret); ret = fib_get_next_hop(&test_fib_table, &iface_id, (uint8_t *)addr_nxt, &add_buf_size, &next_hop_flags, (uint8_t *)addr_dst, add_buf_size - 1, 0x13); TEST_ASSERT_EQUAL_INT(0, ret); ret = strncmp(addr_expect, addr_nxt, add_buf_size); TEST_ASSERT_EQUAL_INT(0, ret); #if (TEST_FIB_SHOW_OUTPUT == 1) fib_print_fib_table(&test_fib_table); puts(""); universal_address_print_table(); puts(""); #endif fib_deinit(&test_fib_table); }
/* * @brief get next hop for known destination but unsufficient size for the output * It is expected to get no next hop and receive -ENOBUFS */ static void test_fib_13_get_next_hop_fail_on_buffer_size(void) { size_t add_buf_size = 16; /* includes space for terminating \0 */ char addr_dst[] = "Test address 13"; kernel_pid_t iface_id = KERNEL_PID_UNDEF; uint32_t next_hop_flags = 0; size_t add_buf_size_nxt = 12; char addr_nxt[add_buf_size]; size_t entries = 20; _fill_FIB_multiple(entries, 11); TEST_ASSERT_EQUAL_INT(20, fib_get_num_used_entries()); TEST_ASSERT_EQUAL_INT(20, universal_address_get_num_used_entries()); int ret = fib_get_next_hop(&iface_id, (uint8_t *)addr_nxt, &add_buf_size_nxt, &next_hop_flags, (uint8_t *)addr_dst, add_buf_size - 1, 0x13); TEST_ASSERT_EQUAL_INT(-ENOBUFS, ret); TEST_ASSERT_EQUAL_INT(add_buf_size_nxt, add_buf_size - 1); #if (TEST_FIB_SHOW_OUTPUT == 1) fib_print_fib_table(); puts(""); universal_address_print_table(); puts(""); #endif fib_deinit(); }
kernel_pid_t ng_ndp_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len, kernel_pid_t iface, ng_ipv6_addr_t *dst, ng_pktsnip_t *pkt) { ng_ipv6_addr_t *next_hop_ip = NULL, *prefix = NULL; #ifdef MODULE_NG_IPV6_EXT_RH next_hop_ip = ng_ipv6_ext_rh_next_hop(hdr); #endif #ifdef MODULE_FIB size_t next_hop_size = sizeof(ng_ipv6_addr_t); uint32_t next_hop_flags = 0; ng_ipv6_addr_t next_hop_actual; /* FIB copies address into this variable */ if ((next_hop_ip == NULL) && (fib_get_next_hop(&iface, next_hop_actual.u8, &next_hop_size, &next_hop_flags, (uint8_t *)dst, sizeof(ng_ipv6_addr_t), 0) >= 0) && (next_hop_size == sizeof(ng_ipv6_addr_t))) { next_hop_ip = &next_hop_actual; } #endif if (next_hop_ip == NULL) { /* no route to host */ if (iface == KERNEL_PID_UNDEF) { /* ng_ipv6_netif_t doubles as prefix list */ iface = ng_ipv6_netif_find_by_prefix(&prefix, dst); } else { /* ng_ipv6_netif_t doubles as prefix list */ prefix = ng_ipv6_netif_match_prefix(iface, dst); } if ((prefix != NULL) && /* prefix is on-link */ (ng_ipv6_netif_addr_get(prefix)->flags & NG_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK)) { next_hop_ip = dst; #ifdef MODULE_FIB /* We don't care if FIB is full, this is just for efficiency * for later sends */ fib_add_entry(iface, (uint8_t *)dst, sizeof(ng_ipv6_addr_t), 0, (uint8_t *)next_hop_ip, sizeof(ng_ipv6_addr_t), 0, FIB_LIFETIME_NO_EXPIRE); #endif } } if (next_hop_ip == NULL) { next_hop_ip = _default_router(); #ifdef MODULE_FIB /* We don't care if FIB is full, this is just for efficiency for later * sends */ fib_add_entry(iface, (uint8_t *)dst, sizeof(ng_ipv6_addr_t), 0, (uint8_t *)next_hop_ip, sizeof(ng_ipv6_addr_t), 0, FIB_LIFETIME_NO_EXPIRE); #endif } if (next_hop_ip != NULL) { ng_ipv6_nc_t *nc_entry = ng_ipv6_nc_get(iface, next_hop_ip); if ((nc_entry != NULL) && ng_ipv6_nc_is_reachable(nc_entry)) { DEBUG("ndp: found reachable neighbor (%s => ", ng_ipv6_addr_to_str(addr_str, &nc_entry->ipv6_addr, sizeof(addr_str))); DEBUG("%s)\n", ng_netif_addr_to_str(addr_str, sizeof(addr_str), nc_entry->l2_addr, nc_entry->l2_addr_len)); if (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_STALE) { _set_state(nc_entry, NG_IPV6_NC_STATE_DELAY); } memcpy(l2addr, nc_entry->l2_addr, nc_entry->l2_addr_len); *l2addr_len = nc_entry->l2_addr_len; /* TODO: unreachability check */ return nc_entry->iface; } else if (nc_entry == NULL) { ng_pktqueue_t *pkt_node; ng_ipv6_addr_t dst_sol; nc_entry = ng_ipv6_nc_add(iface, next_hop_ip, NULL, 0, NG_IPV6_NC_STATE_INCOMPLETE << NG_IPV6_NC_STATE_POS); if (nc_entry == NULL) { DEBUG("ndp: could not create neighbor cache entry\n"); return KERNEL_PID_UNDEF; } pkt_node = _alloc_pkt_node(pkt); if (pkt_node == NULL) { DEBUG("ndp: could not add packet to packet queue\n"); } else { /* prevent packet from being released by IPv6 */ ng_pktbuf_hold(pkt_node->pkt, 1); ng_pktqueue_add(&nc_entry->pkts, pkt_node); } /* address resolution */ ng_ipv6_addr_set_solicited_nodes(&dst_sol, next_hop_ip); if (iface == KERNEL_PID_UNDEF) { timex_t t = { 0, NG_NDP_RETRANS_TIMER }; kernel_pid_t ifs[NG_NETIF_NUMOF]; size_t ifnum = ng_netif_get(ifs); for (size_t i = 0; i < ifnum; i++) { _send_nbr_sol(ifs[i], next_hop_ip, &dst_sol); } vtimer_remove(&nc_entry->nbr_sol_timer); vtimer_set_msg(&nc_entry->nbr_sol_timer, t, ng_ipv6_pid, NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry); } else { ng_ipv6_netif_t *ipv6_iface = ng_ipv6_netif_get(iface); _send_nbr_sol(iface, next_hop_ip, &dst_sol); mutex_lock(&ipv6_iface->mutex); vtimer_remove(&nc_entry->nbr_sol_timer); vtimer_set_msg(&nc_entry->nbr_sol_timer, ipv6_iface->retrans_timer, ng_ipv6_pid, NG_NDP_MSG_NBR_SOL_RETRANS, nc_entry); mutex_unlock(&ipv6_iface->mutex); } } } return KERNEL_PID_UNDEF; }
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_GNRC_IPV6_EXT_RH ipv6_hdr_t *hdr; gnrc_pktsnip_t *ipv6; LL_SEARCH_SCALAR(pkt, ipv6, type, GNRC_NETTYPE_IPV6); assert(ipv6); hdr = ipv6->data; next_hop = ipv6_ext_rh_next_hop(hdr); #endif #ifdef MODULE_FIB 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, &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); /* 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->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(); } /* 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 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)) { /* 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 ((nc_entry == NULL) || (!gnrc_ipv6_nc_is_reachable(nc_entry)) || (gnrc_ipv6_nc_get_type(nc_entry) == GNRC_IPV6_NC_TYPE_TENTATIVE)) { return KERNEL_PID_UNDEF; } else { if (nc_entry->l2_addr_len > 0) { memcpy(l2addr, nc_entry->l2_addr, nc_entry->l2_addr_len); } *l2addr_len = nc_entry->l2_addr_len; } return nc_entry->iface; }
/* * @brief testing prefix with bits */ static void test_fib_16_prefix_match(void) { size_t add_buf_size = 16; char addr_dst[add_buf_size]; char addr_nxt[add_buf_size]; char addr_lookup[add_buf_size]; kernel_pid_t iface_id = KERNEL_PID_UNDEF; uint32_t next_hop_flags = 0; memset(addr_dst, 0, add_buf_size); memset(addr_nxt, 0, add_buf_size); memset(addr_lookup, 0, add_buf_size); snprintf(addr_dst, add_buf_size, "Test address 1X"); snprintf(addr_nxt, add_buf_size, "Test address 99"); snprintf(addr_lookup, add_buf_size, "Test address 1X"); /* now we change the last byte of addr_dst to have defined trailing 0 bits */ /* test success */ addr_dst[14] = (char)0x80; /* 1000 0000 */ addr_lookup[14] = (char)0x87; /* 1000 0111 */ fib_add_entry(42, (uint8_t *)addr_dst, add_buf_size - 1, 0x123, (uint8_t *)addr_nxt, add_buf_size - 1, 0x23, 100000); addr_dst[14] = (char)0x3c; /* 0011 1100 */ fib_add_entry(42, (uint8_t *)addr_dst, add_buf_size - 1, 0x123, (uint8_t *)addr_nxt, add_buf_size - 1, 0x23, 100000); memset(addr_nxt, 0, add_buf_size); int ret = fib_get_next_hop(&iface_id, (uint8_t *)addr_nxt, &add_buf_size, &next_hop_flags, (uint8_t *)addr_lookup, add_buf_size - 1, 0x123); TEST_ASSERT_EQUAL_INT(0, ret); /* test fail */ addr_dst[14] = (char)0x3c; /* 0011 1100 */ addr_lookup[14] = (char)0x34; /* 0011 0100 */ add_buf_size = 16; fib_add_entry(42, (uint8_t *)addr_dst, add_buf_size - 1, 0x123, (uint8_t *)addr_nxt, add_buf_size - 1, 0x23, 100000); memset(addr_nxt, 0, add_buf_size); ret = fib_get_next_hop(&iface_id, (uint8_t *)addr_nxt, &add_buf_size, &next_hop_flags, (uint8_t *)addr_lookup, add_buf_size - 1, 0x123); TEST_ASSERT_EQUAL_INT(-EHOSTUNREACH, ret); /* test success (again) by adjusting the lsb */ addr_lookup[14] = (char)0x3e; /* 0011 1110 */ add_buf_size = 16; memset(addr_nxt, 0, add_buf_size); ret = fib_get_next_hop(&iface_id, (uint8_t *)addr_nxt, &add_buf_size, &next_hop_flags, (uint8_t *)addr_lookup, add_buf_size - 1, 0x123); TEST_ASSERT_EQUAL_INT(0, ret); #if (TEST_FIB_SHOW_OUTPUT == 1) fib_print_fib_table(); puts(""); universal_address_print_table(); puts(""); #endif fib_deinit(); }
/* * @brief testing prefix and exact match * It is expected receive 23 for addr123 as exact match and * 12 for addr124 */ static void test_fib_14_exact_and_prefix_match(void) { size_t add_buf_size = 16; char addr_dst[add_buf_size]; char addr_nxt[add_buf_size]; kernel_pid_t iface_id = KERNEL_PID_UNDEF; uint32_t next_hop_flags = 0; char addr_lookup[add_buf_size]; memset(addr_dst, 0, add_buf_size); memset(addr_nxt, 0, add_buf_size); snprintf(addr_dst, add_buf_size, "Test addr12"); snprintf(addr_nxt, add_buf_size, "Test address %02d", 12); fib_add_entry(42, (uint8_t *)addr_dst, add_buf_size - 1, 0x12, (uint8_t *)addr_nxt, add_buf_size - 1, 0x12, 100000); snprintf(addr_dst, add_buf_size, "Test addr123"); snprintf(addr_nxt, add_buf_size, "Test address %02d", 23); fib_add_entry(42, (uint8_t *)addr_dst, add_buf_size - 1, 0x123, (uint8_t *)addr_nxt, add_buf_size - 1, 0x23, 100000); snprintf(addr_dst, add_buf_size, "Test addr1234"); snprintf(addr_nxt, add_buf_size, "Test address %02d", 34); fib_add_entry(42, (uint8_t *)addr_dst, add_buf_size - 1, 0x1234, (uint8_t *)addr_nxt, add_buf_size - 1, 0x34, 100000); memset(addr_lookup, 0, add_buf_size); /* exact match */ snprintf(addr_lookup, add_buf_size, "Test addr123"); int ret = fib_get_next_hop(&iface_id, (uint8_t *)addr_nxt, &add_buf_size, &next_hop_flags, (uint8_t *)addr_lookup, add_buf_size - 1, 0x123); TEST_ASSERT_EQUAL_INT(0, ret); add_buf_size = 16; char addr_expect_01[] = "Test address 23"; ret = strncmp(addr_expect_01, addr_nxt, add_buf_size - 1); TEST_ASSERT_EQUAL_INT(0, ret); /* prefix match */ add_buf_size = 16; memset(addr_nxt, 0, add_buf_size); memset(addr_lookup, 0, add_buf_size); /* cppcheck: addr_lookup is only passed but not required to be read, * since we test prefix matching */ /* cppcheck-suppress redundantCopy */ snprintf(addr_lookup, add_buf_size, "Test addr124"); ret = fib_get_next_hop(&iface_id, (uint8_t *)addr_nxt, &add_buf_size, &next_hop_flags, (uint8_t *)addr_lookup, add_buf_size - 1, 0x124); TEST_ASSERT_EQUAL_INT(0, ret); add_buf_size = 16; char addr_expect_02[] = "Test address 12"; ret = strncmp(addr_expect_02, addr_nxt, add_buf_size); TEST_ASSERT_EQUAL_INT(0, ret); #if (TEST_FIB_SHOW_OUTPUT == 1) fib_print_fib_table(); puts(""); universal_address_print_table(); puts(""); #endif fib_deinit(); }
/* * @brief testing prefix entry changing */ static void test_fib_20_replace_prefix(void) { size_t add_buf_size = 16; char addr_dst[add_buf_size]; char addr_nxt_hop[add_buf_size]; char addr_nxt[add_buf_size]; char addr_lookup[add_buf_size]; kernel_pid_t iface_id = KERNEL_PID_UNDEF; uint32_t next_hop_flags = 0; memset(addr_dst, 0, add_buf_size); memset(addr_nxt, 0, add_buf_size); memset(addr_nxt_hop, 0, add_buf_size); memset(addr_lookup, 0, add_buf_size); /* set the bytes to 0x01..0x10 of the next-hop */ for(size_t i = 0; i < add_buf_size; i++) { addr_nxt[i] = i+1; } /* set the bytes to 0x01..0x08 of the destination prefix */ for(size_t i = 0; i < add_buf_size/2; i++) { addr_dst[i] = i+1; } /* set the bytes to 0x01..0x0e of the lookup address */ for(size_t i = 0; i < 14; i++) { addr_lookup[i] = i+1; } /* add a prefix entry */ fib_add_entry(&test_fib_table, 42, (uint8_t *)addr_dst, add_buf_size, 0x123, (uint8_t *)addr_nxt, add_buf_size, 0x23, 100000); /* check if it matches */ int ret = fib_get_next_hop(&test_fib_table, &iface_id, (uint8_t *)addr_nxt_hop, &add_buf_size, &next_hop_flags, (uint8_t *)addr_lookup, add_buf_size, 0x123); TEST_ASSERT_EQUAL_INT(0, ret); TEST_ASSERT_EQUAL_INT(0, memcmp(addr_nxt, addr_nxt_hop, add_buf_size)); fib_remove_entry(&test_fib_table, (uint8_t *)addr_dst, add_buf_size); memset(addr_nxt_hop, 0, add_buf_size); /* set the bytes to 0x02..0x11 of the new next-hop */ for(size_t i = 0; i < add_buf_size; ++i) { addr_nxt[i] = i+2; } /* set the bytes to 0x01..0x0d of the new destination prefix */ for(size_t i = 0; i < 13; i++) { addr_dst[i] = i+1; } /* change the prefix entry */ fib_add_entry(&test_fib_table, 42, (uint8_t *)addr_dst, add_buf_size, 0x123, (uint8_t *)addr_nxt, add_buf_size, 0x24, 100000); /* and check again if it matches */ ret = fib_get_next_hop(&test_fib_table, &iface_id, (uint8_t *)addr_nxt_hop, &add_buf_size, &next_hop_flags, (uint8_t *)addr_lookup, add_buf_size, 0x123); TEST_ASSERT_EQUAL_INT(0, ret); TEST_ASSERT_EQUAL_INT(0, memcmp(addr_nxt, addr_nxt_hop, add_buf_size)); #if (TEST_FIB_SHOW_OUTPUT == 1) fib_print_fib_table(&test_fib_table); puts(""); universal_address_print_table(); puts(""); #endif fib_deinit(&test_fib_table); }
/* * @brief testing default gateway address */ static void test_fib_19_default_gateway(void) { size_t add_buf_size = 16; char addr_dst[add_buf_size]; char addr_nxt_hop[add_buf_size]; char addr_nxt[add_buf_size]; char addr_lookup[add_buf_size]; kernel_pid_t iface_id = KERNEL_PID_UNDEF; uint32_t next_hop_flags = 0; memset(addr_dst, 0, add_buf_size); memset(addr_nxt, 0, add_buf_size); memset(addr_nxt_hop, 0, add_buf_size); memset(addr_lookup, 0, add_buf_size); snprintf(addr_lookup, add_buf_size, "Some address X1"); /* set the bytes to 0x01..0x10 of the next-hop */ for(size_t i = 0; i < add_buf_size; i++) { addr_nxt[i] = i+1; } /* add a default gateway entry */ fib_add_entry(&test_fib_table, 42, (uint8_t *)addr_dst, add_buf_size, 0x123, (uint8_t *)addr_nxt, add_buf_size, 0x23, 100000); /* check if it matches all */ int ret = fib_get_next_hop(&test_fib_table, &iface_id, (uint8_t *)addr_nxt_hop, &add_buf_size, &next_hop_flags, (uint8_t *)addr_lookup, add_buf_size, 0x123); TEST_ASSERT_EQUAL_INT(0, ret); TEST_ASSERT_EQUAL_INT(0, memcmp(addr_nxt, addr_nxt_hop, add_buf_size)); memset(addr_nxt_hop, 0, add_buf_size); /* set the bytes to 0x02..0x11 of the new next-hop for the default gateway */ for(size_t i = 0; i < add_buf_size; ++i) { addr_nxt[i] = i+2; } /* change the default gateway entry */ fib_add_entry(&test_fib_table, 42, (uint8_t *)addr_dst, add_buf_size, 0x123, (uint8_t *)addr_nxt, add_buf_size, 0x24, 100000); /* and check again if it matches all */ ret = fib_get_next_hop(&test_fib_table, &iface_id, (uint8_t *)addr_nxt_hop, &add_buf_size, &next_hop_flags, (uint8_t *)addr_lookup, add_buf_size, 0x123); TEST_ASSERT_EQUAL_INT(0, ret); TEST_ASSERT_EQUAL_INT(0, memcmp(addr_nxt, addr_nxt_hop, add_buf_size)); #if (TEST_FIB_SHOW_OUTPUT == 1) fib_print_fib_table(&test_fib_table); puts(""); universal_address_print_table(); puts(""); #endif fib_deinit(&test_fib_table); }