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; }
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; /* 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; }
ng_pktsnip_t *ng_ndp_nbr_adv_build(uint8_t flags, ng_ipv6_addr_t *tgt, ng_pktsnip_t *options) { ng_pktsnip_t *pkt; ng_ndp_nbr_adv_t *nbr_adv; DEBUG("ndp: building neighbor advertisement message\n"); if (ng_ipv6_addr_is_multicast(tgt)) { DEBUG("ndp: tgt must not be multicast\n"); return NULL; } pkt = ng_icmpv6_build(options, NG_ICMPV6_NBR_ADV, 0, sizeof(ng_ndp_nbr_adv_t)); if (pkt == NULL) { return NULL; } nbr_adv = pkt->data; nbr_adv->flags = (flags & NG_NDP_NBR_ADV_FLAGS_MASK); nbr_adv->resv[0] = nbr_adv->resv[1] = nbr_adv->resv[2] = 0; memcpy(&nbr_adv->tgt, tgt, sizeof(ng_ipv6_addr_t)); return pkt; }
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; /* 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 { uint8_t l2addr_len = NG_IPV6_NC_L2_ADDR_MAX; uint8_t l2addr[l2addr_len]; iface = ng_ndp_next_hop_l2addr(l2addr, &l2addr_len, iface, &hdr->dst, pkt); if (iface == KERNEL_PID_UNDEF) { DEBUG("ipv6: error determining next hop's link layer address\n"); 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, l2addr, l2addr_len, pkt); } }
static void test_ipv6_addr_is_multicast_multicast(void) { ng_ipv6_addr_t a = { { 0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f } }; TEST_ASSERT_EQUAL_INT(true, ng_ipv6_addr_is_multicast(&a)); }
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; }
ng_pktsnip_t *ng_ndp_nbr_sol_build(ng_ipv6_addr_t *tgt, ng_pktsnip_t *options) { ng_pktsnip_t *pkt; DEBUG("ndp: building neighbor solicitation message\n"); if (ng_ipv6_addr_is_multicast(tgt)) { DEBUG("ndp: tgt must not be multicast\n"); return NULL; } pkt = ng_icmpv6_build(options, NG_ICMPV6_NBR_SOL, 0, sizeof(ng_ndp_nbr_sol_t)); if (pkt != NULL) { ng_ndp_nbr_sol_t *nbr_sol = pkt->data; nbr_sol->resv.u32 = 0; nbr_sol->tgt.u64[0].u64 = tgt->u64[0].u64; nbr_sol->tgt.u64[1].u64 = tgt->u64[1].u64; } return pkt; }
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 _send(ng_pktsnip_t *pkt, bool prep_hdr) { kernel_pid_t iface = KERNEL_PID_UNDEF; ng_pktsnip_t *ipv6, *payload; ng_ipv6_addr_t *tmp; ng_ipv6_hdr_t *hdr; /* 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; /* seize payload as temporary variable */ ipv6 = ng_pktbuf_start_write(pkt); /* write protect for later removal * in _send_unicast() */ if (ipv6 == NULL) { DEBUG("ipv6: unable to get write access to netif header, dropping packet\n"); ng_pktbuf_release(pkt); return; } pkt = ipv6; /* Reset pkt from temporary variable */ ipv6 = pkt->next; } else { ipv6 = pkt; } /* seize payload as temporary variable */ payload = ng_pktbuf_start_write(ipv6); if (payload == NULL) { DEBUG("ipv6: unable to get write access to IPv6 header, dropping packet\n"); ng_pktbuf_release(pkt); return; } if (ipv6 != pkt) { /* in case packet has netif header */ pkt->next = payload;/* pkt is already write-protected so we can do that */ } ipv6 = payload; /* Reset ipv6 from temporary variable */ hdr = ipv6->data; payload = ipv6->next; if (ng_ipv6_addr_is_multicast(&hdr->dst)) { _send_multicast(iface, pkt, ipv6, payload, prep_hdr); } else if ((ng_ipv6_addr_is_loopback(&hdr->dst)) || /* dst is loopback address */ ((iface == KERNEL_PID_UNDEF) && /* or dst registered to any local interface */ ((iface = ng_ipv6_netif_find_by_addr(&tmp, &hdr->dst)) != KERNEL_PID_UNDEF)) || ((iface != KERNEL_PID_UNDEF) && /* or dst registered to given interface */ (ng_ipv6_netif_find_addr(iface, &hdr->dst) != NULL))) { uint8_t *rcv_data; ng_pktsnip_t *ptr = ipv6, *rcv_pkt; if (prep_hdr) { if (_fill_ipv6_hdr(iface, ipv6, payload) < 0) { /* error on filling up header */ ng_pktbuf_release(pkt); return; } } rcv_pkt = ng_pktbuf_add(NULL, NULL, ng_pkt_len(ipv6), NG_NETTYPE_IPV6); if (rcv_pkt == NULL) { DEBUG("ipv6: error on generating loopback packet\n"); ng_pktbuf_release(pkt); return; } rcv_data = rcv_pkt->data; /* "reverse" packet (by making it one snip as if received from NIC) */ while (ptr != NULL) { memcpy(rcv_data, ptr->data, ptr->size); rcv_data += ptr->size; ptr = ptr->next; } ng_pktbuf_release(pkt); DEBUG("ipv6: packet is addressed to myself => loopback\n"); ng_netapi_receive(ng_ipv6_pid, rcv_pkt); } else { uint8_t l2addr_len = NG_IPV6_NC_L2_ADDR_MAX; uint8_t l2addr[l2addr_len]; iface = _next_hop_l2addr(l2addr, &l2addr_len, iface, &hdr->dst, pkt); if (iface == KERNEL_PID_UNDEF) { DEBUG("ipv6: error determining next hop's link layer address\n"); 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, l2addr, l2addr_len, pkt); } }
static int _netif_add(char *cmd_name, kernel_pid_t dev, int argc, char **argv) { #ifdef MODULE_NG_IPV6_NETIF enum { _UNICAST = 0, _MULTICAST, /* multicast value just to check if given addr is mc */ _ANYCAST } type = _UNICAST; char *addr_str = argv[0]; ng_ipv6_addr_t addr; uint8_t prefix_len; if (argc > 1) { if (strcmp(argv[0], "anycast") == 0) { type = _ANYCAST; addr_str = argv[1]; } else if (strcmp(argv[0], "multicast") == 0) { type = _MULTICAST; addr_str = argv[1]; } else if (strcmp(argv[0], "unicast") == 0) { /* type already set to unicast */ addr_str = argv[1]; } else { _add_usage(cmd_name); return 1; } } prefix_len = _get_prefix_len(addr_str); if (ng_ipv6_addr_from_str(&addr, addr_str) == NULL) { puts("error: unable to parse IPv6 address."); return 1; } if ((argc > 1) && (ng_ipv6_addr_is_multicast(&addr)) && (type != _MULTICAST)) { puts("error: address was not a multicast address."); return 1; } if (ng_ipv6_netif_add_addr(dev, &addr, prefix_len, (type == _ANYCAST) ? NG_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST : NG_IPV6_NETIF_ADDR_FLAGS_UNICAST) == NULL) { printf("error: unable to add IPv6 address\n"); return 1; } printf("success: added %s/%d to interface %" PRIkernel_pid "\n", addr_str, prefix_len, dev); return 0; #else (void)cmd_name; (void)dev; (void)argc; (void)argv; puts("error: unable to add IPv6 address."); return 1; #endif }
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 _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); } }