示例#1
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;
}
示例#2
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;
}