Beispiel #1
0
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;
    }
}
Beispiel #2
0
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;
}
Beispiel #3
0
/* 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);
    }
}
Beispiel #4
0
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);
}
Beispiel #5
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);
        }
    }
}
Beispiel #6
0
/* 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);
    }
}
Beispiel #7
0
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);
    }
}
Beispiel #8
0
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;
}
Beispiel #9
0
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);
    }
}
Beispiel #10
0
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);
}
Beispiel #11
0
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);
    }
}
Beispiel #12
0
/*
 *         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 */
}