/* functions for sending */ static void _send_unicast(kernel_pid_t iface, uint8_t *dst_l2addr, uint16_t dst_l2addr_len, ng_pktsnip_t *pkt) { ng_pktsnip_t *netif; if (pkt->type == NG_NETTYPE_NETIF) { /* great: someone already added a netif_hdr_t we assume it's wrong * to keep it simple * XXX: alternative would be to check if ng_netif_hdr_t::dst_l2addr_len * is long enough and only then to throw away the header. This causes * to much overhead IMHO */ DEBUG("ipv6: removed old interface header\n"); pkt = ng_pktbuf_remove_snip(pkt, pkt); } DEBUG("ipv6: add to interface header to packet\n"); netif = ng_netif_hdr_build(NULL, 0, dst_l2addr, dst_l2addr_len); if (netif == NULL) { DEBUG("ipv6: error on interface header allocation, dropping packet\n"); ng_pktbuf_release(pkt); return; } /* add netif to front of the pkt list */ LL_PREPEND(pkt, netif); DEBUG("ipv6: send unicast over interface %" PRIkernel_pid "\n", iface); /* and send to interface */ _send_to_iface(iface, pkt); }
static ng_pktsnip_t *_build_frag_pkt(ng_pktsnip_t *pkt, size_t payload_len, size_t size) { ng_netif_hdr_t *hdr = pkt->data, *new_hdr; ng_pktsnip_t *netif, *frag; netif = ng_netif_hdr_build(ng_netif_hdr_get_src_addr(hdr), hdr->src_l2addr_len, ng_netif_hdr_get_dst_addr(hdr), hdr->dst_l2addr_len); if (netif == NULL) { DEBUG("6lo frag: error allocating new link-layer header\n"); return NULL; } new_hdr = netif->data; new_hdr->if_pid = hdr->if_pid; new_hdr->flags = hdr->flags; new_hdr->rssi = hdr->rssi; new_hdr->lqi = hdr->lqi; frag = ng_pktbuf_add(NULL, NULL, _min(size, payload_len), NG_NETTYPE_SIXLOWPAN); if (frag == NULL) { DEBUG("6lo frag: error allocating first fragment\n"); ng_pktbuf_release(netif); return NULL; } LL_PREPEND(frag, netif); return frag; }
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); } }
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 _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); }
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 */ }
void rbuf_add(ng_netif_hdr_t *netif_hdr, ng_pktsnip_t *pkt, size_t frag_size, size_t offset) { rbuf_t *entry; /* cppcheck is clearly wrong here */ /* cppcheck-suppress variableScope */ unsigned int data_offset = 0; ng_sixlowpan_frag_t *frag = pkt->data; rbuf_int_t *ptr; uint8_t *data = ((uint8_t *)pkt->data) + sizeof(ng_sixlowpan_frag_t); _rbuf_gc(); entry = _rbuf_get(ng_netif_hdr_get_src_addr(netif_hdr), netif_hdr->src_l2addr_len, ng_netif_hdr_get_dst_addr(netif_hdr), netif_hdr->dst_l2addr_len, byteorder_ntohs(frag->disp_size) & NG_SIXLOWPAN_FRAG_SIZE_MASK, byteorder_ntohs(frag->tag)); if (entry == NULL) { DEBUG("6lo rbuf: reassembly buffer full.\n"); return; } ptr = entry->ints; /* dispatches in the first fragment are ignored */ if (offset == 0) { if (data[0] == NG_SIXLOWPAN_UNCOMPRESSED) { data++; /* skip 6LoWPAN dispatch */ frag_size--; } #ifdef MODULE_NG_SIXLOWPAN_IPHC else if (ng_sixlowpan_iphc_is(data)) { size_t iphc_len; iphc_len = ng_sixlowpan_iphc_decode(entry->pkt, pkt, sizeof(ng_sixlowpan_frag_t)); if (iphc_len == 0) { DEBUG("6lo rfrag: could not decode IPHC dispatch\n"); ng_pktbuf_release(entry->pkt); _rbuf_rem(entry); return; } data += iphc_len; /* take remaining data as data */ frag_size -= iphc_len; /* and reduce frag size by IPHC dispatch length */ frag_size += sizeof(ipv6_hdr_t); /* but add IPv6 header length */ data_offset += sizeof(ipv6_hdr_t); /* start copying after IPv6 header */ } #endif } else { data++; /* FRAGN header is one byte longer (offset) */ } if ((offset + frag_size) > entry->pkt->size) { DEBUG("6lo rfrag: fragment too big for resulting datagram, discarding datagram\n"); ng_pktbuf_release(entry->pkt); _rbuf_rem(entry); return; } while (ptr != NULL) { if (_rbuf_int_in(ptr, offset, offset + frag_size - 1)) { DEBUG("6lo rfrag: overlapping or same intervals, discarding datagram\n"); ng_pktbuf_release(entry->pkt); _rbuf_rem(entry); return; } ptr = ptr->next; } if (_rbuf_update_ints(entry, offset, frag_size)) { DEBUG("6lo rbuf: add fragment data\n"); entry->cur_size += (uint16_t)frag_size; memcpy(((uint8_t *)entry->pkt->data) + offset + data_offset, data, frag_size - data_offset); } if (entry->cur_size == entry->pkt->size) { kernel_pid_t iface = netif_hdr->if_pid; ng_pktsnip_t *netif = ng_netif_hdr_build(entry->src, entry->src_len, entry->dst, entry->dst_len); if (netif == NULL) { DEBUG("6lo rbuf: error allocating netif header\n"); ng_pktbuf_release(entry->pkt); _rbuf_rem(entry); return; } netif_hdr = netif->data; netif_hdr->if_pid = iface; LL_APPEND(entry->pkt, netif); if (!ng_netapi_dispatch_receive(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL, entry->pkt)) { DEBUG("6lo rbuf: No receivers for this packet found\n"); ng_pktbuf_release(entry->pkt); } _rbuf_rem(entry); } }
void rbuf_add(ng_netif_hdr_t *netif_hdr, ng_sixlowpan_frag_t *frag, size_t frag_size, size_t offset) { rbuf_t *entry; rbuf_int_t *ptr; uint8_t *data = ((uint8_t *)frag) + sizeof(ng_sixlowpan_frag_t); uint16_t dg_frag_size = frag_size; /* may differ on first fragment */ _rbuf_gc(); entry = _rbuf_get(ng_netif_hdr_get_src_addr(netif_hdr), netif_hdr->src_l2addr_len, ng_netif_hdr_get_dst_addr(netif_hdr), netif_hdr->dst_l2addr_len, byteorder_ntohs(frag->disp_size) & NG_SIXLOWPAN_FRAG_SIZE_MASK, byteorder_ntohs(frag->tag)); if (entry == NULL) { DEBUG("6lo rbuf: reassembly buffer full.\n"); return; } ptr = entry->ints; /* dispatches in the first fragment are ignored */ if (offset != 0) { switch (((uint8_t *)(entry->pkt->data))[0]) { case NG_SIXLOWPAN_UNCOMPRESSED: offset++; break; default: break; } data++; /* also don't take offset field */ } else { switch (data[0]) { case NG_SIXLOWPAN_UNCOMPRESSED: dg_frag_size--; break; default: break; } } if ((offset + frag_size) > entry->pkt->size) { DEBUG("6lo rfrag: fragment too big for resulting datagram, discarding datagram\n"); ng_pktbuf_release(entry->pkt); _rbuf_rem(entry); return; } while (ptr != NULL) { if (_rbuf_int_in(ptr, offset, offset + dg_frag_size - 1)) { DEBUG("6lo rfrag: overlapping or same intervals, discarding datagram\n"); ng_pktbuf_release(entry->pkt); _rbuf_rem(entry); return; } ptr = ptr->next; } if (_rbuf_update_ints(entry, offset, dg_frag_size)) { if (dg_frag_size < frag_size) { /* some dispatches do not count to datagram size and we need * more space because of that */ if (ng_pktbuf_realloc_data(entry->pkt, entry->pkt->size + (frag_size - dg_frag_size)) < 0) { DEBUG("6lo rbuf: could not reallocate packet data.\n"); return; } /* move already inserted fragments (frag_size - dg_frag_size) to the right */ if (entry->cur_size > 0) { for (int i = entry->pkt->size - (frag_size - dg_frag_size); i > 0; i--) { uint8_t *d = ((uint8_t *)(entry->pkt->data)) + i; *d = *(d - 1); } } } DEBUG("6lo rbuf: add fragment data\n"); entry->cur_size += (uint16_t)dg_frag_size; memcpy(((uint8_t *)entry->pkt->data) + offset, data, frag_size); } if (entry->cur_size == entry->datagram_size) { kernel_pid_t iface = netif_hdr->if_pid; ng_pktsnip_t *netif = ng_netif_hdr_build(entry->src, entry->src_len, entry->dst, entry->dst_len); if (netif == NULL) { DEBUG("6lo rbuf: error allocating netif header\n"); ng_pktbuf_release(entry->pkt); return; } netif_hdr = netif->data; netif_hdr->if_pid = iface; LL_APPEND(entry->pkt, netif); DEBUG("6lo rbuf: datagram complete, send to self\n"); ng_netapi_receive(thread_getpid(), entry->pkt); _rbuf_rem(entry); } }