static void test_ipv6_nc_add__full(void) { ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; for (int i = 0; i < NG_IPV6_NC_SIZE; i++) { TEST_ASSERT_NOT_NULL(ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, TEST_STRING4, sizeof(TEST_STRING4), 0)); addr.u16[7].u16++; } TEST_ASSERT_NULL(ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, TEST_STRING4, sizeof(TEST_STRING4), 0)); }
static void test_ipv6_nc_add__address_registered(void) { ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; ng_ipv6_nc_t *entry1, *entry2; TEST_ASSERT_NOT_NULL((entry1 = ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, TEST_STRING4, sizeof(TEST_STRING4), 0))); TEST_ASSERT_NOT_NULL((entry2 = ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, TEST_STRING4, sizeof(TEST_STRING4), 0))); TEST_ASSERT(entry1 == entry2); }
static void test_ipv6_nc_add__l2addr_too_long(void) { ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; TEST_ASSERT_NULL(ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, TEST_STRING4, NG_IPV6_NC_L2_ADDR_MAX + TEST_UINT8, 0)); }
static void test_ipv6_nc_add__addr_unspecified(void) { ipv6_addr_t addr = IPV6_ADDR_UNSPECIFIED; TEST_ASSERT_NULL(ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, TEST_STRING4, sizeof(TEST_STRING4), 0)); }
static void test_ipv6_nc_add__iface_KERNEL_PID_UNDEF(void) { ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; TEST_ASSERT_NOT_NULL(ng_ipv6_nc_add(KERNEL_PID_UNDEF, &addr, TEST_STRING4, sizeof(TEST_STRING4), 0)); }
static int _ipv6_nc_add(kernel_pid_t iface, char *ipv6_addr_str, char *l2_addr_str) { ipv6_addr_t ipv6_addr; uint8_t l2_addr[MAX_L2_ADDR_LEN]; size_t l2_addr_len; if (ipv6_addr_from_str(&ipv6_addr, ipv6_addr_str) == NULL) { puts("error: unable to parse IPv6 address."); return 1; } if ((l2_addr_len = ng_netif_addr_from_str(l2_addr, sizeof(l2_addr), l2_addr_str)) == 0) { puts("error: unable to parse link-layer address."); return 1; } if (ng_ipv6_nc_add(iface, &ipv6_addr, l2_addr, l2_addr_len, 0) == NULL) { puts("error: unable to add address to neighbor cache."); return 1; } printf("success: added IPv6 address %s to neighbor cache\n", ipv6_addr_str); return 0; }
static bool _handle_sl2a_opt(kernel_pid_t iface, ng_pktsnip_t *pkt, ng_ipv6_hdr_t *ipv6, uint8_t icmpv6_type, ng_ndp_opt_t *sl2a_opt) { ng_ipv6_nc_t *nc_entry = NULL; uint8_t sl2a_len = 0; uint8_t *sl2a = (uint8_t *)(sl2a_opt + 1); if ((sl2a_opt->len == 0) || ng_ipv6_addr_is_unspecified(&ipv6->src)) { DEBUG("ndp: invalid source link-layer address option received\n"); return false; } while (pkt) { if (pkt->type == NG_NETTYPE_NETIF) { ng_netif_hdr_t *hdr = pkt->data; sl2a_len = hdr->src_l2addr_len; break; } pkt = pkt->next; } if (sl2a_len == 0) { /* in case there was no source address in l2 */ sl2a_len = (sl2a_opt->len / 8) - sizeof(ng_ndp_opt_t); /* ignore all zeroes at the end for length */ for (; sl2a[sl2a_len - 1] == 0x00; sl2a_len--); } DEBUG("ndp: received SL2A (link-layer address: %s)\n", ng_netif_addr_to_str(addr_str, sizeof(addr_str), sl2a, sl2a_len)); switch (icmpv6_type) { case NG_ICMPV6_NBR_SOL: nc_entry = ng_ipv6_nc_get(iface, &ipv6->src); if (nc_entry != NULL) { if ((sl2a_len != nc_entry->l2_addr_len) || (memcmp(sl2a, nc_entry->l2_addr, sl2a_len) != 0)) { /* if entry exists but l2 address differs: set */ nc_entry->l2_addr_len = sl2a_len; memcpy(nc_entry->l2_addr, sl2a, sl2a_len); _set_state(nc_entry, NG_IPV6_NC_STATE_STALE); } } else { ng_ipv6_nc_add(iface, &ipv6->src, sl2a, sl2a_len, NG_IPV6_NC_STATE_STALE); } return true; default: /* wrong encapsulating message: silently discard */ DEBUG("ndp: silently discard sl2a_opt for ICMPv6 message type %" PRIu8 "\n", icmpv6_type); return true; } }
static void test_ipv6_nc_add__address_update_despite_free_entry(void) { ipv6_addr_t default_addr = DEFAULT_TEST_IPV6_ADDR; ipv6_addr_t other_addr = OTHER_TEST_IPV6_ADDR; ng_ipv6_nc_t *entry1, *entry2; TEST_ASSERT_NOT_NULL(ng_ipv6_nc_add(OTHER_TEST_NETIF, &other_addr, TEST_STRING4, sizeof(TEST_STRING4), 0)); TEST_ASSERT_NOT_NULL((entry1 = ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &default_addr, TEST_STRING4, sizeof(TEST_STRING4), 0))); /* create space by removing first entry and see if duplicate is still detected & updated */ ng_ipv6_nc_remove(OTHER_TEST_NETIF, &other_addr); TEST_ASSERT_NOT_NULL((entry2 = ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &default_addr, TEST_STRING4, sizeof(TEST_STRING4), 0))); TEST_ASSERT(entry1 == entry2); }
static void test_ipv6_nc_get_next__2_entries(void) { ipv6_addr_t addr = OTHER_TEST_IPV6_ADDR; ng_ipv6_nc_t *entry = NULL; test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ TEST_ASSERT_NOT_NULL(ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, TEST_STRING8, sizeof(TEST_STRING8) - 1, 0)); TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get_next(NULL))); TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get_next(entry))); TEST_ASSERT_NULL(ng_ipv6_nc_get_next(entry)); }
static void test_ipv6_nc_get_next__holey(void) { ipv6_addr_t addr1 = OTHER_TEST_IPV6_ADDR; ipv6_addr_t addr2 = THIRD_TEST_IPV6_ADDR; ng_ipv6_nc_t *entry = NULL, *exp_entry = NULL; /* adds DEFAULT_TEST_IPV6_ADDR and OTHER_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ test_ipv6_nc_get_next__2_entries(); TEST_ASSERT_NOT_NULL(ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr2, TEST_STRING8, sizeof(TEST_STRING8) - 2, 0)); TEST_ASSERT_NOT_NULL((exp_entry = ng_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr2))); ng_ipv6_nc_remove(DEFAULT_TEST_NETIF, &addr1); TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get_next(NULL))); TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get_next(entry))); TEST_ASSERT(exp_entry == entry); TEST_ASSERT_NULL(ng_ipv6_nc_get_next(entry)); }
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; }
static void test_ipv6_nc_add__address_NULL(void) { TEST_ASSERT_NULL(ng_ipv6_nc_add(DEFAULT_TEST_NETIF, NULL, TEST_STRING4, sizeof(TEST_STRING4), 0)); }