<commit_before>/*
 * Copyright (C) 2015 <NAME> <<EMAIL>>
 * Copyright (C) 2018 Freie Universität Berlin
 *
 * This file is subject to the terms and conditions of the GNU Lesser
 * General Public License v2.1. See the file LICENSE in the top level
 * directory for more details.
 */

/**
 * @{
 *
 * @file
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 */

#include <errno.h>

#include "utlist.h"
#include "net/gnrc/netif.h"
#include "net/gnrc/netreg.h"
#include "net/gnrc/pktbuf.h"
#include "net/gnrc/icmpv6/error.h"
#include "net/gnrc/ipv6.h"
#include "net/gnrc/ipv6/ext/rh.h"

#include "net/gnrc/ipv6/ext.h"

#define ENABLE_DEBUG    (0)
#include "debug.h"

/**
 * @brief   Checks if @p protnum is a duplicate @ref PROTNUM_IPV6_EXT_HOPOPT.
 *
 * If @p protnum is @ref PROTNUM_IPV6_EXT_HOPOPT, the function sends a parameter
 * problem message (if @ref net_gnrc_icmpv6_error is available), releases the
 * packet with error `EINVAL`, and returns `false`.
 *
 * @note    This function should only be called *after* the first hop-by-hop
 *          option header in the packet was parsed (if it exists) or if the
 *          first extension header wasn't a hop-by-hop option header.
 *
 * @param[in] pkt       A packet in receive order to be checked with the current
 *                      extension header (of type @p protnum) as its payload.
 * @param[in] protnum   The protocol number of the header in
 *                      gnrc_pktsnip_t::data of @p pkt.
 *
 * @return  true, when @p protnum == @ref PROTNUM_IPV6_EXT_HOPOPT.
 * @return  false, when @p protnum != @ref PROTNUM_IPV6_EXT_HOPOPT.
 */
static bool _duplicate_hopopt(gnrc_pktsnip_t *pkt, unsigned protnum);

/**
 * @brief   Demultiplex an extension header according to @p protnum.
 *
 * This includes dispatching it to interested parties in the
 * @ref net_gnrc_netreg.
 *
 * @param[in] pkt       A packet with the first snip pointing to the extension
 *                      header to process.
 * @param[in] protnum   Protocol number of @p pkt.
 *
 * @return  The packet for further processing.
 * @return  NULL, on error or if packet was consumed (by e.g. forwarding via
 *          a routing header). @p pkt is released in case of error.
 */
static gnrc_pktsnip_t *_demux(gnrc_pktsnip_t *pkt, unsigned protnum);

gnrc_pktsnip_t *gnrc_ipv6_ext_process_hopopt(gnrc_pktsnip_t *pkt,
                                             uint8_t *protnum)
{
    if ((*protnum == PROTNUM_IPV6_EXT_HOPOPT) && (pkt != NULL)) {
        /* if a hop-by-hop options header is within the IPv6 packet it comes
         * immediately after the IPv6 header and it must be processed before
         * the packet is forwarded
         * (see https://tools.ietf.org/html/rfc8200#section-4.1) */
        if ((pkt = _demux(pkt, *protnum)) == NULL) {
            DEBUG("ipv6 ext: packet was consumed in extension header "
                  "handling\n");
            return NULL;
        }
        /* packet can only be unmarked (since we are the first one to
         * process this packet and 6LoWPAN only provides packets unmarked)
         *
         * pkt -----------> pkt->next --------> pkt->next->next
         *  v                     v                         v
         * next header          hop-by-hop option       IPv6 header */
        assert((pkt->next != NULL) && (pkt->next->next != NULL) &&
               (pkt->next->next->type == GNRC_NETTYPE_IPV6));
        *protnum = ((ipv6_ext_t *)pkt->next->data)->nh;
        if (_duplicate_hopopt(pkt, *protnum)) {
            return NULL;
        }
    }
    return pkt;
}

gnrc_pktsnip_t *gnrc_ipv6_ext_process_all(gnrc_pktsnip_t *pkt,
                                          uint8_t *protnum)
{
    bool is_ext = true;
    while (is_ext) {
        switch (*protnum) {
            case PROTNUM_IPV6_EXT_DST:
            case PROTNUM_IPV6_EXT_RH:
            case PROTNUM_IPV6_EXT_FRAG:
            case PROTNUM_IPV6_EXT_AH:
            case PROTNUM_IPV6_EXT_ESP:
            case PROTNUM_IPV6_EXT_MOB: {
                ipv6_ext_t *ext_hdr;

                DEBUG("ipv6: handle extension header (protnum = %u)\n",
                      *protnum);
                ext_hdr = pkt->data;
                if ((pkt = _demux(pkt, *protnum)) == NULL) {
                    DEBUG("ipv6: packet was consumed by extension header "
                          "handling\n");
                    return NULL;
                }
                *protnum = ext_hdr->nh;
                if (_duplicate_hopopt(pkt, *protnum)) {
                    return NULL;
                }
                break;
            }
            default:
                is_ext = false;
                break;
        }
    }
    return pkt;
}

static bool _duplicate_hopopt(gnrc_pktsnip_t *pkt, unsigned protnum)
{
    if (protnum == PROTNUM_IPV6_EXT_HOPOPT) {<commit_msg>gnrc_ipv6_ext: don't read from `pkt->data` after `_demux()`<commit_after>/*
 * Copyright (C) 2015 <NAME> <<EMAIL>>
 * Copyright (C) 2018 Freie Universität Berlin
 *
 * This file is subject to the terms and conditions of the GNU Lesser
 * General Public License v2.1. See the file LICENSE in the top level
 * directory for more details.
 */

/**
 * @{
 *
 * @file
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 */

#include <errno.h>

#include "utlist.h"
#include "net/gnrc/netif.h"
#include "net/gnrc/netreg.h"
#include "net/gnrc/pktbuf.h"
#include "net/gnrc/icmpv6/error.h"
#include "net/gnrc/ipv6.h"
#include "net/gnrc/ipv6/ext/rh.h"

#include "net/gnrc/ipv6/ext.h"

#define ENABLE_DEBUG    (0)
#include "debug.h"

/**
 * @brief   Checks if @p protnum is a duplicate @ref PROTNUM_IPV6_EXT_HOPOPT.
 *
 * If @p protnum is @ref PROTNUM_IPV6_EXT_HOPOPT, the function sends a parameter
 * problem message (if @ref net_gnrc_icmpv6_error is available), releases the
 * packet with error `EINVAL`, and returns `false`.
 *
 * @note    This function should only be called *after* the first hop-by-hop
 *          option header in the packet was parsed (if it exists) or if the
 *          first extension header wasn't a hop-by-hop option header.
 *
 * @param[in] pkt       A packet in receive order to be checked with the current
 *                      extension header (of type @p protnum) as its payload.
 * @param[in] protnum   The protocol number of the header in
 *                      gnrc_pktsnip_t::data of @p pkt.
 *
 * @return  true, when @p protnum == @ref PROTNUM_IPV6_EXT_HOPOPT.
 * @return  false, when @p protnum != @ref PROTNUM_IPV6_EXT_HOPOPT.
 */
static bool _duplicate_hopopt(gnrc_pktsnip_t *pkt, unsigned protnum);

/**
 * @brief   Demultiplex an extension header according to @p protnum.
 *
 * This includes dispatching it to interested parties in the
 * @ref net_gnrc_netreg.
 *
 * @param[in] pkt       A packet with the first snip pointing to the extension
 *                      header to process.
 * @param[in] protnum   Protocol number of @p pkt.
 *
 * @return  The packet for further processing.
 * @return  NULL, on error or if packet was consumed (by e.g. forwarding via
 *          a routing header). @p pkt is released in case of error.
 */
static gnrc_pktsnip_t *_demux(gnrc_pktsnip_t *pkt, unsigned protnum);

gnrc_pktsnip_t *gnrc_ipv6_ext_process_hopopt(gnrc_pktsnip_t *pkt,
                                             uint8_t *protnum)
{
    if ((*protnum == PROTNUM_IPV6_EXT_HOPOPT) && (pkt != NULL)) {
        /* if a hop-by-hop options header is within the IPv6 packet it comes
         * immediately after the IPv6 header and it must be processed before
         * the packet is forwarded
         * (see https://tools.ietf.org/html/rfc8200#section-4.1) */
        if ((pkt = _demux(pkt, *protnum)) == NULL) {
            DEBUG("ipv6 ext: packet was consumed in extension header "
                  "handling\n");
            return NULL;
        }
        /* packet can only be unmarked (since we are the first one to
         * process this packet and 6LoWPAN only provides packets unmarked)
         *
         * pkt -----------> pkt->next --------> pkt->next->next
         *  v                     v                         v
         * next header          hop-by-hop option       IPv6 header */
        assert((pkt->next != NULL) && (pkt->next->next != NULL) &&
               (pkt->next->next->type == GNRC_NETTYPE_IPV6));
        *protnum = ((ipv6_ext_t *)pkt->next->data)->nh;
        if (_duplicate_hopopt(pkt, *protnum)) {
            return NULL;
        }
    }
    return pkt;
}

gnrc_pktsnip_t *gnrc_ipv6_ext_process_all(gnrc_pktsnip_t *pkt,
                                          uint8_t *protnum)
{
    bool is_ext = true;
    while (is_ext) {
        switch (*protnum) {
            case PROTNUM_IPV6_EXT_DST:
            case PROTNUM_IPV6_EXT_RH:
            case PROTNUM_IPV6_EXT_FRAG:
            case PROTNUM_IPV6_EXT_AH:
            case PROTNUM_IPV6_EXT_ESP:
            case PROTNUM_IPV6_EXT_MOB: {
                ipv6_ext_t *ext_hdr;
                uint8_t nh;

                DEBUG("ipv6: handle extension header (protnum = %u)\n",
                      *protnum);
                ext_hdr = pkt->data;
                nh = ext_hdr->nh;
                if ((pkt = _demux(pkt, *protnum)) == NULL) {
                    DEBUG("ipv6: packet was consumed by extension header "
                          "handling\n");
                    return NULL;
                }
                *protnum = nh;
                if (_duplicate_hopopt(pkt, nh)) {
                    return NULL;
                }
                break;
            }
            default:
                is_ext = false;
                break;
        }
    }
    return pkt;
}

static bool _duplicate_hopopt(gnrc_pktsnip_t *pkt, unsigned protnum)
{
    if (protnum == PROTNUM_IPV6_EXT_HOPOPT) {
{'fraction_non_alphanumeric': 0.10462858894451824, 'fraction_numerical': 0.010013282926330847, 'mean_word_length': 1.9759805411979325, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 56, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4664400', 'n_tokens_mistral': 3203, 'n_tokens_neox': 3130, 'n_words': 910}