Skip to content

Commit

Permalink
Merge pull request #13275 from miri64/gnrc_ipv6_ext_opt/feat/initial
Browse files Browse the repository at this point in the history
gnrc_ipv6_ext_opt: initial import
  • Loading branch information
benpicco authored May 20, 2020
2 parents 59da69e + f6bd070 commit 70543bb
Show file tree
Hide file tree
Showing 13 changed files with 1,108 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,10 @@ ifneq (,$(filter gnrc_ipv6_ext_frag,$(USEMODULE)))
USEMODULE += xtimer
endif

ifneq (,$(filter gnrc_ipv6_ext_opt,$(USEMODULE)))
USEMODULE += gnrc_ipv6_ext
endif

ifneq (,$(filter gnrc_ipv6_ext_rh,$(USEMODULE)))
USEMODULE += gnrc_ipv6_ext
endif
Expand Down
60 changes: 60 additions & 0 deletions sys/include/net/gnrc/ipv6/ext/opt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2020 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.
*/

/**
* @defgroup net_gnrc_ipv6_ext_opt Support for IPv6 option extension headers
* @ingroup net_gnrc_ipv6_ext
* @brief GNRC implementation of IPv6 hop-by-hop and destination option
* header extension
* @{
*
* @file
* @brief GNRC hop-by-hop and destination option header definitions.
*
* @author Martine Lenders <[email protected]>
*/
#ifndef NET_GNRC_IPV6_EXT_OPT_H
#define NET_GNRC_IPV6_EXT_OPT_H

#include <stdint.h>

#include "net/gnrc/pkt.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Processes all options within an IPv6 option header
*
* @pre `pkt != NULL`
* @pre `(protnum == PROTNUM_IPV6_EXT_HOPOPT) || (protnum == PROTNUM_IPV6_EXT_DST)`
*
* @param[in] pkt The packet containing the option header. The option
* must be contained in the first snip, with all
* preceding headers marked (in receive order).
* Must not be NULL.
* @param[in] protnum The protocol number of the option header. Must be
* @ref PROTNUM_IPV6_EXT_HOPOPT or @ref
* PROTNUM_IPV6_EXT_DST
*
* @return @p pkt with the option header marked on success.
* @return NULL, if the packet was consumed by the option handling.
* @return NULL, on error. @p pkt is released with EINVAL in that case and if
* necessary and [`gnrc_icmpv6_error`](@ref net_gnrc_icmpv6_error) is
* used, the according ICMPv6 error message is sent.
*/
gnrc_pktsnip_t *gnrc_ipv6_ext_opt_process(gnrc_pktsnip_t *pkt,
uint8_t protnum);

#ifdef __cplusplus
}
#endif

#endif /* NET_GNRC_IPV6_EXT_OPT_H */
/** @} */
96 changes: 96 additions & 0 deletions sys/include/net/ipv6/ext/opt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright (C) 2020 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.
*/

/**
* @defgroup net_ipv6_ext_opt IPv6 destination and hop-by-hop options
* @ingroup net_ipv6_ext
* @brief Definitions for IPv6 destination and hop-by-hop options
* extension headers
* @{
*
* @file
* @brief Destination and hop-by-hop options extension header definitions.
*
* @author Martine Lenders <[email protected]>
*/
#ifndef NET_IPV6_EXT_OPT_H
#define NET_IPV6_EXT_OPT_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @name Destination and hop-by-hop option types
* @see [IANA, IPv6 parameters]
* (https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml#ipv6-parameters-2)
* @{
*/
#define IPV6_EXT_OPT_PAD1 (0x00U) /**< Pad1 */
#define IPV6_EXT_OPT_PADN (0x01U) /**< PadN */
#define IPV6_EXT_OPT_JUMBO (0xC2U) /**< Jumbo payload */
#define IPV6_EXT_OPT_RPL (0x63U) /**< RPL Option */
#define IPV6_EXT_OPT_TEL (0x04U) /**< Tunnel Encapsulation Limit */
#define IPV6_EXT_OPT_RTR_ALERT (0x05U) /**< Router Alert */
#define IPV6_EXT_OPT_QUICK_START (0x26U) /**< Quick-Start */
#define IPV6_EXT_OPT_CALIPSO (0x07U) /**< CALIPSO */
#define IPV6_EXT_OPT_SMF_DPD (0x08U) /**< SMF_DPD */
#define IPV6_EXT_OPT_HOME_ADDR (0xC9U) /**< Home Address */
#define IPV6_EXT_OPT_ILNP_NONCE (0x8BU) /**< ILNP Nonce */
#define IPV6_EXT_OPT_LIO (0x8CU) /**< Line-Identification Option */
#define IPV6_EXT_OPT_MPL (0x6DU) /**< MPL Option */
#define IPV6_EXT_OPT_IP_DFF (0xEEU) /**< IP_DFF */
#define IPV6_EXT_OPT_PDM (0x0FU) /**< Performance and Diagnostic Metrics */
/** @} */

/**
* @name Processing actions
* @see [RFC 8200, section 4.2](https://tools.ietf.org/html/rfc8200#section-4.2)
*
* > The Option Type identifiers are internally encoded such that their
* > highest-order 2 bits specify the action that must be taken if the
* > processing IPv6 node does not recognize the Option Type
* @{
*/
/**
* @brief mask to decode action from type
*/
#define IPV6_EXT_OPT_ACTION_MASK (0xc0)
/**
* @brief skip over this option and continue processing the header
*/
#define IPV6_EXT_OPT_ACTION_SKIP (0x00)
#define IPV6_EXT_OPT_ACTION_DISC (0x40) /**< discard the packet */
/**
* @brief discard the packet
*
* > and, regardless of whether or not the packet's Destination Address
* > was a multicast address, send an ICMP Parameter Problem, Code 2,
* > message to the packet's Source Address, pointing to the
* > unrecognized Option Type.
*/
#define IPV6_EXT_OPT_ACTION_DISC_ERR_MCAST (0x80)

/**
* @brief discard the packet
*
* > and, only if the packet's Destination Address was not a multicast
* > address, send an ICMP Parameter Problem, Code 2, message to the
* > packet's Source Address, pointing to the unrecognized Option Type.
*/
#define IPV6_EXT_OPT_ACTION_DISC_ERR (0xc0)
/** @} */

#ifdef __cplusplus
}
#endif

#endif /* NET_IPV6_EXT_OPT_H */
/** @} */
3 changes: 3 additions & 0 deletions sys/net/gnrc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ endif
ifneq (,$(filter gnrc_ipv6_ext_frag,$(USEMODULE)))
DIRS += network_layer/ipv6/ext/frag
endif
ifneq (,$(filter gnrc_ipv6_ext_opt,$(USEMODULE)))
DIRS += network_layer/ipv6/ext/opt
endif
ifneq (,$(filter gnrc_ipv6_ext_rh,$(USEMODULE)))
DIRS += network_layer/ipv6/ext/rh
endif
Expand Down
5 changes: 5 additions & 0 deletions sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "net/gnrc/icmpv6/error.h"
#include "net/gnrc/ipv6.h"
#include "net/gnrc/ipv6/ext/frag.h"
#include "net/gnrc/ipv6/ext/opt.h"
#include "net/gnrc/ipv6/ext/rh.h"
#if defined(MODULE_GNRC_SIXLOWPAN_IPHC_NHC) && \
defined(MODULE_GNRC_IPV6_EXT_FRAG)
Expand Down Expand Up @@ -311,6 +312,10 @@ static gnrc_pktsnip_t *_demux(gnrc_pktsnip_t *pkt, unsigned protnum)
#endif /* MODULE_GNRC_IPV6_EXT_FRAG */
case PROTNUM_IPV6_EXT_HOPOPT:
case PROTNUM_IPV6_EXT_DST:
if (IS_USED(MODULE_GNRC_IPV6_EXT_OPT)) {
return gnrc_ipv6_ext_opt_process(pkt, protnum);
}
/* Intentionally falls through */
case PROTNUM_IPV6_EXT_AH:
case PROTNUM_IPV6_EXT_ESP:
case PROTNUM_IPV6_EXT_MOB:
Expand Down
3 changes: 3 additions & 0 deletions sys/net/gnrc/network_layer/ipv6/ext/opt/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MODULE := gnrc_ipv6_ext_opt

include $(RIOTBASE)/Makefile.base
133 changes: 133 additions & 0 deletions sys/net/gnrc/network_layer/ipv6/ext/opt/gnrc_ipv6_ext_opt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
* Copyright (C) 2020 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 Martine Lenders <[email protected]>
*/

#include "net/ipv6.h"
#include "net/ipv6/ext.h"
#include "net/ipv6/ext/opt.h"
#include "net/gnrc/icmpv6/error.h"
#include "net/gnrc/pktbuf.h"

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

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

/**
* @brief Determine what action to do, when option is not recognized
*
* @see https://tools.ietf.org/html/rfc8200#section-4.2
*
* @param[in] type Type of the option
*/
static inline uint8_t _unrec_action(uint8_t type)
{
return (type & IPV6_EXT_OPT_ACTION_MASK);
}

static bool _multicast_dst(gnrc_pktsnip_t *pkt)
{
gnrc_pktsnip_t *ipv6 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6);
ipv6_hdr_t *ipv6_hdr;

assert(ipv6 != NULL);
ipv6_hdr = ipv6->data;
return ipv6_addr_is_multicast(&ipv6_hdr->dst);
}

gnrc_pktsnip_t *gnrc_ipv6_ext_opt_process(gnrc_pktsnip_t *pkt,
uint8_t protnum)
{
assert(pkt != NULL);
assert((protnum == PROTNUM_IPV6_EXT_HOPOPT) ||
(protnum == PROTNUM_IPV6_EXT_DST));
gnrc_pktsnip_t *hdr;
ipv6_ext_t *opt_hdr = pkt->data;
uint8_t *opts;
size_t hdr_len;

if (pkt->size < sizeof(ipv6_ext_t)) {
DEBUG("gnrc_ipv6_ext_opt: packet of invalid size\n");
goto error;
}
hdr_len = ((opt_hdr->len * IPV6_EXT_LEN_UNIT) + IPV6_EXT_LEN_UNIT);
hdr = gnrc_pktbuf_mark(pkt, hdr_len, GNRC_NETTYPE_IPV6_EXT);
if (hdr == NULL) {
DEBUG("gnrc_ipv6_ext_opt: unable to mark option header\n");
goto error;
}
opts = hdr->data;
for (unsigned offset = sizeof(ipv6_ext_t); offset < hdr_len;) {
uint8_t opt_type = opts[offset++];
uint8_t opt_len;

if (opt_type == IPV6_EXT_OPT_PAD1) {
/* nothing more to do */
continue;
}
opt_len = opts[offset++];
if (opt_len > (hdr_len - offset)) {
DEBUG("gnrc_ipv6_ext_opt: invalid option size\n");
goto error;
}
switch (opt_type) {
/* IPV6_EXT_OPT_PAD1 already handled before length check due
* to special format */
case IPV6_EXT_OPT_PADN:
/* nothing to do, offset will be progressed below */
break;
default: {
bool send_error = false;

switch (_unrec_action(opt_type)) {
case IPV6_EXT_OPT_ACTION_SKIP:
DEBUG("gnrc_ipv6_ext_opt: skipping unknown "
"option %02x\n", opt_type);
/* skip here already, as we don't reach the
* incrementation of offset below */
offset += opt_len;
continue;
case IPV6_EXT_OPT_ACTION_DISC:
break;
case IPV6_EXT_OPT_ACTION_DISC_ERR_MCAST:
send_error = IS_USED(MODULE_GNRC_ICMPV6_ERROR);
break;
case IPV6_EXT_OPT_ACTION_DISC_ERR:
send_error = IS_USED(MODULE_GNRC_ICMPV6_ERROR) &&
!_multicast_dst(pkt);
break;
}
DEBUG("gnrc_ipv6_ext_opt: discarding packet with unknown "
"option %02x\n", opt_type);
if (send_error) {
DEBUG("gnrc_ipv6_ext_opt: reporting parameter problem "
"for option %02x (pos at %02x)\n", opts[offset - 2U],
opt_type);
gnrc_icmpv6_error_param_prob_send(
ICMPV6_ERROR_PARAM_PROB_OPT,
/* offset was already progressed to opt data*/
&opts[offset - 2U], pkt);
}
goto error;
}
}
offset += opt_len;
}
return pkt;
error:
gnrc_pktbuf_release_error(pkt, EINVAL);
return NULL;
}

/** @} */
39 changes: 39 additions & 0 deletions tests/gnrc_ipv6_ext_opt/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
DEVELHELP = 1
# name of your application
include ../Makefile.tests_common

export TAP ?= tap0

# use Ethernet as link-layer protocol
ifeq (native,$(BOARD))
TERMFLAGS ?= $(TAP)
else
ETHOS_BAUDRATE ?= 115200
CFLAGS += -DETHOS_BAUDRATE=$(ETHOS_BAUDRATE)
TERMDEPS += ethos
TERMPROG ?= sudo $(RIOTTOOLS)/ethos/ethos
TERMFLAGS ?= $(TAP) $(PORT) $(ETHOS_BAUDRATE)
endif
USEMODULE += auto_init_gnrc_netif
USEMODULE += gnrc_ipv6_default
USEMODULE += gnrc_icmpv6_error
USEMODULE += gnrc_pktdump
USEMODULE += gnrc_pktbuf_cmd
# IPv6 extension headers
USEMODULE += gnrc_ipv6_ext_opt
USEMODULE += od
# Add also the shell, some shell commands
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += ps

# The test requires some setup and to be run as root
# So it cannot currently be run
TEST_ON_CI_BLACKLIST += all

.PHONY: ethos

ethos:
$(Q)env -u CC -u CFLAGS make -C $(RIOTTOOLS)/ethos

include $(RIOTBASE)/Makefile.include
6 changes: 6 additions & 0 deletions tests/gnrc_ipv6_ext_opt/Makefile.board.dep
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Put board specific dependencies here
ifeq (native,$(BOARD))
USEMODULE += netdev_tap
else
USEMODULE += stdio_ethos
endif
Loading

0 comments on commit 70543bb

Please sign in to comment.