static void _pass_on_packet(gnrc_pktsnip_t *pkt) { /* throw away packet if no one is interested */ if (!gnrc_netapi_dispatch_receive(pkt->type, GNRC_NETREG_DEMUX_CTX_ALL, pkt)) { DEBUG("gnrc_netdev2: unable to forward packet of type %i\n", pkt->type); gnrc_pktbuf_release(pkt); return; } }
static enum gnrc_ipv6_ext_demux_status _handle_rh(gnrc_pktsnip_t *current, gnrc_pktsnip_t *pkt) { gnrc_pktsnip_t *ipv6; ipv6_ext_t *ext = (ipv6_ext_t *) current->data; size_t current_offset; ipv6_hdr_t *hdr; /* check seg_left early to avoid duplicating the packet */ if (((ipv6_ext_rh_t *)ext)->seg_left == 0) { return GNRC_IPV6_EXT_OK; } /* We cannot use `gnrc_pktbuf_start_write` since it duplicates only the head. `ipv6_ext_rh_process` modifies the IPv6 header as well as the extension header */ current_offset = gnrc_pkt_len_upto(current->next, GNRC_NETTYPE_IPV6); if (pkt->users != 1) { if ((ipv6 = gnrc_pktbuf_duplicate_upto(pkt, GNRC_NETTYPE_IPV6)) == NULL) { DEBUG("ipv6: could not get a copy of pkt\n"); gnrc_pktbuf_release(pkt); return GNRC_IPV6_EXT_ERROR; } pkt = ipv6; hdr = ipv6->data; ext = (ipv6_ext_t *)(((uint8_t *)ipv6->data) + current_offset); } else { ipv6 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6); hdr = ipv6->data; } switch (ipv6_ext_rh_process(hdr, (ipv6_ext_rh_t *)ext)) { case EXT_RH_CODE_ERROR: /* TODO: send ICMPv6 error codes */ gnrc_pktbuf_release(pkt); return GNRC_IPV6_EXT_ERROR; case EXT_RH_CODE_FORWARD: /* forward packet */ if (!gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, GNRC_NETREG_DEMUX_CTX_ALL, pkt)) { DEBUG("ipv6: could not dispatch packet to the ipv6 thread\n"); gnrc_pktbuf_release(pkt); } return GNRC_IPV6_EXT_FORWARDED; case EXT_RH_CODE_OK: /* this should not happen since we checked seg_left early */ gnrc_pktbuf_release(pkt); return GNRC_IPV6_EXT_ERROR; } return GNRC_IPV6_EXT_OK; }
/* internal functions */ static void _dispatch_next_header(gnrc_pktsnip_t *current, gnrc_pktsnip_t *pkt, uint8_t nh, bool interested) { #ifdef MODULE_GNRC_IPV6_EXT const bool should_dispatch_current_type = ((current->type != GNRC_NETTYPE_IPV6_EXT) || (current->next->type == GNRC_NETTYPE_IPV6)); #else const bool should_dispatch_current_type = (current->next->type == GNRC_NETTYPE_IPV6); #endif DEBUG("ipv6: forward nh = %u to other threads\n", nh); /* dispatch IPv6 extension header only once */ if (should_dispatch_current_type) { bool should_release = (gnrc_netreg_num(GNRC_NETTYPE_IPV6, nh) == 0) && (!interested); if (!should_release) { gnrc_pktbuf_hold(pkt, 1); /* don't remove from packet buffer in * next dispatch */ } if (gnrc_netapi_dispatch_receive(current->type, GNRC_NETREG_DEMUX_CTX_ALL, pkt) == 0) { gnrc_pktbuf_release(pkt); } if (should_release) { return; } } if (interested) { gnrc_pktbuf_hold(pkt, 1); /* don't remove from packet buffer in * next dispatch */ } if (gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, nh, pkt) == 0) { gnrc_pktbuf_release(pkt); } }
bool _inject_packet(const ipv6_addr_t *src, const ipv6_addr_t *dst, uint8_t proto, void *data, size_t data_len, uint16_t netif) { gnrc_pktsnip_t *pkt = _build_ipv6_packet(src, dst, proto, data, data_len, netif); if (pkt == NULL) { return false; } /* put directly in mbox, dispatching to IPv6 would result in the packet * being dropped, since dst is not on any interface */ return (gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, proto, pkt) > 0); }
/** * @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(gnrc_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) { gnrc_pktsnip_t *pkt; /* get pointer to the received packet */ pkt = (gnrc_pktsnip_t *)data; /* send the packet to everyone interested in it's type */ if (!gnrc_netapi_dispatch_receive(pkt->type, GNRC_NETREG_DEMUX_CTX_ALL, pkt)) { DEBUG("nomac: unable to forward packet of type %i\n", pkt->type); gnrc_pktbuf_release(pkt); } } }
/* SLIP receive handler */ static void _slip_receive(gnrc_slip_dev_t *dev, size_t bytes) { gnrc_pktsnip_t *pkt, *hdr; hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0); if (hdr == NULL) { DEBUG("slip: no space left in packet buffer\n"); return; } ((gnrc_netif_hdr_t *)(hdr->data))->if_pid = thread_getpid(); pkt = gnrc_pktbuf_add(hdr, NULL, bytes, GNRC_NETTYPE_UNDEF); if (pkt == NULL) { DEBUG("slip: no space left in packet buffer\n"); gnrc_pktbuf_release(hdr); return; } if (ringbuffer_get(&dev->in_buf, pkt->data, bytes) != bytes) { DEBUG("slip: could not read %u bytes from ringbuffer\n", (unsigned)bytes); gnrc_pktbuf_release(pkt); return; } #if ENABLE_DEBUG && defined(MODULE_OD) else { DEBUG("slip: received data\n"); od_hex_dump(pkt->data, bytes, OD_WIDTH_DEFAULT); } #endif #ifdef MODULE_GNRC_IPV6 if ((pkt->size >= sizeof(ipv6_hdr_t)) && ipv6_hdr_is(pkt->data)) { pkt->type = GNRC_NETTYPE_IPV6; } #endif if (gnrc_netapi_dispatch_receive(pkt->type, GNRC_NETREG_DEMUX_CTX_ALL, pkt) == 0) { DEBUG("slip: unable to forward packet of type %i\n", pkt->type); gnrc_pktbuf_release(pkt); } }
void gnrc_icmpv6_demux(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt) { gnrc_pktsnip_t *icmpv6, *ipv6; icmpv6_hdr_t *hdr; icmpv6 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_ICMPV6); assert(icmpv6 != NULL); /* there can be extension headers between IPv6 and ICMPv6 header so we have * to search it */ ipv6 = gnrc_pktsnip_search_type(icmpv6, GNRC_NETTYPE_IPV6); assert(ipv6 != NULL); if (icmpv6->size < sizeof(icmpv6_hdr_t)) { DEBUG("icmpv6: packet too short.\n"); return; } /* Note: size will be checked again in packet handlers */ hdr = (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_GNRC_ICMPV6_ECHO case ICMPV6_ECHO_REQ: DEBUG("icmpv6: handle echo request.\n"); gnrc_icmpv6_echo_req_handle(netif, (ipv6_hdr_t *)ipv6->data, (icmpv6_echo_t *)hdr, icmpv6->size); break; #endif case ICMPV6_RTR_SOL: case ICMPV6_RTR_ADV: case ICMPV6_NBR_SOL: case ICMPV6_NBR_ADV: case ICMPV6_REDIRECT: case ICMPV6_DAR: case ICMPV6_DAC: DEBUG("icmpv6: NDP message received. Handle with gnrc_ipv6_nib\n"); gnrc_ipv6_nib_handle_pkt(netif, ipv6->data, hdr, icmpv6->size); break; default: DEBUG("icmpv6: unknown type field %u\n", hdr->type); (void)netif; break; } /* ICMPv6-all will be send in gnrc_ipv6.c so only dispatch of subtypes is * needed */ if (!gnrc_netapi_dispatch_receive(GNRC_NETTYPE_ICMPV6, hdr->type, pkt)) { DEBUG("icmpv6: no one interested in type %d\n", hdr->type); gnrc_pktbuf_release(pkt); } }
bool gnrc_ipv6_ext_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt, uint8_t nh) { gnrc_pktsnip_t *ext_snip, *tmp; ipv6_ext_t *ext; unsigned int offset = 0; ipv6_hdr_t *hdr; int res; ext = ((ipv6_ext_t *)(((uint8_t *)pkt->data) + sizeof(ipv6_hdr_t))); bool c = true; while (c) { switch (nh) { case PROTNUM_IPV6_EXT_HOPOPT: case PROTNUM_IPV6_EXT_DST: case PROTNUM_IPV6_EXT_RH: if ((tmp = gnrc_pktbuf_start_write(pkt)) == NULL) { DEBUG("ipv6: could not get a copy of pkt\n"); gnrc_pktbuf_release(pkt); return false; } pkt = tmp; hdr = pkt->data; ext = (ipv6_ext_t *) (((uint8_t *) pkt->data) + sizeof(ipv6_hdr_t) + offset); res = ipv6_ext_rh_process(hdr, (ipv6_ext_rh_t *)ext); if (res == EXT_RH_CODE_ERROR) { /* TODO: send ICMPv6 error codes */ gnrc_pktbuf_release(pkt); return false; } else if (res == EXT_RH_CODE_FORWARD) { /* forward packet */ if (!gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, GNRC_NETREG_DEMUX_CTX_ALL, pkt)) { DEBUG("ipv6: could not dispatch packet to the ipv6 thread\n"); gnrc_pktbuf_release(pkt); } return false; } else if (res == EXT_RH_CODE_OK) { nh = ext->nh; offset += ((ext->len * IPV6_EXT_LEN_UNIT) + IPV6_EXT_LEN_UNIT); ext = ipv6_ext_get_next((ipv6_ext_t *)ext); } break; case PROTNUM_IPV6_EXT_FRAG: case PROTNUM_IPV6_EXT_AH: case PROTNUM_IPV6_EXT_ESP: case PROTNUM_IPV6_EXT_MOB: /* TODO: add handling of types */ nh = ext->nh; offset += ((ext->len * IPV6_EXT_LEN_UNIT) + IPV6_EXT_LEN_UNIT); ext = ipv6_ext_get_next((ipv6_ext_t *)ext); break; default: c = false; offset += ((ext->len * IPV6_EXT_LEN_UNIT) + IPV6_EXT_LEN_UNIT); ext = ipv6_ext_get_next((ipv6_ext_t *)ext); break; } } ext_snip = gnrc_pktbuf_mark(pkt, offset, GNRC_NETTYPE_IPV6); if (ext_snip == NULL) { gnrc_pktbuf_release(pkt); return false; } gnrc_ipv6_demux(iface, pkt, nh); /* demultiplex next header */ return true; }
void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt, size_t frag_size, size_t offset) { rbuf_t *entry; /* cppcheck-suppress variableScope * (reason: cppcheck is clearly wrong here) */ unsigned int data_offset = 0; size_t original_size = frag_size; sixlowpan_frag_t *frag = pkt->data; rbuf_int_t *ptr; uint8_t *data = ((uint8_t *)pkt->data) + sizeof(sixlowpan_frag_t); _rbuf_gc(); entry = _rbuf_get(gnrc_netif_hdr_get_src_addr(netif_hdr), netif_hdr->src_l2addr_len, gnrc_netif_hdr_get_dst_addr(netif_hdr), netif_hdr->dst_l2addr_len, byteorder_ntohs(frag->disp_size) & 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] == SIXLOWPAN_UNCOMP) { data++; /* skip 6LoWPAN dispatch */ frag_size--; } #ifdef MODULE_GNRC_SIXLOWPAN_IPHC else if (sixlowpan_iphc_is(data)) { size_t iphc_len, nh_len = 0; iphc_len = gnrc_sixlowpan_iphc_decode(&entry->pkt, pkt, entry->pkt->size, sizeof(sixlowpan_frag_t), &nh_len); if (iphc_len == 0) { DEBUG("6lo rfrag: could not decode IPHC dispatch\n"); gnrc_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 */ /* but add IPv6 header + next header lengths */ frag_size += sizeof(ipv6_hdr_t) + nh_len; /* start copying after IPv6 header and next headers */ data_offset += sizeof(ipv6_hdr_t) + nh_len; } #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"); gnrc_pktbuf_release(entry->pkt); _rbuf_rem(entry); return; } /* If the fragment overlaps another fragment and differs in either the size * or the offset of the overlapped fragment, discards the datagram * https://tools.ietf.org/html/rfc4944#section-5.3 */ while (ptr != NULL) { if (_rbuf_int_overlap_partially(ptr, offset, offset + frag_size - 1)) { DEBUG("6lo rfrag: overlapping intervals, discarding datagram\n"); gnrc_pktbuf_release(entry->pkt); _rbuf_rem(entry); /* "A fresh reassembly may be commenced with the most recently * received link fragment" * https://tools.ietf.org/html/rfc4944#section-5.3 */ rbuf_add(netif_hdr, pkt, original_size, offset); 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) { gnrc_pktsnip_t *netif = gnrc_netif_hdr_build(entry->src, entry->src_len, entry->dst, entry->dst_len); if (netif == NULL) { DEBUG("6lo rbuf: error allocating netif header\n"); gnrc_pktbuf_release(entry->pkt); _rbuf_rem(entry); return; } /* copy the transmit information of the latest fragment into the newly * created header to have some link_layer information. The link_layer * info of the previous fragments is discarded. */ gnrc_netif_hdr_t *new_netif_hdr = netif->data; new_netif_hdr->if_pid = netif_hdr->if_pid; new_netif_hdr->flags = netif_hdr->flags; new_netif_hdr->lqi = netif_hdr->lqi; new_netif_hdr->rssi = netif_hdr->rssi; LL_APPEND(entry->pkt, netif); if (!gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, GNRC_NETREG_DEMUX_CTX_ALL, entry->pkt)) { DEBUG("6lo rbuf: No receivers for this packet found\n"); gnrc_pktbuf_release(entry->pkt); } _rbuf_rem(entry); } }
static void _send_packet(void) { gnrc_netif_t *netif = gnrc_netif_iter(NULL); struct { gnrc_netif_hdr_t netif_hdr; uint8_t src[8]; uint8_t dst[8]; } netif_hdr = { .src = IEEE802154_REMOTE_EUI64, .dst = IEEE802154_LOCAL_EUI64, }; gnrc_netif_hdr_init(&(netif_hdr.netif_hdr), 8, 8); netif_hdr.netif_hdr.if_pid = netif->pid; uint8_t data1[] = { /* 6LoWPAN Header */ /* Fragmentation Header (first) */ 0xc0, 0x94, /* 0b11000: frag1, 0b00010010100: datagram_size (148) */ 0x00, 0x01, /* datagram_tag */ /* 0b011: LOWPAN_IPHC */ /* 0b11: Traffic Class and Flow Label are elided */ /* 0b1: Next Header is compressed */ /* 0b11: The Hop Limit field is compressed and the hop limit is 255 */ 0x7f, /* 0b0: No additional 8-bit Context Identifier Extension is used */ /* 0b0: Source address compression uses stateless compression */ /* 0b11: source address mode is 0 bits */ /* 0b0: Destination address is not a multicast address */ /* 0x0: Destination address compression uses stateless compression */ /* 0x00: destination address mode is 128 bits */ 0x30, /* destination address: fd01::1 */ 0xfd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* 0b11110: UDP LOWPAN_NHC */ /* 0b0: Checksum is carried in-line */ /* 0b11: First 12 bits of both Source Port and Destination Port are 0xf0b and elided */ 0xf3, 0x00, /* Source Port and Destination Port (4 bits each) */ 0x23, 0x2f, /* Checksum */ /* payload */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; uint8_t data2[] = { /* 6LoWPAN Header */ /* Fragmentation Header (rest) */ 0xe0, 0x94, /* 0b11100: frag1, 0b00010010100: datagram_size (148) */ 0x00, 0x01, /* datagram_tag */ 0x0c, /* datagram_offset (12 * 8 = 96) */ /* payload */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; gnrc_netreg_entry_t dump_6lowpan = GNRC_NETREG_ENTRY_INIT_PID(GNRC_NETREG_DEMUX_CTX_ALL, gnrc_pktdump_pid); gnrc_netreg_entry_t dump_ipv6 = GNRC_NETREG_ENTRY_INIT_PID(GNRC_NETREG_DEMUX_CTX_ALL, gnrc_pktdump_pid); gnrc_netreg_entry_t dump_udp = GNRC_NETREG_ENTRY_INIT_PID(GNRC_NETREG_DEMUX_CTX_ALL, gnrc_pktdump_pid); gnrc_netreg_entry_t dump_udp_61616 = GNRC_NETREG_ENTRY_INIT_PID(61616, gnrc_pktdump_pid); gnrc_netreg_register(GNRC_NETTYPE_SIXLOWPAN, &dump_6lowpan); gnrc_netreg_register(GNRC_NETTYPE_IPV6, &dump_ipv6); gnrc_netreg_register(GNRC_NETTYPE_UDP, &dump_udp); gnrc_netreg_register(GNRC_NETTYPE_UDP, &dump_udp_61616); gnrc_pktsnip_t *netif1 = gnrc_pktbuf_add(NULL, &netif_hdr, sizeof(netif_hdr), GNRC_NETTYPE_NETIF); gnrc_pktsnip_t *pkt1 = gnrc_pktbuf_add(netif1, data1, sizeof(data1), GNRC_NETTYPE_SIXLOWPAN); gnrc_netapi_dispatch_receive(GNRC_NETTYPE_SIXLOWPAN, GNRC_NETREG_DEMUX_CTX_ALL, pkt1); gnrc_pktsnip_t *netif2 = gnrc_pktbuf_add(NULL, &netif_hdr, sizeof(netif_hdr), GNRC_NETTYPE_NETIF); gnrc_pktsnip_t *pkt2 = gnrc_pktbuf_add(netif2, data2, sizeof(data2), GNRC_NETTYPE_SIXLOWPAN); gnrc_netapi_dispatch_receive(GNRC_NETTYPE_SIXLOWPAN, GNRC_NETREG_DEMUX_CTX_ALL, pkt2); }
static void _receive(gnrc_pktsnip_t *pkt) { gnrc_pktsnip_t *payload; uint8_t *dispatch; /* seize payload as a temporary variable */ payload = gnrc_pktbuf_start_write(pkt); /* need to duplicate since pkt->next * might get replaced */ if (payload == NULL) { DEBUG("6lo: can not get write access on received packet\n"); #if defined(DEVELHELP) && ENABLE_DEBUG gnrc_pktbuf_stats(); #endif gnrc_pktbuf_release(pkt); return; } pkt = payload; /* reset pkt from temporary variable */ payload = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_SIXLOWPAN); if ((payload == NULL) || (payload->size < 1)) { DEBUG("6lo: Received packet has no 6LoWPAN payload\n"); gnrc_pktbuf_release(pkt); return; } dispatch = payload->data; if (dispatch[0] == SIXLOWPAN_UNCOMP) { gnrc_pktsnip_t *sixlowpan; DEBUG("6lo: received uncompressed IPv6 packet\n"); payload = gnrc_pktbuf_start_write(payload); if (payload == NULL) { DEBUG("6lo: can not get write access on received packet\n"); #if defined(DEVELHELP) && ENABLE_DEBUG gnrc_pktbuf_stats(); #endif gnrc_pktbuf_release(pkt); return; } /* packet is uncompressed: just mark and remove the dispatch */ sixlowpan = gnrc_pktbuf_mark(payload, sizeof(uint8_t), GNRC_NETTYPE_SIXLOWPAN); if (sixlowpan == NULL) { DEBUG("6lo: can not mark 6LoWPAN dispatch\n"); gnrc_pktbuf_release(pkt); return; } pkt = gnrc_pktbuf_remove_snip(pkt, sixlowpan); payload->type = GNRC_NETTYPE_IPV6; } #ifdef MODULE_GNRC_SIXLOWPAN_FRAG else if (sixlowpan_frag_is((sixlowpan_frag_t *)dispatch)) { DEBUG("6lo: received 6LoWPAN fragment\n"); gnrc_sixlowpan_frag_handle_pkt(pkt); return; } #endif #ifdef MODULE_GNRC_SIXLOWPAN_IPHC else if (sixlowpan_iphc_is(dispatch)) { size_t dispatch_size, nh_len; gnrc_pktsnip_t *sixlowpan; gnrc_pktsnip_t *dec_hdr = gnrc_pktbuf_add(NULL, NULL, sizeof(ipv6_hdr_t), GNRC_NETTYPE_IPV6); if ((dec_hdr == NULL) || (dispatch_size = gnrc_sixlowpan_iphc_decode(&dec_hdr, pkt, 0, 0, &nh_len)) == 0) { DEBUG("6lo: error on IPHC decoding\n"); if (dec_hdr != NULL) { gnrc_pktbuf_release(dec_hdr); } gnrc_pktbuf_release(pkt); return; } sixlowpan = gnrc_pktbuf_mark(pkt, dispatch_size, GNRC_NETTYPE_SIXLOWPAN); if (sixlowpan == NULL) { DEBUG("6lo: error on marking IPHC dispatch\n"); gnrc_pktbuf_release(dec_hdr); gnrc_pktbuf_release(pkt); return; } /* Remove IPHC dispatches */ /* Insert decoded header instead */ pkt = gnrc_pktbuf_replace_snip(pkt, sixlowpan, dec_hdr); payload->type = GNRC_NETTYPE_UNDEF; } #endif else { DEBUG("6lo: dispatch %02" PRIx8 " ... is not supported\n", dispatch[0]); gnrc_pktbuf_release(pkt); return; } if (!gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, GNRC_NETREG_DEMUX_CTX_ALL, pkt)) { DEBUG("6lo: No receivers for this packet found\n"); gnrc_pktbuf_release(pkt); } }
/* * current pkt * | | * v v * IPv6 <- IPv6_EXT <- IPv6_EXT <- UNDEF */ void gnrc_ipv6_ext_demux(kernel_pid_t iface, gnrc_pktsnip_t *current, gnrc_pktsnip_t *pkt, uint8_t nh) { ipv6_ext_t *ext; while (true) { ext = (ipv6_ext_t *) current->data; switch (nh) { case PROTNUM_IPV6_EXT_RH: #ifdef MODULE_GNRC_RPL_SRH switch (_handle_rh(current, pkt)) { case GNRC_IPV6_EXT_OK: /* We are the final destination. So proceeds like normal packet. */ nh = ext->nh; DEBUG("ipv6_ext: next header = %" PRIu8 "\n", nh); if ((current = _mark_extension_header(current, &pkt)) == NULL) { return; } gnrc_ipv6_demux(iface, current, pkt, nh); /* demultiplex next header */ return; case GNRC_IPV6_EXT_ERROR: /* already released by _handle_rh, so no release here */ return; case GNRC_IPV6_EXT_FORWARDED: /* the packet is forwarded and released. finish processing */ return; } break; #endif case PROTNUM_IPV6_EXT_HOPOPT: case PROTNUM_IPV6_EXT_DST: case PROTNUM_IPV6_EXT_FRAG: case PROTNUM_IPV6_EXT_AH: case PROTNUM_IPV6_EXT_ESP: case PROTNUM_IPV6_EXT_MOB: /* TODO: add handling of types */ nh = ext->nh; DEBUG("ipv6_ext: next header = %" PRIu8 "\n", nh); if ((current = _mark_extension_header(current, &pkt)) == NULL) { return; } gnrc_pktbuf_hold(pkt, 1); /* don't release on next dispatch */ if (gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, nh, pkt) == 0) { gnrc_pktbuf_release(pkt); } break; default: gnrc_ipv6_demux(iface, current, pkt, nh); /* demultiplex next header */ return; } } assert(false); /* never reaches here */ }