Esempio n. 1
0
static void test_pktbuf_start_write__pkt_users_1(void)
{
    gnrc_pktsnip_t *pkt_copy, *pkt = gnrc_pktbuf_add(NULL, TEST_STRING16, sizeof(TEST_STRING16),
                                                     GNRC_NETTYPE_TEST);

    TEST_ASSERT_NOT_NULL((pkt_copy = gnrc_pktbuf_start_write(pkt)));
    TEST_ASSERT(pkt == pkt_copy);
    gnrc_pktbuf_release(pkt);
    TEST_ASSERT(gnrc_pktbuf_is_empty());
}
Esempio n. 2
0
static void test_pktbuf_start_write__pkt_users_2(void)
{
    gnrc_pktsnip_t *pkt_copy, *pkt = gnrc_pktbuf_add(NULL, TEST_STRING16, sizeof(TEST_STRING16),
                                                     GNRC_NETTYPE_TEST);

    gnrc_pktbuf_hold(pkt, 1);
    TEST_ASSERT_NOT_NULL((pkt_copy = gnrc_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);

    gnrc_pktbuf_release(pkt_copy);
    gnrc_pktbuf_release(pkt);
    TEST_ASSERT(gnrc_pktbuf_is_empty());
}
Esempio n. 3
0
/**
 * @brief marks IPv6 extension header if needed.
 *   updates pkt and returns next header.
 * @param[in] current  The current header
 * @param[in,out] pkt  The whole packet
 * @return The next header
 * @return NULL on error
 */
static gnrc_pktsnip_t *_mark_extension_header(gnrc_pktsnip_t *current,
                                              gnrc_pktsnip_t **pkt)
{
    gnrc_pktsnip_t *ext_snip, *tmp, *next;
    ipv6_ext_t *ext = (ipv6_ext_t *) current->data;
    size_t offset = ((ext->len * IPV6_EXT_LEN_UNIT) + IPV6_EXT_LEN_UNIT);

    if (current == *pkt) {
        if ((tmp = gnrc_pktbuf_start_write(*pkt)) == NULL) {
            DEBUG("ipv6: could not get a copy of pkt\n");
            gnrc_pktbuf_release(*pkt);
            return NULL;
        }
        *pkt = tmp;

        ext_snip = gnrc_pktbuf_mark(*pkt, offset, GNRC_NETTYPE_IPV6_EXT);
        next = *pkt;

        if (ext_snip == NULL) {
            gnrc_pktbuf_release(*pkt);
            return NULL;
        }
    }
    else {
        /* the header is already marked */

        next = NULL;

        for (tmp = *pkt; tmp != NULL; tmp = tmp->next) {
            if (tmp->next == current) {
                next = tmp;
                break;
            }
        }

        assert(next != NULL);
    }

    return next;
}
Esempio n. 4
0
static void test_pktbuf_start_write__NULL(void)
{
    gnrc_pktbuf_start_write(NULL);
    TEST_ASSERT(gnrc_pktbuf_is_empty());
}
Esempio n. 5
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;
}
Esempio n. 6
0
static void _receive(gnrc_pktsnip_t *pkt)
{
    kernel_pid_t iface = KERNEL_PID_UNDEF;
    gnrc_pktsnip_t *ipv6, *netif, *first_ext;
    ipv6_hdr_t *hdr;

    assert(pkt != NULL);

    netif = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF);

    if (netif != NULL) {
        iface = ((gnrc_netif_hdr_t *)netif->data)->if_pid;

#ifdef MODULE_NETSTATS_IPV6
        assert(iface);
        netstats_t *stats = gnrc_ipv6_netif_get_stats(iface);
        stats->rx_count++;
        stats->rx_bytes += (gnrc_pkt_len(pkt) - netif->size);
#endif
    }

    first_ext = pkt;

    for (ipv6 = pkt; ipv6 != NULL; ipv6 = ipv6->next) { /* find IPv6 header if already marked */
        if ((ipv6->type == GNRC_NETTYPE_IPV6) && (ipv6->size == sizeof(ipv6_hdr_t)) &&
            (ipv6_hdr_is(ipv6->data))) {
            break;
        }

        first_ext = ipv6;
    }

    if (ipv6 == NULL) {
        if (!ipv6_hdr_is(pkt->data)) {
            DEBUG("ipv6: Received packet was not IPv6, dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
#ifdef MODULE_GNRC_IPV6_WHITELIST
        if (!gnrc_ipv6_whitelisted(&((ipv6_hdr_t *)(pkt->data))->src)) {
            DEBUG("ipv6: Source address not whitelisted, dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
#endif
#ifdef MODULE_GNRC_IPV6_BLACKLIST
        if (gnrc_ipv6_blacklisted(&((ipv6_hdr_t *)(pkt->data))->src)) {
            DEBUG("ipv6: Source address blacklisted, dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
#endif
        /* seize ipv6 as a temporary variable */
        ipv6 = gnrc_pktbuf_start_write(pkt);

        if (ipv6 == NULL) {
            DEBUG("ipv6: unable to get write access to packet, drop it\n");
            gnrc_pktbuf_release(pkt);
            return;
        }

        pkt = ipv6;     /* reset pkt from temporary variable */

        ipv6 = gnrc_pktbuf_mark(pkt, sizeof(ipv6_hdr_t), GNRC_NETTYPE_IPV6);

        first_ext = pkt;
        pkt->type = GNRC_NETTYPE_UNDEF; /* snip is no longer IPv6 */

        if (ipv6 == NULL) {
            DEBUG("ipv6: error marking IPv6 header, dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
    }
#ifdef MODULE_GNRC_IPV6_WHITELIST
    else if (!gnrc_ipv6_whitelisted(&((ipv6_hdr_t *)(ipv6->data))->src)) {
        /* if ipv6 header already marked*/
        DEBUG("ipv6: Source address not whitelisted, dropping packet\n");
        gnrc_pktbuf_release(pkt);
        return;
    }
#endif
#ifdef MODULE_GNRC_IPV6_BLACKLIST
    else if (gnrc_ipv6_blacklisted(&((ipv6_hdr_t *)(ipv6->data))->src)) {
        /* if ipv6 header already marked*/
        DEBUG("ipv6: Source address blacklisted, dropping packet\n");
        gnrc_pktbuf_release(pkt);
        return;
    }
#endif

    /* extract header */
    hdr = (ipv6_hdr_t *)ipv6->data;

    /* if available, remove any padding that was added by lower layers
     * to fulfill their minimum size requirements (e.g. ethernet) */
    if (byteorder_ntohs(hdr->len) < pkt->size) {
        gnrc_pktbuf_realloc_data(pkt, byteorder_ntohs(hdr->len));
    }
    else if (byteorder_ntohs(hdr->len) >
             (gnrc_pkt_len_upto(pkt, GNRC_NETTYPE_IPV6) - sizeof(ipv6_hdr_t))) {
        DEBUG("ipv6: invalid payload length: %d, actual: %d, dropping packet\n",
              (int) byteorder_ntohs(hdr->len),
              (int) (gnrc_pkt_len_upto(pkt, GNRC_NETTYPE_IPV6) - sizeof(ipv6_hdr_t)));
        gnrc_pktbuf_release(pkt);
        return;
    }

    DEBUG("ipv6: Received (src = %s, ",
          ipv6_addr_to_str(addr_str, &(hdr->src), sizeof(addr_str)));
    DEBUG("dst = %s, next header = %u, length = %" PRIu16 ")\n",
          ipv6_addr_to_str(addr_str, &(hdr->dst), sizeof(addr_str)),
          hdr->nh, byteorder_ntohs(hdr->len));

    if (_pkt_not_for_me(&iface, hdr)) { /* if packet is not for me */
        DEBUG("ipv6: packet destination not this host\n");

#ifdef MODULE_GNRC_IPV6_ROUTER    /* only routers redirect */
        /* redirect to next hop */
        DEBUG("ipv6: decrement hop limit to %u\n", (uint8_t) (hdr->hl - 1));

        /* RFC 4291, section 2.5.6 states: "Routers must not forward any
         * packets with Link-Local source or destination addresses to other
         * links."
         */
        if ((ipv6_addr_is_link_local(&(hdr->src))) || (ipv6_addr_is_link_local(&(hdr->dst)))) {
            DEBUG("ipv6: do not forward packets with link-local source or"
                  " destination address\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
        /* TODO: check if receiving interface is router */
        else if (--(hdr->hl) > 0) {  /* drop packets that *reach* Hop Limit 0 */
            gnrc_pktsnip_t *reversed_pkt = NULL, *ptr = pkt;

            DEBUG("ipv6: forward packet to next hop\n");

            /* pkt might not be writable yet, if header was given above */
            ipv6 = gnrc_pktbuf_start_write(ipv6);
            if (ipv6 == NULL) {
                DEBUG("ipv6: unable to get write access to packet: dropping it\n");
                gnrc_pktbuf_release(pkt);
                return;
            }

            /* remove L2 headers around IPV6 */
            netif = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF);
            if (netif != NULL) {
                gnrc_pktbuf_remove_snip(pkt, netif);
            }

            /* reverse packet snip list order */
            while (ptr != NULL) {
                gnrc_pktsnip_t *next;
                ptr = gnrc_pktbuf_start_write(ptr);     /* duplicate if not already done */
                if (ptr == NULL) {
                    DEBUG("ipv6: unable to get write access to packet: dropping it\n");
                    gnrc_pktbuf_release(reversed_pkt);
                    gnrc_pktbuf_release(pkt);
                    return;
                }
                next = ptr->next;
                ptr->next = reversed_pkt;
                reversed_pkt = ptr;
                ptr = next;
            }
            _send(reversed_pkt, false);
            return;
        }
        else {
            DEBUG("ipv6: hop limit reached 0: drop packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }

#else  /* MODULE_GNRC_IPV6_ROUTER */
        DEBUG("ipv6: dropping packet\n");
        /* non rounting hosts just drop the packet */
        gnrc_pktbuf_release(pkt);
        return;
#endif /* MODULE_GNRC_IPV6_ROUTER */
    }

    /* IPv6 internal demuxing (ICMPv6, Extension headers etc.) */
    gnrc_ipv6_demux(iface, first_ext, pkt, hdr->nh);
}
Esempio n. 7
0
static void _send(gnrc_pktsnip_t *pkt, bool prep_hdr)
{
    kernel_pid_t iface = KERNEL_PID_UNDEF;
    gnrc_pktsnip_t *ipv6, *payload;
    ipv6_addr_t *tmp;
    ipv6_hdr_t *hdr;
    /* get IPv6 snip and (if present) generic interface header */
    if (pkt->type == GNRC_NETTYPE_NETIF) {
        /* If there is already a netif header (routing protocols and
         * neighbor discovery might add them to preset sending interface) */
        iface = ((gnrc_netif_hdr_t *)pkt->data)->if_pid;
        /* seize payload as temporary variable */
        ipv6 = gnrc_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");
            gnrc_pktbuf_release(pkt);
            return;
        }
        pkt = ipv6;  /* Reset pkt from temporary variable */

        ipv6 = pkt->next;
    }
    else {
        ipv6 = pkt;
    }
    /* seize payload as temporary variable */
    payload = gnrc_pktbuf_start_write(ipv6);
    if (payload == NULL) {
        DEBUG("ipv6: unable to get write access to IPv6 header, dropping packet\n");
        gnrc_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 */
    }
    else {
        pkt = payload;      /* pkt is the IPv6 header so we just write-protected it */
    }
    ipv6 = payload;  /* Reset ipv6 from temporary variable */

    hdr = ipv6->data;
    payload = ipv6->next;

    if (ipv6_addr_is_multicast(&hdr->dst)) {
        _send_multicast(iface, pkt, ipv6, payload, prep_hdr);
    }
    else if ((ipv6_addr_is_loopback(&hdr->dst)) ||      /* dst is loopback address */
             ((iface == KERNEL_PID_UNDEF) && /* or dst registered to any local interface */
              ((iface = gnrc_ipv6_netif_find_by_addr(&tmp, &hdr->dst)) != KERNEL_PID_UNDEF)) ||
             ((iface != KERNEL_PID_UNDEF) && /* or dst registered to given interface */
              (gnrc_ipv6_netif_find_addr(iface, &hdr->dst) != NULL))) {
        uint8_t *rcv_data;
        gnrc_pktsnip_t *ptr = ipv6, *rcv_pkt;

        if (prep_hdr) {
            if (_fill_ipv6_hdr(iface, ipv6, payload) < 0) {
                /* error on filling up header */
                gnrc_pktbuf_release(pkt);
                return;
            }
        }

        rcv_pkt = gnrc_pktbuf_add(NULL, NULL, gnrc_pkt_len(ipv6), GNRC_NETTYPE_IPV6);

        if (rcv_pkt == NULL) {
            DEBUG("ipv6: error on generating loopback packet\n");
            gnrc_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;
        }

        gnrc_pktbuf_release(pkt);

        DEBUG("ipv6: packet is addressed to myself => loopback\n");

        if (gnrc_netapi_receive(gnrc_ipv6_pid, rcv_pkt) < 1) {
            DEBUG("ipv6: unable to deliver packet\n");
            gnrc_pktbuf_release(rcv_pkt);
        }
    }
    else {
        uint8_t l2addr_len = GNRC_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");
            gnrc_pktbuf_release(pkt);
            return;
        }

        if (prep_hdr) {
            if (_fill_ipv6_hdr(iface, ipv6, payload) < 0) {
                /* error on filling up header */
                gnrc_pktbuf_release(pkt);
                return;
            }
        }

        _send_unicast(iface, l2addr, l2addr_len, pkt);
    }
}
Esempio n. 8
0
static void _send_multicast(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
                            gnrc_pktsnip_t *ipv6, gnrc_pktsnip_t *payload,
                            bool prep_hdr)
{
    kernel_pid_t ifs[GNRC_NETIF_NUMOF];
    size_t ifnum = 0;

    if (iface == KERNEL_PID_UNDEF) {
        /* get list of interfaces */
        ifnum = gnrc_netif_get(ifs);

        /* throw away packet if no one is interested */
        if (ifnum == 0) {
            DEBUG("ipv6: no interfaces registered, dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
    }


#if GNRC_NETIF_NUMOF > 1
    /* netif header not present: send over all interfaces */
    if (iface == KERNEL_PID_UNDEF) {
        assert(pkt == ipv6);
        /* send packet to link layer */
        gnrc_pktbuf_hold(pkt, ifnum - 1);

        for (size_t i = 0; i < ifnum; i++) {
            gnrc_pktsnip_t *netif;
            if (prep_hdr) {
                /* need to get second write access (duplication) to fill IPv6
                 * header interface-local */
                gnrc_pktsnip_t *tmp = gnrc_pktbuf_start_write(pkt);
                gnrc_pktsnip_t *ptr = tmp->next;
                ipv6 = tmp;

                if (ipv6 == NULL) {
                    DEBUG("ipv6: unable to get write access to IPv6 header, "
                          "for interface %" PRIkernel_pid "\n", ifs[i]);
                    gnrc_pktbuf_release(pkt);
                    return;
                }

                /* multiple interfaces => possibly different source addresses
                 * => different checksums => duplication of payload needed */
                while (ptr != payload->next) {
                    /* duplicate everything including payload */
                    tmp->next = gnrc_pktbuf_start_write(ptr);
                    if (tmp->next == NULL) {
                        DEBUG("ipv6: unable to get write access to payload, drop it\n");
                        gnrc_pktbuf_release(ipv6);
                        return;
                    }
                    tmp = tmp->next;
                    ptr = ptr->next;
                }

                if (_fill_ipv6_hdr(ifs[i], ipv6, tmp) < 0) {
                    /* error on filling up header */
                    gnrc_pktbuf_release(ipv6);
                    return;
                }
            }

            /* allocate interface header */
            netif = gnrc_netif_hdr_build(NULL, 0, NULL, 0);

            if (netif == NULL) {
                DEBUG("ipv6: error on interface header allocation, "
                      "dropping packet\n");
                gnrc_pktbuf_release(ipv6);
                return;
            }

            LL_PREPEND(ipv6, netif);

            _send_multicast_over_iface(ifs[i], ipv6);
        }
    }
    else {
        /* iface != KERNEL_PID_UNDEF implies that netif header is present */
        assert(pkt != ipv6);
        if (prep_hdr) {
            if (_fill_ipv6_hdr(iface, ipv6, payload) < 0) {
                /* error on filling up header */
                gnrc_pktbuf_release(pkt);
                return;
            }
        }

        _send_multicast_over_iface(iface, pkt);
    }
#else   /* GNRC_NETIF_NUMOF */
    (void)ifnum; /* not used in this build branch */
    if (iface == KERNEL_PID_UNDEF) {
        gnrc_pktsnip_t *netif;
        iface = ifs[0];

        /* allocate interface header */
        netif = gnrc_netif_hdr_build(NULL, 0, NULL, 0);

        if (netif == NULL) {
            DEBUG("ipv6: error on interface header allocation, "
                  "dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }

        LL_PREPEND(pkt, netif);
    }

    if (prep_hdr) {
        if (_fill_ipv6_hdr(iface, ipv6, payload) < 0) {
            /* error on filling up header */
            gnrc_pktbuf_release(pkt);
            return;
        }
    }

    _send_multicast_over_iface(iface, pkt);
#endif  /* GNRC_NETIF_NUMOF */
}
Esempio n. 9
0
void gnrc_rpl_p2p_recv_DRO(gnrc_pktsnip_t *pkt, ipv6_addr_t *src)
{
    gnrc_pktsnip_t *icmpv6_snip = gnrc_pktbuf_mark(pkt, sizeof(icmpv6_hdr_t), GNRC_NETTYPE_ICMPV6);
    gnrc_pktsnip_t *dro_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_rpl_p2p_dro_t),
                                                GNRC_NETTYPE_UNDEF);
    gnrc_pktsnip_t *rdo_snip = gnrc_pktbuf_mark(pkt, sizeof(gnrc_rpl_p2p_opt_rdo_t),
                                                GNRC_NETTYPE_UNDEF);
    gnrc_pktsnip_t *addr_snip = pkt;
    gnrc_rpl_instance_t *inst;
    gnrc_rpl_dodag_t *dodag;
    gnrc_rpl_p2p_ext_t *p2p_ext;
    gnrc_rpl_p2p_dro_t *dro;
    gnrc_rpl_p2p_opt_rdo_t *rdo;
    uint8_t *addr_vec;
    uint16_t flags;
    size_t addr_len;

    if (!rdo_snip || !dro_snip) {
        DEBUG("RPL-P2P: Error - No DRO or RDO received\n");
        gnrc_pktbuf_release(pkt);
        return;
    }

    dro = dro_snip->data;

    if ((inst = gnrc_rpl_instance_get(dro->instance_id)) == NULL) {
        DEBUG("RPL-P2P: Error - Instance (%d) does not exist\n", dro->instance_id);
        return;
    }

    dodag = &inst->dodag;

    if ((p2p_ext = gnrc_rpl_p2p_ext_get(dodag)) == NULL) {
        DEBUG("RPL-P2P: Error - No P2P-RPL DODAG extension found\n");
        return;
    }

    if (p2p_ext->for_me) {
        DEBUG("RPL-P2P: Ignore DRO\n");
        return;
    }

    flags = byteorder_ntohs(dro->flags_rev);
    p2p_ext->stop = (flags & (1 << GNRC_RPL_P2P_DRO_FLAGS_STOP)) >> GNRC_RPL_P2P_DRO_FLAGS_STOP;
    p2p_ext->dro_ack = (flags & (1 << GNRC_RPL_P2P_DRO_FLAGS_ACK)) >> GNRC_RPL_P2P_DRO_FLAGS_ACK;
    p2p_ext->dro_seq = (flags & (0x3 << GNRC_RPL_P2P_DRO_FLAGS_SEQ)) >> GNRC_RPL_P2P_DRO_FLAGS_SEQ;

    addr_len = sizeof(ipv6_addr_t) - p2p_ext->compr;
    ipv6_addr_t addr = p2p_ext->dodag->dodag_id;
    ipv6_addr_t *me = NULL;
    addr_vec = addr_snip->data;

    rdo = rdo_snip->data;

    if (rdo->lmn > 0) {
        rdo->lmn--;
        memcpy(&addr.u8[p2p_ext->compr], &addr_vec[addr_len * rdo->lmn], addr_len);
    }

    if (gnrc_ipv6_netif_find_by_addr(&me, &addr) == dodag->iface) {
        gnrc_ipv6_nib_ft_add(&p2p_ext->target, IPV6_ADDR_BIT_LEN, src, dodag->iface,
                             p2p_ext->dodag->default_lifetime *
                             p2p_ext->dodag->lifetime_unit);

        if (p2p_ext->dodag->node_status != GNRC_RPL_ROOT_NODE) {
            if ((rdo_snip = gnrc_pktbuf_start_write(rdo_snip)) == NULL) {
                DEBUG("RPL-P2P: Error - Cannot allocate new RDO\n");
                return;
            }

            addr_snip->next = NULL;
            rdo_snip->next = addr_snip;
            dro_snip->next = rdo_snip;

            icmpv6_snip = gnrc_icmpv6_build(dro_snip, ICMPV6_RPL_CTRL, GNRC_RPL_P2P_ICMPV6_CODE_DRO,
                                            sizeof(icmpv6_hdr_t));
            if (icmpv6_snip == NULL) {
                DEBUG("RPL-P2P: cannot allocate ICMPv6 - no space left in packet buffer\n");
                gnrc_pktbuf_release(pkt);
                return;
            }

            gnrc_rpl_send(icmpv6_snip, p2p_ext->dodag->iface, NULL, NULL, &p2p_ext->dodag->dodag_id);
            return;
        }
    }

    gnrc_pktbuf_release(pkt);

    return;
}
Esempio n. 10
0
static void _receive(gnrc_pktsnip_t *pkt)
{
    kernel_pid_t iface = KERNEL_PID_UNDEF;
    gnrc_pktsnip_t *ipv6, *netif;
    ipv6_hdr_t *hdr;

    assert(pkt != NULL);

    LL_SEARCH_SCALAR(pkt, netif, type, GNRC_NETTYPE_NETIF);

    if (netif != NULL) {
        iface = ((gnrc_netif_hdr_t *)netif->data)->if_pid;
    }

    if ((pkt->next != NULL) && (pkt->next->type == GNRC_NETTYPE_IPV6) &&
        (pkt->next->size == sizeof(ipv6_hdr_t))) {
        /* IP header was already marked. Take it. */
        ipv6 = pkt->next;

        if (!ipv6_hdr_is(ipv6->data)) {
            DEBUG("ipv6: Received packet was not IPv6, dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
    }
    else {
        if (!ipv6_hdr_is(pkt->data)) {
            DEBUG("ipv6: Received packet was not IPv6, dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }

        /* seize ipv6 as a temporary variable */
        ipv6 = gnrc_pktbuf_start_write(pkt);

        if (ipv6 == NULL) {
            DEBUG("ipv6: unable to get write access to packet, drop it\n");
            gnrc_pktbuf_release(pkt);
            return;
        }

        pkt = ipv6;     /* reset pkt from temporary variable */

        ipv6 = gnrc_pktbuf_mark(pkt, sizeof(ipv6_hdr_t), GNRC_NETTYPE_IPV6);

        if (ipv6 == NULL) {
            DEBUG("ipv6: error marking IPv6 header, dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
    }

    /* extract header */
    hdr = (ipv6_hdr_t *)ipv6->data;

    /* if available, remove any padding that was added by lower layers
     * to fulfill their minimum size requirements (e.g. ethernet) */
    if (byteorder_ntohs(hdr->len) < pkt->size) {
        gnrc_pktbuf_realloc_data(pkt, byteorder_ntohs(hdr->len));
    }

    DEBUG("ipv6: Received (src = %s, ",
          ipv6_addr_to_str(addr_str, &(hdr->src), sizeof(addr_str)));
    DEBUG("dst = %s, next header = %" PRIu8 ", length = %" PRIu16 ")\n",
          ipv6_addr_to_str(addr_str, &(hdr->dst), sizeof(addr_str)),
          hdr->nh, byteorder_ntohs(hdr->len));

    if (_pkt_not_for_me(&iface, hdr)) { /* if packet is not for me */
        DEBUG("ipv6: packet destination not this host\n");

#ifdef MODULE_GNRC_IPV6_ROUTER    /* only routers redirect */
        /* redirect to next hop */
        DEBUG("ipv6: decrement hop limit to %" PRIu8 "\n", hdr->hl - 1);

        /* RFC 4291, section 2.5.6 states: "Routers must not forward any
         * packets with Link-Local source or destination addresses to other
         * links."
         */
        if ((ipv6_addr_is_link_local(&(hdr->src))) || (ipv6_addr_is_link_local(&(hdr->dst)))) {
            DEBUG("ipv6: do not forward packets with link-local source or"\
                  " destination address\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
        /* TODO: check if receiving interface is router */
        else if (--(hdr->hl) > 0) {  /* drop packets that *reach* Hop Limit 0 */
            gnrc_pktsnip_t *tmp = pkt;

            DEBUG("ipv6: forward packet to next hop\n");

            /* pkt might not be writable yet, if header was given above */
            pkt = gnrc_pktbuf_start_write(tmp);
            ipv6 = gnrc_pktbuf_start_write(ipv6);

            if ((ipv6 == NULL) || (pkt == NULL)) {
                DEBUG("ipv6: unable to get write access to packet: dropping it\n");
                gnrc_pktbuf_release(tmp);
                return;
            }

            gnrc_pktbuf_release(ipv6->next);    /* remove headers around IPV6 */
            ipv6->next = pkt;                   /* reorder for sending */
            pkt->next = NULL;
            _send(ipv6, false);
            return;
        }
        else {
            DEBUG("ipv6: hop limit reached 0: drop packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }

#else  /* MODULE_GNRC_IPV6_ROUTER */
        DEBUG("ipv6: dropping packet\n");
        /* non rounting hosts just drop the packet */
        gnrc_pktbuf_release(pkt);
        return;
#endif /* MODULE_GNRC_IPV6_ROUTER */
    }

    /* IPv6 internal demuxing (ICMPv6, Extension headers etc.) */
    gnrc_ipv6_demux(iface, pkt, hdr->nh);
}
Esempio n. 11
0
static void _send_multicast(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
                            gnrc_pktsnip_t *ipv6, gnrc_pktsnip_t *payload,
                            bool prep_hdr)
{
    gnrc_pktsnip_t *netif;
    kernel_pid_t ifs[GNRC_NETIF_NUMOF];
    size_t ifnum = 0;

    if (iface == KERNEL_PID_UNDEF) {
        /* get list of interfaces */
        ifnum = gnrc_netif_get(ifs);

        /* throw away packet if no one is interested */
        if (ifnum == 0) {
            DEBUG("ipv6: no interfaces registered, dropping packet\n");
            gnrc_pktbuf_release(pkt);
            return;
        }
    }


#if GNRC_NETIF_NUMOF > 1
    /* netif header not present: send over all interfaces */
    if (iface == KERNEL_PID_UNDEF) {
        /* send packet to link layer */
        gnrc_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 = gnrc_pktbuf_start_write(ipv6);

                if (ipv6 == NULL) {
                    DEBUG("ipv6: unable to get write access to IPv6 header, "
                          "for interface %" PRIkernel_pid "\n", ifs[i]);
                    gnrc_pktbuf_release(pkt);
                    return;
                }

                if (_fill_ipv6_hdr(ifs[i], ipv6, payload) < 0) {
                    /* error on filling up header */
                    gnrc_pktbuf_release(pkt);
                    return;
                }
            }

            /* allocate interface header */
            netif = gnrc_netif_hdr_build(NULL, 0, NULL, 0);

            if (netif == NULL) {
                DEBUG("ipv6: error on interface header allocation, "
                      "dropping packet\n");
                gnrc_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 */
                gnrc_pktbuf_release(pkt);
                return;
            }
        }

        netif = pkt;

        _send_multicast_over_iface(iface, pkt, netif);
    }
#else   /* GNRC_NETIF_NUMOF */
    (void)ifnum; /* not used in this build branch */
    if (iface == KERNEL_PID_UNDEF) {
        iface = ifs[0];

        /* allocate interface header */
        netif = gnrc_netif_hdr_build(NULL, 0, NULL, 0);

        if (netif == NULL) {
            DEBUG("ipv6: error on interface header allocation, "
                  "dropping packet\n");
            gnrc_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 */
            gnrc_pktbuf_release(pkt);
            return;
        }
    }

    _send_multicast_over_iface(iface, pkt, netif);
#endif  /* GNRC_NETIF_NUMOF */
}
Esempio n. 12
0
static int _fill_ipv6_hdr(kernel_pid_t iface, gnrc_pktsnip_t *ipv6,
                          gnrc_pktsnip_t *payload)
{
    int res;
    ipv6_hdr_t *hdr = ipv6->data;

    hdr->len = byteorder_htons(gnrc_pkt_len(payload));
    DEBUG("ipv6: set payload length to %zu (network byteorder %04" PRIx16 ")\n",
          gnrc_pkt_len(payload), hdr->len.u16);

    /* check if e.g. extension header was not already marked */
    if (hdr->nh == PROTNUM_RESERVED) {
        hdr->nh = gnrc_nettype_to_protnum(payload->type);

        /* if still reserved: mark no next header */
        if (hdr->nh == PROTNUM_RESERVED) {
            hdr->nh = PROTNUM_IPV6_NONXT;
        }
    }

    DEBUG("ipv6: set next header to %" PRIu8 "\n", hdr->nh);

    if (hdr->hl == 0) {
        if (iface == KERNEL_PID_UNDEF) {
            hdr->hl = GNRC_IPV6_NETIF_DEFAULT_HL;
        }
        else {
            hdr->hl = gnrc_ipv6_netif_get(iface)->cur_hl;
        }
    }

    if (ipv6_addr_is_unspecified(&hdr->src)) {
        if (ipv6_addr_is_loopback(&hdr->dst)) {
            ipv6_addr_set_loopback(&hdr->src);
        }
        else {
            ipv6_addr_t *src = gnrc_ipv6_netif_find_best_src_addr(iface, &hdr->dst);

            if (src != NULL) {
                DEBUG("ipv6: set packet source to %s\n",
                      ipv6_addr_to_str(addr_str, src, sizeof(addr_str)));
                memcpy(&hdr->src, src, sizeof(ipv6_addr_t));
            }
            /* Otherwise leave unspecified */
        }
    }

    DEBUG("ipv6: calculate checksum for upper header.\n");

#if GNRC_NETIF_NUMOF > 1
    if (payload->users > 1) {
        gnrc_pktsnip_t *ptr = ipv6;

        /* We deal with multiple interfaces here (multicast) => possible
         * different source addresses => duplication of payload needed */
        while (ptr != payload->next) {
            gnrc_pktsnip_t *old = ptr->next;
            /* duplicate everything including payload */
            ptr->next = gnrc_pktbuf_start_write(ptr->next);

            if (ptr->next == NULL) {
                DEBUG("ipv6: unable to get write access to payload, drop it\n");
                return -ENOBUFS;
            }

            ptr = old;
        }
    }
#endif /* GNRC_NETIF_NUMOF */

    if ((res = gnrc_netreg_calc_csum(payload, ipv6)) < 0) {
        if (res != -ENOENT) {   /* if there is no checksum we are okay */
            DEBUG("ipv6: checksum calculation failed.\n");
            return res;
        }
    }

    return 0;
}
Esempio n. 13
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);
    }
}
Esempio n. 14
0
static void _send(gnrc_pktsnip_t *pkt)
{
    gnrc_netif_hdr_t *hdr;
    gnrc_pktsnip_t *pkt2;
    gnrc_netif_t *iface;
    /* datagram_size: pure IPv6 packet without 6LoWPAN dispatches or compression */
    size_t datagram_size;

    if ((pkt == NULL) || (pkt->size < sizeof(gnrc_netif_hdr_t))) {
        DEBUG("6lo: Sending packet has no netif header\n");
        gnrc_pktbuf_release(pkt);
        return;
    }

    if ((pkt->next == NULL) || (pkt->next->type != GNRC_NETTYPE_IPV6)) {
        DEBUG("6lo: Sending packet has no IPv6 header\n");
        gnrc_pktbuf_release(pkt);
        return;
    }

    pkt2 = gnrc_pktbuf_start_write(pkt);

    if (pkt2 == NULL) {
        DEBUG("6lo: no space left in packet buffer\n");
        gnrc_pktbuf_release(pkt);
        return;
    }

    hdr = pkt2->data;
    iface = gnrc_netif_get_by_pid(hdr->if_pid);
    datagram_size = gnrc_pkt_len(pkt2->next);

    if (iface == NULL) {
        DEBUG("6lo: Can not get 6LoWPAN specific interface information.\n");
        gnrc_pktbuf_release(pkt);
        return;
    }

#ifdef MODULE_GNRC_SIXLOWPAN_IPHC
    if (iface->flags & GNRC_NETIF_FLAGS_6LO_HC) {
        if (!gnrc_sixlowpan_iphc_encode(pkt2)) {
            DEBUG("6lo: error on IPHC encoding\n");
            gnrc_pktbuf_release(pkt2);
            return;
        }
        /* IPHC dispatch does not count on dispatch length since it _shortens_
         * the datagram */
    }
    else {
        if (!_add_uncompr_disp(pkt2)) {
            /* adding uncompressed dispatch failed */
            DEBUG("6lo: no space left in packet buffer\n");
            gnrc_pktbuf_release(pkt2);
            return;
        }
    }
#else
    /* suppress clang-analyzer report about iface being not read */
    (void) iface;
    if (!_add_uncompr_disp(pkt2)) {
        /* adding uncompressed dispatch failed */
        DEBUG("6lo: no space left in packet buffer\n");
        gnrc_pktbuf_release(pkt2);
        return;
    }
#endif
    DEBUG("6lo: iface->sixlo.max_frag_size = %" PRIu16 " for interface %"
          PRIkernel_pid "\n", iface->sixlo.max_frag_size, hdr->if_pid);

    /* IP should not send anything here if it is not a 6LoWPAN interface,
     * so we don't need to check for NULL pointers.
     * Note, that datagram_size cannot be used here, because the header size
     * might be changed by IPHC. */
    if (gnrc_pkt_len(pkt2->next) <= iface->sixlo.max_frag_size) {
        DEBUG("6lo: Send SND command for %p to %" PRIu16 "\n",
              (void *)pkt2, hdr->if_pid);
        if (gnrc_netapi_send(hdr->if_pid, pkt2) < 1) {
            DEBUG("6lo: unable to send %p over %" PRIu16 "\n", (void *)pkt, hdr->if_pid);
            gnrc_pktbuf_release(pkt2);
        }

        return;
    }
#ifdef MODULE_GNRC_SIXLOWPAN_FRAG
    else if (fragment_msg.pkt != NULL) {
        DEBUG("6lo: Fragmentation already ongoing. Dropping packet\n");
        gnrc_pktbuf_release(pkt2);
        return;
    }
    else if (datagram_size <= SIXLOWPAN_FRAG_MAX_LEN) {
        DEBUG("6lo: Send fragmented (%u > %" PRIu16 ")\n",
              (unsigned int)datagram_size, iface->max_frag_size);
        msg_t msg;

        fragment_msg.pid = hdr->if_pid;
        fragment_msg.pkt = pkt2;
        fragment_msg.datagram_size = datagram_size;
        /* Sending the first fragment has an offset==0 */
        fragment_msg.offset = 0;

        /* set the outgoing message's fields */
        msg.type = GNRC_SIXLOWPAN_MSG_FRAG_SND;
        msg.content.ptr = &fragment_msg;
        /* send message to self */
        msg_send_to_self(&msg);
    }
    else {
        DEBUG("6lo: packet too big (%u > %" PRIu16 ")\n",
              (unsigned int)datagram_size, (uint16_t)SIXLOWPAN_FRAG_MAX_LEN);
        gnrc_pktbuf_release(pkt2);
    }
#else
    (void) datagram_size;
    DEBUG("6lo: packet too big (%u > %" PRIu16 ")\n",
          (unsigned int)datagram_size, iface->max_frag_size);
    gnrc_pktbuf_release(pkt2);
#endif
}