static void _send(ng_pktsnip_t *pkt) { ng_udp_hdr_t *hdr; ng_pktsnip_t *udp_snip; ng_netreg_entry_t *sendto; /* get udp snip and hdr */ LL_SEARCH_SCALAR(pkt, udp_snip, type, NG_NETTYPE_UDP); udp_snip = ng_pktbuf_start_write(udp_snip); if (udp_snip == NULL) { DEBUG("udp: cannot send packet: unable to allocate packet\n"); ng_pktbuf_release(pkt); return; } hdr = (ng_udp_hdr_t *)udp_snip->data; /* fill in size field */ hdr->length = byteorder_htons(ng_pkt_len(udp_snip)); /* and forward packet to the network layer */ sendto = ng_netreg_lookup(pkt->type, NG_NETREG_DEMUX_CTX_ALL); /* throw away packet if no one is interested */ if (sendto == NULL) { DEBUG("udp: cannot send packet: network layer not found\n"); ng_pktbuf_release(pkt); return; } /* send packet to network layer */ ng_pktbuf_hold(pkt, ng_netreg_num(pkt->type, NG_NETREG_DEMUX_CTX_ALL) - 1); while (sendto != NULL) { ng_netapi_send(sendto->pid, pkt); sendto = ng_netreg_getnext(sendto); } }
static void test_pktbuf_hold__pkt_external(void) { ng_pktsnip_t pkt = { 1, NULL, TEST_STRING8, sizeof(TEST_STRING8), NG_NETTYPE_TEST }; ng_pktbuf_hold(&pkt, 1); TEST_ASSERT(ng_pktbuf_is_empty()); }
static void _send_to_iface(kernel_pid_t iface, ng_pktsnip_t *pkt) { ng_ipv6_netif_t *if_entry = ng_ipv6_netif_get(iface); ((ng_netif_hdr_t *)pkt->data)->if_pid = iface; if ((if_entry != NULL) && (if_entry->flags & NG_IPV6_NETIF_FLAGS_SIXLOWPAN)) { DEBUG("ipv6: send to 6LoWPAN instead\n"); ng_netreg_entry_t *reg = ng_netreg_lookup(NG_NETTYPE_SIXLOWPAN, NG_NETREG_DEMUX_CTX_ALL); if (reg != NULL) { ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_SIXLOWPAN, NG_NETREG_DEMUX_CTX_ALL) - 1); } else { DEBUG("ipv6: no 6LoWPAN thread found"); } while (reg) { ng_netapi_send(reg->pid, pkt); reg = ng_netreg_getnext(reg); } } else { ng_netapi_send(iface, pkt); } }
/** * @brief Function called by the device driver on device events * * @param[in] event type of event * @param[in] data optional parameter */ static void _event_cb(ng_netdev_event_t event, void *data) { DEBUG("nomac: event triggered -> %i\n", event); /* NOMAC only understands the RX_COMPLETE event... */ if (event == NETDEV_EVENT_RX_COMPLETE) { ng_pktsnip_t *pkt; ng_netreg_entry_t *sendto; /* get pointer to the received packet */ pkt = (ng_pktsnip_t *)data; /* find out, who to send the packet to */ sendto = ng_netreg_lookup(pkt->type, NG_NETREG_DEMUX_CTX_ALL); /* throw away packet if no one is interested */ if (sendto == NULL) { DEBUG("nomac: unable to forward packet of type %i\n", pkt->type); ng_pktbuf_release(pkt); return; } /* send the packet to everyone interested in it's type */ ng_pktbuf_hold(pkt, ng_netreg_num(pkt->type, NG_NETREG_DEMUX_CTX_ALL) - 1); while (sendto != NULL) { DEBUG("nomac: sending pkt %p to PID %u\n", (void*)pkt, sendto->pid); ng_netapi_receive(sendto->pid, pkt); sendto = ng_netreg_getnext(sendto); } } }
void ng_ipv6_demux(kernel_pid_t iface, ng_pktsnip_t *pkt, uint8_t nh) { int receiver_num; pkt->type = ng_nettype_from_protnum(nh); switch (nh) { case NG_PROTNUM_ICMPV6: ng_icmpv6_demux(iface, pkt); break; /* TODO: add extension header handling */ default: break; } receiver_num = ng_netreg_num(pkt->type, NG_NETREG_DEMUX_CTX_ALL) + ng_netreg_num(NG_NETTYPE_IPV6, nh); if (receiver_num == 0) { DEBUG("ipv6: unable to forward packet as no one is interested in it\n"); ng_pktbuf_release(pkt); return; } ng_pktbuf_hold(pkt, receiver_num - 1); /* IPv6 is not interested anymore so `- 1` */ _dispatch_rcv_pkt(pkt->type, NG_NETREG_DEMUX_CTX_ALL, pkt); _dispatch_rcv_pkt(NG_NETTYPE_IPV6, nh, pkt); }
static void test_pktbuf_hold__success2(void) { ng_pktsnip_t *pkt = ng_pktbuf_add(NULL, TEST_STRING16, sizeof(TEST_STRING16), NG_NETTYPE_TEST); ng_pktbuf_hold(pkt, TEST_UINT8); TEST_ASSERT_EQUAL_INT(TEST_UINT8 + 1, pkt->users); }
static void send(char *addr_str, char *port_str, char *data) { uint8_t port[2]; uint16_t tmp; ng_pktsnip_t *payload, *udp, *ip; ng_ipv6_addr_t addr; ng_netreg_entry_t *sendto; /* parse destination address */ if (ng_ipv6_addr_from_str(&addr, addr_str) == NULL) { puts("Error: unable to parse destination address"); return; } /* parse port */ tmp = (uint16_t)atoi(port_str); if (tmp == 0) { puts("Error: unable to parse destination port"); return; } port[0] = (uint8_t)tmp; port[1] = tmp >> 8; /* allocate payload */ payload = ng_pktbuf_add(NULL, data, strlen(data), NG_NETTYPE_UNDEF); if (payload == NULL) { puts("Error: unable to copy data to packet buffer"); return; } /* allocate UDP header, set source port := destination port */ udp = ng_udp_hdr_build(payload, port, 2, port, 2); if (udp == NULL) { puts("Error: unable to allocate UDP header"); ng_pktbuf_release(payload); return; } /* allocate IPv6 header */ ip = ng_ipv6_hdr_build(udp, NULL, 0, (uint8_t *)&addr, sizeof(addr)); if (ip == NULL) { puts("Error: unable to allocate IPv6 header"); ng_pktbuf_release(udp); return; } /* send packet */ sendto = ng_netreg_lookup(NG_NETTYPE_UDP, NG_NETREG_DEMUX_CTX_ALL); if (sendto == NULL) { puts("Error: unable to locate UDP thread"); ng_pktbuf_release(ip); return; } ng_pktbuf_hold(ip, ng_netreg_num(NG_NETTYPE_UDP, NG_NETREG_DEMUX_CTX_ALL) - 1); while (sendto != NULL) { ng_netapi_send(sendto->pid, ip); sendto = ng_netreg_getnext(sendto); } printf("Success: send %i byte to %s:%u\n", payload->size, addr_str, tmp); }
static void test_pktbuf_realloc_data__pkt_users_gt_1(void) { ng_pktsnip_t *pkt = ng_pktbuf_add(NULL, NULL, sizeof(TEST_STRING8), NG_NETTYPE_UNDEF); ng_pktbuf_hold(pkt, 1); TEST_ASSERT_EQUAL_INT(EINVAL, ng_pktbuf_realloc_data(pkt, sizeof(TEST_STRING8) - 1)); ng_pktbuf_release(pkt); ng_pktbuf_release(pkt); TEST_ASSERT(ng_pktbuf_is_empty()); }
static void test_pktbuf_hold__success(void) { ng_pktsnip_t *pkt = ng_pktbuf_add(NULL, TEST_STRING16, sizeof(TEST_STRING16), NG_NETTYPE_TEST); for (uint8_t i = 0; i < TEST_UINT8; i++) { uint8_t prev_users = pkt->users; ng_pktbuf_hold(pkt, 1); TEST_ASSERT_EQUAL_INT(prev_users + 1, pkt->users); } }
/* SLIP receive handler */ static void _slip_receive(ng_slip_dev_t *dev, size_t bytes) { ng_netif_hdr_t *hdr; ng_netreg_entry_t *sendto; ng_pktsnip_t *pkt, *netif_hdr; pkt = ng_pktbuf_add(NULL, NULL, bytes, NG_NETTYPE_UNDEF); if (pkt == NULL) { DEBUG("slip: no space left in packet buffer\n"); return; } netif_hdr = ng_pktbuf_add(pkt, NULL, sizeof(ng_netif_hdr_t), NG_NETTYPE_NETIF); if (netif_hdr == NULL) { DEBUG("slip: no space left in packet buffer\n"); ng_pktbuf_release(pkt); return; } hdr = netif_hdr->data; ng_netif_hdr_init(hdr, 0, 0); hdr->if_pid = thread_getpid(); if (ringbuffer_get(dev->in_buf, pkt->data, bytes) != bytes) { DEBUG("slip: could not read %zu bytes from ringbuffer\n", bytes); ng_pktbuf_release(pkt); return; } #ifdef MODULE_NG_IPV6 if ((pkt->size >= sizeof(ipv6_hdr_t)) && ipv6_hdr_is(pkt->data)) { pkt->type = NG_NETTYPE_IPV6; } #endif sendto = ng_netreg_lookup(pkt->type, NG_NETREG_DEMUX_CTX_ALL); if (sendto == NULL) { DEBUG("slip: unable to forward packet of type %i\n", pkt->type); ng_pktbuf_release(pkt); } ng_pktbuf_hold(pkt, ng_netreg_num(pkt->type, NG_NETREG_DEMUX_CTX_ALL) - 1); while (sendto != NULL) { DEBUG("slip: sending pkt %p to PID %u\n", pkt, sendto->pid); ng_netapi_receive(sendto->pid, pkt); sendto = ng_netreg_getnext(sendto); } }
static void _receive(ng_pktsnip_t *pkt) { ng_pktsnip_t *udp, *ipv6; ng_udp_hdr_t *hdr; uint32_t port; ng_netreg_entry_t *sendto; /* mark UDP header */ udp = ng_pktbuf_start_write(pkt); if (udp == NULL) { DEBUG("udp: unable to get write access to packet\n"); ng_pktbuf_release(pkt); return; } pkt = udp; udp = ng_pktbuf_add(pkt, pkt->data, sizeof(ng_udp_hdr_t), NG_NETTYPE_UDP); if (udp == NULL) { DEBUG("udp: error marking UDP header, dropping packet\n"); ng_pktbuf_release(pkt); return; } /* mark payload as Type: UNDEF */ pkt->type = NG_NETTYPE_UNDEF; /* get explicit pointer to UDP header */ hdr = (ng_udp_hdr_t *)udp->data; LL_SEARCH_SCALAR(pkt, ipv6, type, NG_NETTYPE_IPV6); /* validate checksum */ if (_calc_csum(udp, ipv6, pkt)) { DEBUG("udp: received packet with invalid checksum, dropping it\n"); ng_pktbuf_release(pkt); return; } /* get port (netreg demux context) */ port = (uint32_t)byteorder_ntohs(hdr->dst_port); /* send payload to receivers */ sendto = ng_netreg_lookup(NG_NETTYPE_UDP, port); if (sendto == NULL) { DEBUG("udp: unable to forward packet as no one is interested in it\n"); ng_pktbuf_release(pkt); return; } ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_UDP, port) - 1); while (sendto != NULL) { ng_netapi_receive(sendto->pid, pkt); sendto = ng_netreg_getnext(sendto); } }
void ng_ipv6_demux(kernel_pid_t iface, ng_pktsnip_t *pkt, uint8_t nh) { int receiver_num; pkt->type = ng_nettype_from_protnum(nh); switch (nh) { case NG_PROTNUM_ICMPV6: DEBUG("ipv6: handle ICMPv6 packet (nh = %" PRIu8 ")\n", nh); ng_icmpv6_demux(iface, pkt); break; #ifdef MODULE_NG_IPV6_EXT case NG_PROTNUM_IPV6_EXT_HOPOPT: case NG_PROTNUM_IPV6_EXT_DST: case NG_PROTNUM_IPV6_EXT_RH: case NG_PROTNUM_IPV6_EXT_FRAG: case NG_PROTNUM_IPV6_EXT_AH: case NG_PROTNUM_IPV6_EXT_ESP: case NG_PROTNUM_IPV6_EXT_MOB: DEBUG("ipv6: handle extension header (nh = %" PRIu8 ")\n", nh); if (!ng_ipv6_ext_demux(iface, pkt, nh)) { DEBUG("ipv6: unable to parse extension headers.\n"); ng_pktbuf_release(pkt); return; } #endif case NG_PROTNUM_IPV6: DEBUG("ipv6: handle encapsulated IPv6 packet (nh = %" PRIu8 ")\n", nh); _decapsulate(pkt); break; default: break; } DEBUG("ipv6: forward nh = %" PRIu8 " to other threads\n", nh); receiver_num = ng_netreg_num(pkt->type, NG_NETREG_DEMUX_CTX_ALL) + ng_netreg_num(NG_NETTYPE_IPV6, nh); if (receiver_num == 0) { DEBUG("ipv6: unable to forward packet as no one is interested in it\n"); ng_pktbuf_release(pkt); return; } ng_pktbuf_hold(pkt, receiver_num - 1); /* IPv6 is not interested anymore so `- 1` */ _dispatch_rcv_pkt(pkt->type, NG_NETREG_DEMUX_CTX_ALL, pkt); _dispatch_rcv_pkt(NG_NETTYPE_IPV6, nh, pkt); }
static void test_pktbuf_start_write__pkt_users_2(void) { ng_pktsnip_t *pkt_copy, *pkt = ng_pktbuf_add(NULL, TEST_STRING16, sizeof(TEST_STRING16), NG_NETTYPE_TEST); ng_pktbuf_hold(pkt, 1); TEST_ASSERT_NOT_NULL((pkt_copy = ng_pktbuf_start_write(pkt))); TEST_ASSERT(pkt != pkt_copy); TEST_ASSERT(pkt->next == pkt_copy->next); TEST_ASSERT_EQUAL_STRING(pkt->data, pkt_copy->data); TEST_ASSERT_EQUAL_INT(pkt->size, pkt_copy->size); TEST_ASSERT_EQUAL_INT(pkt->type, pkt_copy->type); TEST_ASSERT_EQUAL_INT(pkt->users, pkt_copy->users); TEST_ASSERT_EQUAL_INT(1, pkt->users); ng_pktbuf_release(pkt_copy); ng_pktbuf_release(pkt); TEST_ASSERT(ng_pktbuf_is_empty()); }
static void udp_send(const char *str) { uint8_t data[20]; ng_pktsnip_t *payload, *udp, *ip; ng_netreg_entry_t *sendto; memcpy(data, str, strlen(str)); /* allocate payload */ payload = ng_pktbuf_add(NULL, data, strlen(str), NG_NETTYPE_UNDEF); if (payload == NULL) { puts("Error: unable to copy data to packet buffer"); return; } /* allocate UDP header, set source port := destination port */ udp = ng_udp_hdr_build(payload, port, 2, port, 2); if (udp == NULL) { puts("Error: unable to allocate UDP header"); ng_pktbuf_release(payload); return; } /* allocate IPv6 header */ ip = ng_ipv6_hdr_build(udp, NULL, 0, (uint8_t *)&addr, sizeof(addr)); if (ip == NULL) { puts("Error: unable to allocate IPv6 header"); ng_pktbuf_release(udp); return; } /* send packet */ sendto = ng_netreg_lookup(NG_NETTYPE_UDP, NG_NETREG_DEMUX_CTX_ALL); if (sendto == NULL) { puts("Error: unable to locate UDP thread"); ng_pktbuf_release(ip); return; } ng_pktbuf_hold(ip, ng_netreg_num(NG_NETTYPE_UDP, NG_NETREG_DEMUX_CTX_ALL) - 1); while (sendto != NULL) { ng_netapi_send(sendto->pid, ip); sendto = ng_netreg_getnext(sendto); } printf("Send %s\n", str); }
static void test_pktbuf_release__success(void) { ng_pktsnip_t *pkt = ng_pktbuf_add(NULL, TEST_STRING16, sizeof(TEST_STRING16), NG_NETTYPE_UNDEF); for (uint8_t i = 0; i < TEST_UINT8; i++) { uint8_t prev_users = pkt->users; ng_pktbuf_hold(pkt, 1); TEST_ASSERT_EQUAL_INT(prev_users + 1, pkt->users); } TEST_ASSERT(!ng_pktbuf_is_empty()); for (uint8_t i = 0; i < TEST_UINT8; i++) { uint8_t prev_users = pkt->users; ng_pktbuf_release(pkt); TEST_ASSERT_EQUAL_INT(prev_users - 1, pkt->users); } TEST_ASSERT(!ng_pktbuf_is_empty()); ng_pktbuf_release(pkt); TEST_ASSERT(ng_pktbuf_is_empty()); }
void ng_icmpv6_echo_req_handle(kernel_pid_t iface, ng_ipv6_hdr_t *ipv6_hdr, ng_icmpv6_echo_t *echo, uint16_t len) { uint8_t *payload = ((uint8_t *)echo) + sizeof(ng_icmpv6_echo_t); ng_pktsnip_t *hdr, *pkt; ng_netreg_entry_t *sendto = NULL; if ((echo == NULL) || (len < sizeof(ng_icmpv6_echo_t))) { DEBUG("icmpv6_echo: echo was NULL or len (%" PRIu16 ") was < sizeof(ng_icmpv6_echo_t)\n", len); return; } pkt = ng_icmpv6_echo_build(NG_ICMPV6_ECHO_REP, byteorder_ntohs(echo->id), byteorder_ntohs(echo->seq), payload, len - sizeof(ng_icmpv6_echo_t)); if (pkt == NULL) { DEBUG("icmpv6_echo: no space left in packet buffer\n"); return; } if (ipv6_addr_is_multicast(&ipv6_hdr->dst)) { hdr = ng_ipv6_hdr_build(pkt, NULL, 0, (uint8_t *)&ipv6_hdr->src, sizeof(ipv6_addr_t)); } else { hdr = ng_ipv6_hdr_build(pkt, (uint8_t *)&ipv6_hdr->dst, sizeof(ipv6_addr_t), (uint8_t *)&ipv6_hdr->src, sizeof(ipv6_addr_t)); } if (hdr == NULL) { DEBUG("icmpv6_echo: no space left in packet buffer\n"); ng_pktbuf_release(pkt); return; } pkt = hdr; hdr = ng_netif_hdr_build(NULL, 0, NULL, 0); ((ng_netif_hdr_t *)hdr->data)->if_pid = iface; LL_PREPEND(pkt, hdr); sendto = ng_netreg_lookup(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL); if (sendto == NULL) { DEBUG("icmpv6_echo: no receivers for IPv6 packets\n"); ng_pktbuf_release(pkt); return; } /* ICMPv6 is not interested anymore so `- 1` */ ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL) - 1); while (sendto != NULL) { ng_netapi_send(sendto->pid, pkt); sendto = ng_netreg_getnext(sendto); } }
void _receive(ng_pktsnip_t *pkt) { ng_pktsnip_t *payload; uint8_t *dispatch; ng_netreg_entry_t *entry; LL_SEARCH_SCALAR(pkt, payload, type, NG_NETTYPE_SIXLOWPAN); if ((payload == NULL) || (payload->size < 1)) { DEBUG("6lo: Received packet has no 6LoWPAN payload\n"); ng_pktbuf_release(pkt); } dispatch = payload->data; if (dispatch[0] == NG_SIXLOWPAN_UNCOMPRESSED) { ng_pktsnip_t *sixlowpan; DEBUG("6lo: received uncompressed IPv6 packet\n"); payload = ng_pktbuf_start_write(payload); if (payload == NULL) { DEBUG("6lo: can not get write access on received packet\n"); #if defined(DEVELHELP) && defined(ENABLE_DEBUG) ng_pktbuf_stats(); #endif ng_pktbuf_release(pkt); return; } /* packet is uncompressed: just mark and remove the dispatch */ sixlowpan = ng_pktbuf_add(payload, payload->data, sizeof(uint8_t), NG_NETTYPE_SIXLOWPAN); LL_DELETE(pkt, sixlowpan); ng_pktbuf_release(sixlowpan); } #ifdef MODULE_NG_SIXLOWPAN_FRAG else if (ng_sixlowpan_frag_is((ng_sixlowpan_frag_t *)dispatch)) { DEBUG("6lo: received 6LoWPAN fragment\n"); ng_sixlowpan_frag_handle_pkt(pkt); } #endif else { DEBUG("6lo: dispatch %02x ... is not supported\n", dispatch[0]); ng_pktbuf_release(pkt); return; } payload->type = NG_NETTYPE_IPV6; entry = ng_netreg_lookup(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL); if (entry == NULL) { DEBUG("ipv6: No receivers for this packet found\n"); ng_pktbuf_release(pkt); return; } ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL) - 1); while (entry) { DEBUG("6lo: Send receive command for %p to %" PRIu16 "\n", (void *)pkt, entry->pid); ng_netapi_receive(entry->pid, pkt); entry = ng_netreg_getnext(entry); } }
static void test_pktbuf_hold__pkt_null(void) { ng_pktbuf_hold(NULL, 1); TEST_ASSERT(ng_pktbuf_is_empty()); }
static void _send_multicast(kernel_pid_t iface, ng_pktsnip_t *pkt, ng_pktsnip_t *ipv6, ng_pktsnip_t *payload, bool prep_hdr) { ng_pktsnip_t *netif; kernel_pid_t ifs[NG_NETIF_NUMOF]; size_t ifnum = 0; if (iface == KERNEL_PID_UNDEF) { /* get list of interfaces */ ifnum = ng_netif_get(ifs); /* throw away packet if no one is interested */ if (ifnum == 0) { DEBUG("ipv6: no interfaces registered, dropping packet\n"); ng_pktbuf_release(pkt); return; } } #if NG_NETIF_NUMOF > 1 /* netif header not present: send over all interfaces */ if (iface == KERNEL_PID_UNDEF) { /* send packet to link layer */ ng_pktbuf_hold(pkt, ifnum - 1); for (size_t i = 0; i < ifnum; i++) { if (prep_hdr) { /* need to get second write access (duplication) to fill IPv6 * header interface-local */ ipv6 = ng_pktbuf_start_write(ipv6); if (ipv6 == NULL) { DEBUG("ipv6: unable to get write access to IPv6 header, " "for interface %" PRIkernel_pid "\n", ifs[i]); ng_pktbuf_release(pkt); return; } if (_fill_ipv6_hdr(ifs[i], ipv6, payload) < 0) { /* error on filling up header */ ng_pktbuf_release(pkt); return; } } /* allocate interface header */ netif = ng_netif_hdr_build(NULL, 0, NULL, 0); if (netif == NULL) { DEBUG("ipv6: error on interface header allocation, " "dropping packet\n"); ng_pktbuf_release(pkt); return; } LL_PREPEND(pkt, netif); _send_multicast_over_iface(ifs[i], pkt, netif); } } else { /* iface != KERNEL_PID_UNDEF implies that netif header is present */ if (prep_hdr) { if (_fill_ipv6_hdr(iface, ipv6, payload) < 0) { /* error on filling up header */ ng_pktbuf_release(pkt); return; } } netif = pkt; _send_multicast_over_iface(iface, pkt, netif); } #else /* NG_NETIF_NUMOF */ (void)ifnum; /* not used in this build branch */ if (iface == KERNEL_PID_UNDEF) { iface = ifs[0]; /* allocate interface header */ netif = ng_netif_hdr_build(NULL, 0, NULL, 0); if (netif == NULL) { DEBUG("ipv6: error on interface header allocation, " "dropping packet\n"); ng_pktbuf_release(pkt); return; } LL_PREPEND(pkt, netif); } else { netif = pkt; } if (prep_hdr) { if (_fill_ipv6_hdr(iface, ipv6, payload) < 0) { /* error on filling up header */ ng_pktbuf_release(pkt); return; } } _send_multicast_over_iface(iface, pkt, netif); #endif /* NG_NETIF_NUMOF */ }
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; }
void ng_icmpv6_demux(kernel_pid_t iface, ng_pktsnip_t *pkt) { ng_pktsnip_t *icmpv6, *ipv6; ng_icmpv6_hdr_t *hdr; ng_netreg_entry_t *sendto; LL_SEARCH_SCALAR(pkt, icmpv6, type, NG_NETTYPE_ICMPV6); /* there can be extension headers between IPv6 and ICMPv6 header so we have * to search it */ LL_SEARCH_SCALAR(icmpv6, ipv6, type, NG_NETTYPE_IPV6); hdr = (ng_icmpv6_hdr_t *)icmpv6->data; if (_calc_csum(icmpv6, ipv6, pkt)) { DEBUG("icmpv6: wrong checksum.\n"); /* don't release: IPv6 does this */ return; } switch (hdr->type) { /* TODO: handle ICMPv6 errors */ #ifdef MODULE_NG_ICMPV6_ECHO case NG_ICMPV6_ECHO_REQ: DEBUG("icmpv6: handle echo request.\n"); ng_icmpv6_echo_req_handle(iface, (ng_ipv6_hdr_t *)ipv6->data, (ng_icmpv6_echo_t *)hdr, icmpv6->size); break; #endif case NG_ICMPV6_RTR_SOL: DEBUG("icmpv6: router solicitation received\n"); /* TODO */ break; case NG_ICMPV6_RTR_ADV: DEBUG("icmpv6: router advertisement received\n"); /* TODO */ break; case NG_ICMPV6_NBR_SOL: DEBUG("icmpv6: neighbor solicitation received\n"); ng_ndp_nbr_sol_handle(iface, pkt, ipv6->data, (ng_ndp_nbr_sol_t *)hdr, icmpv6->size); break; case NG_ICMPV6_NBR_ADV: DEBUG("icmpv6: neighbor advertisement received\n"); ng_ndp_nbr_adv_handle(iface, pkt, ipv6->data, (ng_ndp_nbr_adv_t *)hdr, icmpv6->size); break; case NG_ICMPV6_REDIRECT: DEBUG("icmpv6: redirect message received\n"); /* TODO */ break; #ifdef MODULE_NG_RPL case NG_ICMPV6_RPL_CTRL: DEBUG("icmpv6: RPL control message received\n"); /* TODO */ break; #endif default: DEBUG("icmpv6: unknown type field %" PRIu8 "\n", hdr->type); break; } /* ICMPv6-all will be send in ng_ipv6.c so only dispatch of subtypes is * needed */ sendto = ng_netreg_lookup(NG_NETTYPE_ICMPV6, hdr->type); if (sendto == NULL) { DEBUG("icmpv6: no receivers for ICMPv6 type %" PRIu8 "\n", hdr->type); /* don't release: IPv6 does this */ return; } /* ICMPv6 is not interested anymore so `- 1` */ ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_ICMPV6, hdr->type)); while (sendto != NULL) { ng_netapi_receive(sendto->pid, pkt); sendto = ng_netreg_getnext(sendto); } }