gnrc_ipv6_ext_opt: initial import
This provides header parsing for IPv6 hop-by-hop and destination options according to [RFC 8200]. [RFC 8200]: https://tools.ietf.org/html/rfc8200#section-4.2
This commit is contained in:
parent
166315dcc2
commit
d04621fc43
@ -300,6 +300,10 @@ ifneq (,$(filter gnrc_ipv6_ext_frag,$(USEMODULE)))
|
|||||||
USEMODULE += xtimer
|
USEMODULE += xtimer
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter gnrc_ipv6_ext_opt,$(USEMODULE)))
|
||||||
|
USEMODULE += gnrc_ipv6_ext
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq (,$(filter gnrc_ipv6_ext_rh,$(USEMODULE)))
|
ifneq (,$(filter gnrc_ipv6_ext_rh,$(USEMODULE)))
|
||||||
USEMODULE += gnrc_ipv6_ext
|
USEMODULE += gnrc_ipv6_ext
|
||||||
endif
|
endif
|
||||||
|
|||||||
60
sys/include/net/gnrc/ipv6/ext/opt.h
Normal file
60
sys/include/net/gnrc/ipv6/ext/opt.h
Normal file
@ -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 <m.lenders@fu-berlin.de>
|
||||||
|
*/
|
||||||
|
#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 */
|
||||||
|
/** @} */
|
||||||
@ -19,6 +19,9 @@ endif
|
|||||||
ifneq (,$(filter gnrc_ipv6_ext_frag,$(USEMODULE)))
|
ifneq (,$(filter gnrc_ipv6_ext_frag,$(USEMODULE)))
|
||||||
DIRS += network_layer/ipv6/ext/frag
|
DIRS += network_layer/ipv6/ext/frag
|
||||||
endif
|
endif
|
||||||
|
ifneq (,$(filter gnrc_ipv6_ext_opt,$(USEMODULE)))
|
||||||
|
DIRS += network_layer/ipv6/ext/opt
|
||||||
|
endif
|
||||||
ifneq (,$(filter gnrc_ipv6_ext_rh,$(USEMODULE)))
|
ifneq (,$(filter gnrc_ipv6_ext_rh,$(USEMODULE)))
|
||||||
DIRS += network_layer/ipv6/ext/rh
|
DIRS += network_layer/ipv6/ext/rh
|
||||||
endif
|
endif
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
#include "net/gnrc/icmpv6/error.h"
|
#include "net/gnrc/icmpv6/error.h"
|
||||||
#include "net/gnrc/ipv6.h"
|
#include "net/gnrc/ipv6.h"
|
||||||
#include "net/gnrc/ipv6/ext/frag.h"
|
#include "net/gnrc/ipv6/ext/frag.h"
|
||||||
|
#include "net/gnrc/ipv6/ext/opt.h"
|
||||||
#include "net/gnrc/ipv6/ext/rh.h"
|
#include "net/gnrc/ipv6/ext/rh.h"
|
||||||
#if defined(MODULE_GNRC_SIXLOWPAN_IPHC_NHC) && \
|
#if defined(MODULE_GNRC_SIXLOWPAN_IPHC_NHC) && \
|
||||||
defined(MODULE_GNRC_IPV6_EXT_FRAG)
|
defined(MODULE_GNRC_IPV6_EXT_FRAG)
|
||||||
@ -311,6 +312,10 @@ static gnrc_pktsnip_t *_demux(gnrc_pktsnip_t *pkt, unsigned protnum)
|
|||||||
#endif /* MODULE_GNRC_IPV6_EXT_FRAG */
|
#endif /* MODULE_GNRC_IPV6_EXT_FRAG */
|
||||||
case PROTNUM_IPV6_EXT_HOPOPT:
|
case PROTNUM_IPV6_EXT_HOPOPT:
|
||||||
case PROTNUM_IPV6_EXT_DST:
|
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_AH:
|
||||||
case PROTNUM_IPV6_EXT_ESP:
|
case PROTNUM_IPV6_EXT_ESP:
|
||||||
case PROTNUM_IPV6_EXT_MOB:
|
case PROTNUM_IPV6_EXT_MOB:
|
||||||
|
|||||||
3
sys/net/gnrc/network_layer/ipv6/ext/opt/Makefile
Normal file
3
sys/net/gnrc/network_layer/ipv6/ext/opt/Makefile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
MODULE := gnrc_ipv6_ext_opt
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.base
|
||||||
133
sys/net/gnrc/network_layer/ipv6/ext/opt/gnrc_ipv6_ext_opt.c
Normal file
133
sys/net/gnrc/network_layer/ipv6/ext/opt/gnrc_ipv6_ext_opt.c
Normal file
@ -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 <m.lenders@fu-berlin.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
Loading…
x
Reference in New Issue
Block a user