kernel_pid_t ng_ipv6_netif_find_by_addr(ng_ipv6_addr_t **out, const ng_ipv6_addr_t *addr) { for (int i = 0; i < NG_NETIF_NUMOF; i++) { if (out != NULL) { *out = ng_ipv6_netif_find_addr(ipv6_ifs[i].pid, addr); if (*out != NULL) { DEBUG("ipv6 netif: Found %s on interface %" PRIkernel_pid "\n", ng_ipv6_addr_to_str(addr_str, *out, sizeof(addr_str)), ipv6_ifs[i].pid); return ipv6_ifs[i].pid; } } else { if (ng_ipv6_netif_find_addr(ipv6_ifs[i].pid, addr) != NULL) { DEBUG("ipv6 netif: Found %s on interface %" PRIkernel_pid "\n", ng_ipv6_addr_to_str(addr_str, *out, sizeof(addr_str)), ipv6_ifs[i].pid); return ipv6_ifs[i].pid; } } } if (out != NULL) { *out = NULL; } return KERNEL_PID_UNDEF; }
void ng_ndp_retrans_nbr_sol(ng_ipv6_nc_t *nc_entry) { if ((ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_INCOMPLETE) || (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_PROBE)) { if (nc_entry->probes_remaining > 1) { ng_ipv6_addr_t dst; DEBUG("ndp: Retransmit neighbor solicitation for %s\n", ng_ipv6_addr_to_str(addr_str, &nc_entry->ipv6_addr, sizeof(addr_str))); /* retransmit neighbor solicatation */ if (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_INCOMPLETE) { ng_ipv6_addr_set_solicited_nodes(&dst, &nc_entry->ipv6_addr); } else { dst.u64[0] = nc_entry->ipv6_addr.u64[0]; dst.u64[1] = nc_entry->ipv6_addr.u64[1]; } nc_entry->probes_remaining--; if (nc_entry->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], &nc_entry->ipv6_addr, &dst); } 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(nc_entry->iface); _send_nbr_sol(nc_entry->iface, &nc_entry->ipv6_addr, &dst); 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); } } else if (nc_entry->probes_remaining <= 1) { DEBUG("ndp: Remove nc entry %s for interface %" PRIkernel_pid "\n", ng_ipv6_addr_to_str(addr_str, &nc_entry->ipv6_addr, sizeof(addr_str)), nc_entry->iface); #ifdef MODULE_FIB fib_remove_entry((uint8_t *) & (nc_entry->ipv6_addr), sizeof(ng_ipv6_addr_t)); #endif ng_ipv6_nc_remove(nc_entry->iface, &nc_entry->ipv6_addr); } } }
ng_pktsnip_t *ng_ipv6_hdr_build(ng_pktsnip_t *payload, uint8_t *src, uint8_t src_len, uint8_t *dst, uint8_t dst_len) { ng_pktsnip_t *ipv6; ng_ipv6_hdr_t *hdr; if (((src_len != 0) && (src_len != sizeof(ng_ipv6_addr_t))) || ((dst_len != 0) && (dst_len != sizeof(ng_ipv6_addr_t)))) { DEBUG("ipv6_hdr: Address length was not 0 or %zu byte.\n", sizeof(ng_ipv6_addr_t)); return NULL; } ipv6 = ng_pktbuf_add(payload, NULL, sizeof(ng_ipv6_hdr_t), HDR_NETTYPE); if (ipv6 == NULL) { DEBUG("ipv6_hdr: no space left in packet buffer\n"); return NULL; } hdr = (ng_ipv6_hdr_t *)ipv6->data; if ((src != NULL) && (src_len != 0)) { #ifdef MODULE_NG_IPV6_ADDR DEBUG("ipv6_hdr: set packet source to %s\n", ng_ipv6_addr_to_str(addr_str, (ng_ipv6_addr_t *)src, sizeof(addr_str))); #endif memcpy(&hdr->src, src, src_len); } else { DEBUG("ipv6_hdr: set packet source to ::\n"); ng_ipv6_addr_set_unspecified(&hdr->src); } memset(&hdr->dst + dst_len, 0, sizeof(ng_ipv6_addr_t) - dst_len); if ((dst != NULL) && (dst_len != 0)) { #ifdef MODULE_NG_IPV6_ADDR DEBUG("ipv6_hdr: set packet destination to %s\n", ng_ipv6_addr_to_str(addr_str, (ng_ipv6_addr_t *)dst, sizeof(addr_str))); #endif memcpy(&hdr->dst, dst, dst_len); } else { DEBUG("ipv6_hdr: set packet destination to ::1\n"); ng_ipv6_addr_set_loopback(&hdr->dst); } hdr->v_tc_fl = byteorder_htonl(0x60000000); /* set version, tc and fl in one go*/ hdr->nh = PROTNUM_RESERVED; hdr->hl = 0; return ipv6; }
static ng_ipv6_addr_t *_add_addr_to_entry(ng_ipv6_netif_t *entry, const ng_ipv6_addr_t *addr, uint8_t prefix_len, uint8_t flags) { ng_ipv6_netif_addr_t *tmp_addr = NULL; for (int i = 0; i < NG_IPV6_NETIF_ADDR_NUMOF; i++) { if (ng_ipv6_addr_equal(&(entry->addrs[i].addr), addr)) { return &(entry->addrs[i].addr); } if (ng_ipv6_addr_is_unspecified(&(entry->addrs[i].addr)) && !tmp_addr) { tmp_addr = &(entry->addrs[i]); } } if (!tmp_addr) { DEBUG("ipv6 netif: couldn't add %s/%" PRIu8 " to interface %" PRIkernel_pid "\n: No space left.", ng_ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)), prefix_len, entry->pid); return NULL; } memcpy(&(tmp_addr->addr), addr, sizeof(ng_ipv6_addr_t)); DEBUG("ipv6 netif: Added %s/%" PRIu8 " to interface %" PRIkernel_pid "\n", ng_ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)), prefix_len, entry->pid); tmp_addr->prefix_len = prefix_len; tmp_addr->flags = flags; if (ng_ipv6_addr_is_multicast(addr)) { tmp_addr->flags |= NG_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST; } else { ng_ipv6_addr_t sol_node; if (!ng_ipv6_addr_is_link_local(addr)) { /* add also corresponding link-local address */ ng_ipv6_addr_t ll_addr; ll_addr.u64[1] = addr->u64[1]; ng_ipv6_addr_set_link_local_prefix(&ll_addr); _add_addr_to_entry(entry, &ll_addr, 64, flags | NG_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK); } else { tmp_addr->flags |= NG_IPV6_NETIF_ADDR_FLAGS_NDP_ON_LINK; } ng_ipv6_addr_set_solicited_nodes(&sol_node, addr); _add_addr_to_entry(entry, &sol_node, NG_IPV6_ADDR_BIT_LEN, 0); } return &(tmp_addr->addr); }
static uint8_t _find_by_prefix_unsafe(ng_ipv6_addr_t **res, ng_ipv6_netif_t *iface, const ng_ipv6_addr_t *addr, bool only_unicast) { uint8_t best_match = 0; for (int i = 0; i < NG_IPV6_NETIF_ADDR_NUMOF; i++) { uint8_t match; if ((only_unicast && ng_ipv6_netif_addr_is_non_unicast(&(iface->addrs[i].addr))) || ng_ipv6_addr_is_unspecified(&(iface->addrs[i].addr))) { continue; } match = ng_ipv6_addr_match_prefix(&(iface->addrs[i].addr), addr); if (only_unicast && !ng_ipv6_addr_is_multicast(addr) && (match < iface->addrs[i].prefix_len)) { /* match but not of same subnet */ continue; } if (match > best_match) { if (res != NULL) { *res = &(iface->addrs[i].addr); } best_match = match; } } #if ENABLE_DEBUG if (*res != NULL) { DEBUG("ipv6 netif: Found %s on interface %" PRIkernel_pid " matching ", ng_ipv6_addr_to_str(addr_str, *res, sizeof(addr_str)), iface->pid); DEBUG("%s by %" PRIu8 " bits (used as source address = %s)\n", ng_ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)), best_match, (only_unicast) ? "true" : "false"); } else { DEBUG("ipv6 netif: Did not found any address on interface %" PRIkernel_pid " matching %s (used as source address = %s)\n", iface->pid, ng_ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)), (only_unicast) ? "true" : "false"); } #endif return best_match; }
static void test_ipv6_addr_to_str__success3(void) { ng_ipv6_addr_t a = NG_IPV6_ADDR_UNSPECIFIED; char result[sizeof("::")]; TEST_ASSERT_EQUAL_STRING("::", ng_ipv6_addr_to_str(result, &a, sizeof(result))); }
static int _add_addr_to_entry(ng_ipv6_netif_t *entry, const ng_ipv6_addr_t *addr, uint8_t prefix_len, bool anycast) { for (int i = 0; i < NG_IPV6_NETIF_ADDR_NUMOF; i++) { if (ng_ipv6_addr_equal(&(entry->addrs[i].addr), addr)) { return 0; } if (ng_ipv6_addr_is_unspecified(&(entry->addrs[i].addr))) { memcpy(&(entry->addrs[i].addr), addr, sizeof(ng_ipv6_addr_t)); DEBUG("Added %s/%" PRIu8 " to interface %" PRIkernel_pid "\n", ng_ipv6_addr_to_str(&(entry->addrs[i].addr), addr, sizeof(addr_str)), prefix_len, entry->pid); if (anycast || ng_ipv6_addr_is_multicast(addr)) { if (ng_ipv6_addr_is_multicast(addr)) { entry->addrs[i].prefix_len = NG_IPV6_ADDR_BIT_LEN; } entry->addrs[i].flags = NG_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST; } else { entry->addrs[i].prefix_len = prefix_len; entry->addrs[i].flags = NG_IPV6_NETIF_ADDR_FLAGS_UNICAST; } return 0; } } return -ENOMEM; }
static void test_ipv6_addr_to_str__success4(void) { ng_ipv6_addr_t a = NG_IPV6_ADDR_LOOPBACK; char result[sizeof("::1")]; TEST_ASSERT_EQUAL_STRING("::1", ng_ipv6_addr_to_str(result, &a, sizeof(result))); }
kernel_pid_t ng_ipv6_netif_find_by_prefix(ng_ipv6_addr_t **out, const ng_ipv6_addr_t *prefix) { uint8_t best_match = 0; ng_ipv6_addr_t *tmp_res = NULL; kernel_pid_t res = KERNEL_PID_UNDEF; for (int i = 0; i < NG_NETIF_NUMOF; i++) { uint8_t match; mutex_lock(&(ipv6_ifs[i].mutex)); match = _find_by_prefix_unsafe(&tmp_res, ipv6_ifs + i, prefix, false); if (match > best_match) { if (out != NULL) { *out = tmp_res; } res = ipv6_ifs[i].pid; best_match = match; } mutex_unlock(&(ipv6_ifs[i].mutex)); } #if ENABLE_DEBUG if (res != KERNEL_PID_UNDEF) { DEBUG("Found %s on interface %" PRIkernel_pid " globally matching ", ng_ipv6_addr_to_str(addr_str, *out, sizeof(addr_str)), res); DEBUG("%s by %" PRIu8 " bits\n", ng_ipv6_addr_to_str(addr_str, prefix, sizeof(addr_str)), best_match); } else { DEBUG("Did not found any address globally matching %s\n", ng_ipv6_addr_to_str(addr_str, prefix, sizeof(addr_str))); } #endif return res; }
static void test_ipv6_addr_to_str__string_too_short(void) { ng_ipv6_addr_t a = { { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f } }; char result[1]; TEST_ASSERT_NULL(ng_ipv6_addr_to_str(result, &a, sizeof(result))); }
static void _dump_ipv6_hdr(ng_ipv6_hdr_t *hdr) { char addr_str[NG_IPV6_ADDR_MAX_STR_LEN]; if (ng_ipv6_hdr_is_ipv6_hdr(hdr)) { printf("illegal version field: %" PRIu8 "\n", ng_ipv6_hdr_get_version(hdr)); } printf("traffic class: 0x%02" PRIx8 " (ECN: 0x%" PRIx8 ", DSCP: 0x%02" PRIx8 ")\n", ng_ipv6_hdr_get_tc(hdr), ng_ipv6_hdr_get_tc_ecn(hdr), ng_ipv6_hdr_get_tc_dscp(hdr)); printf("flow label: 0x%05" PRIx32 "\n", ng_ipv6_hdr_get_fl(hdr)); printf("length: %" PRIu16 " next header: %" PRIu8 " hop limit: %" PRIu8 "\n", byteorder_ntohs(hdr->len), hdr->nh, hdr->hl); printf("source address: %s\n", ng_ipv6_addr_to_str(addr_str, &hdr->src, sizeof(addr_str))); printf("destination address: %s\n", ng_ipv6_addr_to_str(addr_str, &hdr->dst, sizeof(addr_str))); }
static void test_ipv6_addr_to_str__success2(void) { ng_ipv6_addr_t a = { { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff } }; char result[NG_IPV6_ADDR_MAX_STR_LEN]; TEST_ASSERT_EQUAL_STRING("fe80::f8f9:fafb:fcfd:feff", ng_ipv6_addr_to_str(result, &a, sizeof(result))); }
static void test_ipv6_addr_to_str__success(void) { ng_ipv6_addr_t a = { { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f } }; char result[NG_IPV6_ADDR_MAX_STR_LEN]; TEST_ASSERT_EQUAL_STRING("1:203:405:607:809:a0b:c0d:e0f", ng_ipv6_addr_to_str(result, &a, sizeof(result))); }
static void test_ipv6_addr_to_str__success5(void) { ng_ipv6_addr_t a = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 192, 168, 0, 1 } }; char result[NG_IPV6_ADDR_MAX_STR_LEN]; TEST_ASSERT_EQUAL_STRING("::ffff:192.168.0.1", ng_ipv6_addr_to_str(result, &a, sizeof(result))); }
static void _remove_addr_from_entry(ng_ipv6_netif_t *entry, ng_ipv6_addr_t *addr) { mutex_lock(&entry->mutex); for (int i = 0; i < NG_IPV6_NETIF_ADDR_NUMOF; i++) { if (ng_ipv6_addr_equal(&(entry->addrs[i].addr), addr)) { DEBUG("ipv6 netif: Remove %s to interface %" PRIkernel_pid "\n", ng_ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)), entry->pid); ng_ipv6_addr_set_unspecified(&(entry->addrs[i].addr)); entry->addrs[i].flags = 0; mutex_unlock(&entry->mutex); return; } } mutex_unlock(&entry->mutex); }
int main(void) { shell_t shell; const char *disco_addr = DISCO_ADDR; port[0] = (uint8_t)DISCO_PORT; port[1] = (uint8_t)(DISCO_PORT >> 8); ng_ipv6_addr_from_str(&addr, disco_addr); char buf[100]; ng_ipv6_addr_to_str(buf, &addr, 100); printf("got address: %s\n", buf); set_chan(DISCO_CHANNEL); shell_init(&shell, shell_commands, STDIO_RX_BUFSIZE, getchar, putchar); shell_run(&shell); return 0; }
ng_ipv6_addr_t *ng_ipv6_netif_find_addr(kernel_pid_t pid, const ng_ipv6_addr_t *addr) { ng_ipv6_netif_t *entry = ng_ipv6_netif_get(pid); if (entry == NULL) { return NULL; } mutex_lock(&entry->mutex); for (int i = 0; i < NG_IPV6_NETIF_ADDR_NUMOF; i++) { if (ng_ipv6_addr_equal(&(entry->addrs[i].addr), addr)) { mutex_unlock(&entry->mutex); DEBUG("ipv6 netif: Found %s on interface %" PRIkernel_pid "\n", ng_ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)), pid); return &(entry->addrs[i].addr); } } mutex_unlock(&entry->mutex); return NULL; }
void ng_ipv6_netif_remove_addr(kernel_pid_t pid, ng_ipv6_addr_t *addr) { ng_ipv6_netif_t *entry = ng_ipv6_netif_get(pid); if (entry == NULL) { return; } mutex_lock(&entry->mutex); for (int i = 0; i < NG_IPV6_NETIF_ADDR_NUMOF; i++) { if (ng_ipv6_addr_equal(&(entry->addrs[i].addr), addr)) { DEBUG("Remove %s to interface %" PRIkernel_pid "\n", ng_ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)), pid); ng_ipv6_addr_set_unspecified(&(entry->addrs[i].addr)); entry->addrs[i].flags = 0; mutex_unlock(&entry->mutex); return; } } mutex_unlock(&entry->mutex); }
void ng_ndp_nbr_adv_handle(kernel_pid_t iface, ng_pktsnip_t *pkt, ng_ipv6_hdr_t *ipv6, ng_ndp_nbr_adv_t *nbr_adv, size_t icmpv6_size) { uint16_t opt_offset = 0; uint8_t *buf = ((uint8_t *)nbr_adv) + sizeof(ng_ndp_nbr_adv_t); int l2tgt_len = 0; uint8_t l2tgt[NG_IPV6_NC_L2_ADDR_MAX]; int sicmpv6_size = (int)icmpv6_size; ng_ipv6_nc_t *nc_entry = ng_ipv6_nc_get(iface, &nbr_adv->tgt); ng_pktsnip_t *netif; ng_netif_hdr_t *netif_hdr = NULL; DEBUG("ndp: received neighbor advertisement (src: %s, ", ng_ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str))); DEBUG("dst: %s, ", ng_ipv6_addr_to_str(addr_str, &ipv6->dst, sizeof(addr_str))); DEBUG("tgt: %s)\n", ng_ipv6_addr_to_str(addr_str, &nbr_adv->tgt, sizeof(addr_str))); /* check validity */ if ((ipv6->hl != 255) || (nbr_adv->code != 0) || (icmpv6_size < sizeof(ng_ndp_nbr_adv_t)) || ng_ipv6_addr_is_multicast(&nbr_adv->tgt)) { DEBUG("ndp: neighbor advertisement was invalid.\n"); /* ipv6 releases */ return; } if (nc_entry == NULL) { /* see https://tools.ietf.org/html/rfc4861#section-7.2.5 */ DEBUG("ndp: no neighbor cache entry found for advertisement's target\n"); /* ipv6 releases */ return; } sicmpv6_size -= sizeof(ng_ndp_nbr_adv_t); while (sicmpv6_size > 0) { ng_ndp_opt_t *opt = (ng_ndp_opt_t *)(buf + opt_offset); switch (opt->type) { case NG_NDP_OPT_TL2A: if ((l2tgt_len = _handle_tl2a_opt(pkt, ipv6, nbr_adv->type, opt, l2tgt)) < 0) { /* invalid target link-layer address option */ return; } break; default: /* silently discard all other options */ break; } opt_offset += (opt->len * 8); sicmpv6_size -= (opt->len * 8); } LL_SEARCH_SCALAR(pkt, netif, type, NG_NETTYPE_NETIF); if (netif != NULL) { netif_hdr = netif->data; } if (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_INCOMPLETE) { ng_pktqueue_t *queued_pkt; if (_pkt_has_l2addr(netif_hdr) && (l2tgt_len == 0)) { /* link-layer has addresses, but no TLLAO supplied: discard silently * (see https://tools.ietf.org/html/rfc4861#section-7.2.5) */ return; } nc_entry->iface = iface; nc_entry->l2_addr_len = l2tgt_len; memcpy(nc_entry->l2_addr, l2tgt, l2tgt_len); if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_S) { _set_state(nc_entry, NG_IPV6_NC_STATE_REACHABLE); } else { _set_state(nc_entry, NG_IPV6_NC_STATE_STALE); } if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_R) { nc_entry->flags |= NG_IPV6_NC_IS_ROUTER; } else { nc_entry->flags &= ~NG_IPV6_NC_IS_ROUTER; /* TODO: update FIB */ } while ((queued_pkt = ng_pktqueue_remove_head(&nc_entry->pkts)) != NULL) { ng_netapi_send(ng_ipv6_pid, queued_pkt->pkt); queued_pkt->pkt = NULL; } } else { /* first or-term: no link-layer, but nc_entry has l2addr, * second or-term: different l2addr cached */ bool l2tgt_changed = false; if ((!_pkt_has_l2addr(netif_hdr)) && (l2tgt_len == 0)) { /* there was previously a L2 address registered */ l2tgt_changed = (nc_entry->l2_addr_len != 0); } /* link-layer has addresses and TLLAO with different address */ else if (_pkt_has_l2addr(netif_hdr) && (l2tgt_len != 0)) { l2tgt_changed = (!(l2tgt_len == nc_entry->l2_addr_len)) && (memcmp(nc_entry->l2_addr, l2tgt, l2tgt_len) == 0); } if ((nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_O) || !l2tgt_changed || (l2tgt_len == 0)) { if (l2tgt_len != 0) { nc_entry->iface = iface; nc_entry->l2_addr_len = l2tgt_len; memcpy(nc_entry->l2_addr, l2tgt, l2tgt_len); } if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_S) { _set_state(nc_entry, NG_IPV6_NC_STATE_REACHABLE); } else if (l2tgt_changed && (l2tgt_len != 0)) { _set_state(nc_entry, NG_IPV6_NC_STATE_STALE); } if (nbr_adv->flags & NG_NDP_NBR_ADV_FLAGS_R) { nc_entry->flags |= NG_IPV6_NC_IS_ROUTER; } else { nc_entry->flags &= ~NG_IPV6_NC_IS_ROUTER; /* TODO: update FIB */ } } else if (l2tgt_changed) { if (ng_ipv6_nc_get_state(nc_entry) == NG_IPV6_NC_STATE_REACHABLE) { _set_state(nc_entry, NG_IPV6_NC_STATE_STALE); } } } return; }
static void _netif_list(kernel_pid_t dev) { uint8_t hwaddr[MAX_ADDR_LEN]; uint16_t u16; int16_t i16; int res; ng_netconf_state_t state; ng_netconf_enable_t enable; bool linebreak = false; #ifdef MODULE_NG_IPV6_NETIF ng_ipv6_netif_t *entry = ng_ipv6_netif_get(dev); char ipv6_addr[NG_IPV6_ADDR_MAX_STR_LEN]; #endif printf("Iface %2d ", dev); res = ng_netapi_get(dev, NETCONF_OPT_ADDRESS, 0, hwaddr, sizeof(hwaddr)); if (res >= 0) { char hwaddr_str[res * 3]; printf(" HWaddr: "); printf("%s", ng_netif_addr_to_str(hwaddr_str, sizeof(hwaddr_str), hwaddr, res)); printf(" "); } res = ng_netapi_get(dev, NETCONF_OPT_CHANNEL, 0, &u16, sizeof(u16)); if (res >= 0) { printf(" Channel: %" PRIu16 " ", u16); } res = ng_netapi_get(dev, NETCONF_OPT_NID, 0, &u16, sizeof(u16)); if (res >= 0) { printf(" NID: 0x%" PRIx16 " ", u16); } res = ng_netapi_get(dev, NETCONF_OPT_TX_POWER, 0, &i16, sizeof(i16)); if (res >= 0) { printf(" TX-Power: %" PRIi16 "dBm ", i16); } res = ng_netapi_get(dev, NETCONF_OPT_STATE, 0, &state, sizeof(state)); if (res >= 0) { printf(" State: "); _print_netconf_state(state); } printf("\n "); res = ng_netapi_get(dev, NETCONF_OPT_ADDRESS_LONG, 0, hwaddr, sizeof(hwaddr)); if (res >= 0) { char hwaddr_str[res * 3]; printf("Long HWaddr: "); printf("%s", ng_netif_addr_to_str(hwaddr_str, sizeof(hwaddr_str), hwaddr, res)); printf("\n "); } res = ng_netapi_get(dev, NETCONF_OPT_PROMISCUOUSMODE, 0, &enable, sizeof(enable)); if ((res >= 0) && (enable == NETCONF_ENABLE)) { printf("PROMISC "); linebreak = true; } res = ng_netapi_get(dev, NETCONF_OPT_AUTOACK, 0, &enable, sizeof(enable)); if ((res >= 0) && (enable == NETCONF_ENABLE)) { printf("AUTOACK "); linebreak = true; } res = ng_netapi_get(dev, NETCONF_OPT_PRELOADING, 0, &enable, sizeof(enable)); if ((res >= 0) && (enable == NETCONF_ENABLE)) { printf("PRELOAD "); linebreak = true; } res = ng_netapi_get(dev, NETCONF_OPT_RAWMODE, 0, &enable, sizeof(enable)); if ((res >= 0) && (enable == NETCONF_ENABLE)) { printf("RAWMODE "); linebreak = true; } #ifdef MODULE_NG_IPV6_NETIF if ((entry != NULL) && (entry->flags & NG_IPV6_NETIF_FLAGS_SIXLOWPAN)) { printf("6LO "); linebreak = true; } #endif if (linebreak) { printf("\n "); } res = ng_netapi_get(dev, NETCONF_OPT_SRC_LEN, 0, &u16, sizeof(u16)); if (res >= 0) { printf("Source address length: %" PRIu16 "\n ", u16); } #ifdef MODULE_NG_IPV6_NETIF for (int i = 0; i < NG_IPV6_NETIF_ADDR_NUMOF; i++) { if (!ng_ipv6_addr_is_unspecified(&entry->addrs[i].addr)) { printf("inet6 addr: "); if (ng_ipv6_addr_to_str(ipv6_addr, &entry->addrs[i].addr, NG_IPV6_ADDR_MAX_STR_LEN)) { printf("%s/%" PRIu8 " scope: ", ipv6_addr, entry->addrs[i].prefix_len); if ((ng_ipv6_addr_is_link_local(&entry->addrs[i].addr))) { printf("local"); } else { printf("global"); } if (entry->addrs[i].flags & NG_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST) { if (ng_ipv6_addr_is_multicast(&entry->addrs[i].addr)) { printf(" [multicast]"); } else { printf(" [anycast]"); } } } else { printf("error in conversion"); } printf("\n "); } } #endif puts(""); }
static void test_ipv6_addr_to_str__addr_NULL(void) { char result[NG_IPV6_ADDR_MAX_STR_LEN]; TEST_ASSERT_NULL(ng_ipv6_addr_to_str(result, NULL, sizeof(result))); }
static void test_ipv6_addr_to_str__result_NULL(void) { ng_ipv6_addr_t a; TEST_ASSERT_NULL(ng_ipv6_addr_to_str(NULL, &a, NG_IPV6_ADDR_MAX_STR_LEN)); }
static void _send_nbr_sol(kernel_pid_t iface, ng_ipv6_addr_t *tgt, ng_ipv6_addr_t *dst) { ng_pktsnip_t *hdr, *pkt = NULL; ng_ipv6_addr_t *src = NULL; size_t src_len = 0; DEBUG("ndp: send neighbor solicitation (iface: %" PRIkernel_pid ", tgt: %s, ", iface, ng_ipv6_addr_to_str(addr_str, tgt, sizeof(addr_str))); DEBUG("dst: %s)\n", ng_ipv6_addr_to_str(addr_str, dst, sizeof(addr_str))); /* check if there is a fitting source address to target */ if ((src = ng_ipv6_netif_find_best_src_addr(iface, tgt)) != NULL) { uint8_t l2src[8]; uint16_t l2src_len; src_len = sizeof(ng_ipv6_addr_t); l2src_len = _get_l2src(l2src, sizeof(l2src), iface); if (l2src_len > 0) { /* add source address link-layer address option */ pkt = ng_ndp_opt_sl2a_build(l2src, l2src_len, NULL); if (pkt == NULL) { DEBUG("ndp: error allocating Source Link-layer address option.\n"); ng_pktbuf_release(pkt); return; } } } hdr = ng_ndp_nbr_sol_build(tgt, pkt); if (hdr == NULL) { DEBUG("ndp: error allocating Neighbor solicitation.\n"); ng_pktbuf_release(pkt); return; } pkt = hdr; hdr = ng_ipv6_hdr_build(pkt, (uint8_t *)src, src_len, (uint8_t *)dst, sizeof(ng_ipv6_addr_t)); if (hdr == NULL) { DEBUG("ndp: error allocating IPv6 header.\n"); ng_pktbuf_release(pkt); return; } ((ng_ipv6_hdr_t *)hdr->data)->hl = 255; pkt = hdr; /* add netif header for send interface specification */ hdr = ng_netif_hdr_build(NULL, 0, NULL, 0); if (hdr == NULL) { DEBUG("ndp: error allocating netif header.\n"); return; } ((ng_netif_hdr_t *)hdr->data)->if_pid = iface; LL_PREPEND(pkt, hdr); ng_netapi_send(ng_ipv6_pid, pkt); }
void ng_ndp_nbr_sol_handle(kernel_pid_t iface, ng_pktsnip_t *pkt, ng_ipv6_hdr_t *ipv6, ng_ndp_nbr_sol_t *nbr_sol, size_t icmpv6_size) { uint16_t opt_offset = 0; uint8_t *buf = ((uint8_t *)nbr_sol) + sizeof(ng_ndp_nbr_sol_t); ng_ipv6_addr_t *tgt; int sicmpv6_size = (int)icmpv6_size; DEBUG("ndp: received neighbor solicitation (src: %s, ", ng_ipv6_addr_to_str(addr_str, &ipv6->src, sizeof(addr_str))); DEBUG("dst: %s, ", ng_ipv6_addr_to_str(addr_str, &ipv6->dst, sizeof(addr_str))); DEBUG("tgt: %s)\n", ng_ipv6_addr_to_str(addr_str, &nbr_sol->tgt, sizeof(addr_str))); /* check validity */ if ((ipv6->hl != 255) || (nbr_sol->code != 0) || (icmpv6_size < sizeof(ng_ndp_nbr_sol_t)) || ng_ipv6_addr_is_multicast(&nbr_sol->tgt) || (ng_ipv6_addr_is_unspecified(&ipv6->src) && ng_ipv6_addr_is_solicited_node(&ipv6->dst))) { DEBUG("ndp: neighbor solicitation was invalid.\n"); /* ipv6 releases */ return; } if ((tgt = ng_ipv6_netif_find_addr(iface, &nbr_sol->tgt)) == NULL) { DEBUG("ndp: Target address is not to interface %" PRIkernel_pid "\n", iface); /* ipv6 releases */ return; } sicmpv6_size -= sizeof(ng_ndp_nbr_sol_t); while (sicmpv6_size > 0) { ng_ndp_opt_t *opt = (ng_ndp_opt_t *)(buf + opt_offset); switch (opt->type) { case NG_NDP_OPT_SL2A: if (!_handle_sl2a_opt(iface, pkt, ipv6, nbr_sol->type, opt)) { /* invalid source link-layer address option */ return; } break; default: /* silently discard all other options */ break; } opt_offset += (opt->len * 8); sicmpv6_size -= (opt->len * 8); } _send_nbr_adv(iface, tgt, &ipv6->src, ng_ipv6_addr_is_multicast(&ipv6->dst)); return; }
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 int _fill_ipv6_hdr(kernel_pid_t iface, ng_pktsnip_t *ipv6, ng_pktsnip_t *payload) { int res; ng_ipv6_hdr_t *hdr = ipv6->data; hdr->len = byteorder_htons(ng_pkt_len(payload)); DEBUG("ipv6: set payload length to %zu (network byteorder %04" PRIx16 ")\n", ng_pkt_len(payload), hdr->len.u16); /* check if e.g. extension header was not already marked */ if (hdr->nh == NG_PROTNUM_RESERVED) { hdr->nh = ng_nettype_to_protnum(payload->type); /* if still reserved: mark no next header */ if (hdr->nh == NG_PROTNUM_RESERVED) { hdr->nh = NG_PROTNUM_IPV6_NONXT; } } DEBUG("ipv6: set next header to %" PRIu8 "\n", hdr->nh); if (hdr->hl == 0) { hdr->hl = ng_ipv6_netif_get(iface)->cur_hl; } if (ng_ipv6_addr_is_unspecified(&hdr->src)) { ng_ipv6_addr_t *src = ng_ipv6_netif_find_best_src_addr(iface, &hdr->dst); if (src != NULL) { DEBUG("ipv6: set packet source to %s\n", ng_ipv6_addr_to_str(addr_str, src, sizeof(addr_str))); memcpy(&hdr->src, src, sizeof(ng_ipv6_addr_t)); } /* Otherwise leave unspecified */ } DEBUG("ipv6: calculate checksum for upper header.\n"); #if NG_NETIF_NUMOF > 1 if (payload->users > 1) { ng_pktsnip_t *ptr = ipv6; /* We deal with multiple interfaces here (multicast) => possible * different source addresses => duplication of payload needed */ while (ptr != payload->next) { ng_pktsnip_t *old = ptr->next; /* duplicate everything including payload */ ptr->next = ng_pktbuf_start_write(ptr->next); if (ptr->next == NULL) { DEBUG("ipv6: unable to get write access to payload, drop it\n"); return -ENOBUFS; } ptr = old; } } #endif /* NG_NETIF_NUMOF */ if ((res = ng_netreg_calc_csum(payload, ipv6)) < 0) { if (res != -ENOENT) { /* if there is no checksum we are okay */ DEBUG("ipv6: checksum calculation failed.\n"); return res; } } return 0; }
static void _send_nbr_adv(kernel_pid_t iface, ng_ipv6_addr_t *tgt, ng_ipv6_addr_t *dst, bool supply_tl2a) { ng_pktsnip_t *hdr, *pkt = NULL; uint8_t adv_flags = 0; DEBUG("ndp: send neighbor advertisement (iface: %" PRIkernel_pid ", tgt: %s, ", iface, ng_ipv6_addr_to_str(addr_str, tgt, sizeof(addr_str))); DEBUG("dst: %s, supply_tl2a: %d)\n", ng_ipv6_addr_to_str(addr_str, dst, sizeof(addr_str)), supply_tl2a); if (ng_ipv6_netif_get(iface)->flags & NG_IPV6_NETIF_FLAGS_ROUTER) { adv_flags |= NG_NDP_NBR_ADV_FLAGS_R; } if (ng_ipv6_addr_is_unspecified(dst)) { ng_ipv6_addr_set_all_nodes_multicast(dst, NG_IPV6_ADDR_MCAST_SCP_LINK_LOCAL); } else { adv_flags |= NG_NDP_NBR_ADV_FLAGS_S; } if (supply_tl2a) { uint8_t l2src[8]; uint16_t l2src_len; /* we previously checked if we are the target, so we can take our L2src */ l2src_len = _get_l2src(l2src, sizeof(l2src), iface); if (l2src_len > 0) { /* add target address link-layer address option */ pkt = ng_ndp_opt_tl2a_build(l2src, l2src_len, NULL); if (pkt == NULL) { DEBUG("ndp: error allocating Target Link-layer address option.\n"); ng_pktbuf_release(pkt); return; } } } /* TODO: also check if the node provides proxy servies for tgt */ if ((pkt != NULL) && !ng_ipv6_netif_addr_is_non_unicast(tgt)) { /* TL2A is not supplied and tgt is not anycast */ adv_flags |= NG_NDP_NBR_ADV_FLAGS_O; } hdr = ng_ndp_nbr_adv_build(adv_flags, tgt, pkt); if (hdr == NULL) { DEBUG("ndp: error allocating Neighbor advertisement.\n"); ng_pktbuf_release(pkt); return; } pkt = hdr; hdr = ng_ipv6_hdr_build(pkt, NULL, 0, (uint8_t *)dst, sizeof(ng_ipv6_addr_t)); if (hdr == NULL) { DEBUG("ndp: error allocating IPv6 header.\n"); ng_pktbuf_release(pkt); return; } ((ng_ipv6_hdr_t *)hdr->data)->hl = 255; pkt = hdr; /* add netif header for send interface specification */ hdr = ng_netif_hdr_build(NULL, 0, NULL, 0); if (hdr == NULL) { DEBUG("ndp: error allocating netif header.\n"); return; } ((ng_netif_hdr_t *)hdr->data)->if_pid = iface; LL_PREPEND(pkt, hdr); if (ng_ipv6_netif_addr_is_non_unicast(tgt)) { /* avoid collision for anycast addresses * (see https://tools.ietf.org/html/rfc4861#section-7.2.7) */ timex_t delay = { _rand(0, NG_NDP_MAX_AC_TGT_DELAY), 0 }; ng_ipv6_nc_t *nc_entry = ng_ipv6_nc_get(iface, tgt); DEBUG("ndp: delay neighbor advertisement for %" PRIu32 " sec.", delay.seconds); /* nc_entry must be set so no need to check it */ _send_delayed(&nc_entry->nbr_adv_timer, delay, pkt); } else { ng_netapi_send(ng_ipv6_pid, pkt); } }
static void _receive(ng_pktsnip_t *pkt) { kernel_pid_t iface = KERNEL_PID_UNDEF; ng_pktsnip_t *ipv6, *netif; ng_ipv6_hdr_t *hdr; LL_SEARCH_SCALAR(pkt, netif, type, NG_NETTYPE_NETIF); if (netif != NULL) { iface = ((ng_netif_hdr_t *)netif->data)->if_pid; } if ((pkt->next != NULL) && (pkt->next->type == NG_NETTYPE_IPV6) && (pkt->next->size == sizeof(ng_ipv6_hdr_t))) { /* IP header was already marked. Take it. */ ipv6 = pkt->next; if (!ng_ipv6_hdr_is(ipv6->data)) { DEBUG("ipv6: Received packet was not IPv6, dropping packet\n"); ng_pktbuf_release(pkt); return; } } else { if (!ng_ipv6_hdr_is(pkt->data)) { DEBUG("ipv6: Received packet was not IPv6, dropping packet\n"); ng_pktbuf_release(pkt); return; } /* seize ipv6 as a temporary variable */ ipv6 = ng_pktbuf_start_write(pkt); if (ipv6 == NULL) { DEBUG("ipv6: unable to get write access to packet, drop it\n"); ng_pktbuf_release(pkt); return; } pkt = ipv6; /* reset pkt from temporary variable */ ipv6 = ng_pktbuf_add(pkt, pkt->data, sizeof(ng_ipv6_hdr_t), NG_NETTYPE_IPV6); if (ipv6 == NULL) { DEBUG("ipv6: error marking IPv6 header, dropping packet\n"); ng_pktbuf_release(pkt); return; } } /* extract header */ hdr = (ng_ipv6_hdr_t *)ipv6->data; DEBUG("ipv6: Received (src = %s, ", ng_ipv6_addr_to_str(addr_str, &(hdr->src), sizeof(addr_str))); DEBUG("dst = %s, next header = %" PRIu8 ", length = %" PRIu16 ")\n", ng_ipv6_addr_to_str(addr_str, &(hdr->dst), sizeof(addr_str)), hdr->nh, byteorder_ntohs(hdr->len)); if (_pkt_not_for_me(&iface, hdr)) { /* if packet is not for me */ DEBUG("ipv6: packet destination not this host\n"); #ifdef MODULE_NG_IPV6_ROUTER /* only routers redirect */ /* redirect to next hop */ DEBUG("ipv6: decrement hop limit to %" PRIu8 "\n", hdr->hl - 1); /* TODO: check if receiving interface is router */ if (--(hdr->hl) > 0) { /* drop packets that *reach* Hop Limit 0 */ ng_pktsnip_t *tmp = pkt; DEBUG("ipv6: forward packet to next hop\n"); /* pkt might not be writable yet, if header was given above */ pkt = ng_pktbuf_start_write(tmp); ipv6 = ng_pktbuf_start_write(ipv6); if ((ipv6 == NULL) || (pkt == NULL)) { DEBUG("ipv6: unable to get write access to packet: dropping it\n"); ng_pktbuf_release(tmp); return; } ng_pktbuf_release(ipv6->next); /* remove headers around IPV6 */ ipv6->next = pkt; /* reorder for sending */ pkt->next = NULL; _send(ipv6, false); } else { DEBUG("ipv6: hop limit reached 0: drop packet\n"); ng_pktbuf_release(pkt); return; } #else /* MODULE_NG_IPV6_ROUTER */ DEBUG("ipv6: dropping packet\n"); /* non rounting hosts just drop the packet */ ng_pktbuf_release(pkt); return; #endif /* MODULE_NG_IPV6_ROUTER */ } /* IPv6 internal demuxing (ICMPv6, Extension headers etc.) */ ng_ipv6_demux(iface, pkt, hdr->nh); }
static void _set_state(ng_ipv6_nc_t *nc_entry, uint8_t state) { ng_ipv6_netif_t *ipv6_iface; timex_t t = { NG_NDP_FIRST_PROBE_DELAY, 0 }; nc_entry->flags &= ~NG_IPV6_NC_STATE_MASK; nc_entry->flags |= state; DEBUG("ndp: set %s state to ", ng_ipv6_addr_to_str(addr_str, &nc_entry->ipv6_addr, sizeof(addr_str))); switch (state) { case NG_IPV6_NC_STATE_REACHABLE: ipv6_iface = ng_ipv6_netif_get(nc_entry->iface); DEBUG("REACHABLE (reachable time = %" PRIu32 ".%06" PRIu32 ")\n", ipv6_iface->reach_time.seconds, ipv6_iface->reach_time.microseconds); t = ipv6_iface->reach_time; /* we intentionally fall through here to set the desired timeout t */ case NG_IPV6_NC_STATE_DELAY: #if ENABLE_DEBUG if (state == NG_IPV6_NC_STATE_DELAY) { DEBUG("DELAY (probe with unicast NS in %u seconds)\n", NG_NDP_FIRST_PROBE_DELAY); } #endif vtimer_remove(&nc_entry->nbr_sol_timer); vtimer_set_msg(&nc_entry->nbr_sol_timer, t, ng_ipv6_pid, NG_NDP_MSG_NC_STATE_TIMEOUT, nc_entry); break; case NG_IPV6_NC_STATE_PROBE: ipv6_iface = ng_ipv6_netif_get(nc_entry->iface); nc_entry->probes_remaining = NG_NDP_MAX_UC_NBR_SOL_NUMOF; DEBUG("PROBE (probe with %" PRIu8 " unicast NS every %" PRIu32 ".%06" PRIu32 " seconds)\n", nc_entry->probes_remaining, ipv6_iface->retrans_timer.seconds, ipv6_iface->retrans_timer.microseconds); _send_nbr_sol(nc_entry->iface, &nc_entry->ipv6_addr, &nc_entry->ipv6_addr); 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); break; #ifdef ENABLE_DEBUG case NG_IPV6_NC_STATE_STALE: DEBUG("STALE (go into DELAY on next packet)\n"); break; #endif default: DEBUG("errorneous or unknown\n"); break; } }
static void _send(ng_pktsnip_t *pkt, bool prep_hdr) { kernel_pid_t iface = KERNEL_PID_UNDEF; ng_pktsnip_t *ipv6, *payload; ng_ipv6_hdr_t *hdr; ng_ipv6_nc_t *nc_entry; /* seize payload as temporary variable */ payload = ng_pktbuf_start_write(pkt); if (payload == NULL) { DEBUG("ipv6: unable to get write access to packet, dropping packet\n"); ng_pktbuf_release(pkt); return; } pkt = payload; /* Reset pkt from temporary variable */ /* get IPv6 snip and (if present) generic interface header */ if (pkt->type == NG_NETTYPE_NETIF) { /* If there is already a netif header (routing protocols and * neighbor discovery might add them to preset sending interface) */ iface = ((ng_netif_hdr_t *)pkt->data)->if_pid; ipv6 = pkt->next; } else { ipv6 = pkt; } hdr = ipv6->data; payload = ipv6->next; /* TODO: parse extension headers */ if (ng_ipv6_addr_is_multicast(&hdr->dst)) { _send_multicast(iface, pkt, ipv6, payload, prep_hdr); } else { ng_ipv6_addr_t *next_hop = NULL; next_hop = &hdr->dst; /* TODO: next hop determination */ if ((nc_entry = ng_ipv6_nc_get_reachable(iface, next_hop)) == NULL) { DEBUG("ipv6: No link layer address for next_hop %s found.\n", ng_ipv6_addr_to_str(addr_str, next_hop, sizeof(addr_str))); ng_pktbuf_release(pkt); return; } else { iface = nc_entry->iface; } if (iface == KERNEL_PID_UNDEF) { DEBUG("ipv6: no interface for %s registered, dropping packet\n", ng_ipv6_addr_to_str(addr_str, next_hop, sizeof(addr_str))); ng_pktbuf_release(pkt); return; } if (prep_hdr) { if (_fill_ipv6_hdr(iface, ipv6, payload) < 0) { /* error on filling up header */ ng_pktbuf_release(pkt); return; } } _send_unicast(iface, nc_entry->l2_addr, nc_entry->l2_addr_len, pkt); } }