mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-17 02:23:49 +01:00
gnrc_ipv6: fix asserts for NHC
This commit is contained in:
parent
d171c96ede
commit
82a3aae8be
@ -89,6 +89,56 @@ static enum gnrc_ipv6_ext_demux_status _handle_rh(gnrc_pktsnip_t *current, gnrc_
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* current pkt
|
* current pkt
|
||||||
* | |
|
* | |
|
||||||
@ -100,86 +150,68 @@ void gnrc_ipv6_ext_demux(kernel_pid_t iface,
|
|||||||
gnrc_pktsnip_t *pkt,
|
gnrc_pktsnip_t *pkt,
|
||||||
uint8_t nh)
|
uint8_t nh)
|
||||||
{
|
{
|
||||||
gnrc_pktsnip_t *ext_snip, *tmp, *next;
|
|
||||||
ipv6_ext_t *ext;
|
ipv6_ext_t *ext;
|
||||||
size_t offset = 0;
|
|
||||||
|
|
||||||
ext = (ipv6_ext_t *) current->data;
|
while (true) {
|
||||||
|
ext = (ipv6_ext_t *) current->data;
|
||||||
|
|
||||||
switch (nh) {
|
switch (nh) {
|
||||||
case PROTNUM_IPV6_EXT_RH:
|
case PROTNUM_IPV6_EXT_RH:
|
||||||
#ifdef MODULE_GNRC_RPL_SRH
|
#ifdef MODULE_GNRC_RPL_SRH
|
||||||
switch (_handle_rh(current, pkt)) {
|
switch (_handle_rh(current, pkt)) {
|
||||||
case GNRC_IPV6_EXT_OK:
|
case GNRC_IPV6_EXT_OK:
|
||||||
/* We are the final destination. So proceeds like normal packet. */
|
/* We are the final destination. So proceeds like normal packet. */
|
||||||
nh = ext->nh;
|
nh = ext->nh;
|
||||||
DEBUG("ipv6_ext: next header = %" PRIu8 "\n", nh);
|
DEBUG("ipv6_ext: next header = %" PRIu8 "\n", nh);
|
||||||
offset = ((ext->len * IPV6_EXT_LEN_UNIT) + IPV6_EXT_LEN_UNIT);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GNRC_IPV6_EXT_ERROR:
|
if ((current = _mark_extension_header(current, &pkt)) == NULL) {
|
||||||
/* already released by _handle_rh, so no release here */
|
return;
|
||||||
return;
|
}
|
||||||
|
|
||||||
case GNRC_IPV6_EXT_FORWARDED:
|
gnrc_ipv6_demux(iface, current, pkt, nh); /* demultiplex next header */
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
return;
|
||||||
|
|
||||||
|
case GNRC_IPV6_EXT_ERROR:
|
||||||
|
/* already released by _handle_rh, so no release here */
|
||||||
|
return;
|
||||||
|
|
||||||
|
case GNRC_IPV6_EXT_FORWARDED:
|
||||||
|
/* the packet is forwarded and released. finish processing */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case PROTNUM_IPV6_EXT_HOPOPT:
|
case PROTNUM_IPV6_EXT_HOPOPT:
|
||||||
case PROTNUM_IPV6_EXT_DST:
|
case PROTNUM_IPV6_EXT_DST:
|
||||||
case PROTNUM_IPV6_EXT_FRAG:
|
case PROTNUM_IPV6_EXT_FRAG:
|
||||||
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:
|
||||||
/* TODO: add handling of types */
|
/* TODO: add handling of types */
|
||||||
nh = ext->nh;
|
nh = ext->nh;
|
||||||
DEBUG("ipv6_ext: next header = %" PRIu8 "\n", nh);
|
DEBUG("ipv6_ext: next header = %" PRIu8 "\n", nh);
|
||||||
offset = ((ext->len * IPV6_EXT_LEN_UNIT) + IPV6_EXT_LEN_UNIT);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
if ((current = _mark_extension_header(current, &pkt)) == NULL) {
|
||||||
DEBUG("ipv6_ext: unknown next header: %" PRIu8 "\n", nh);
|
return;
|
||||||
gnrc_pktbuf_release(pkt);
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current == pkt) {
|
gnrc_pktbuf_hold(pkt, 1); /* don't release on next dispatch */
|
||||||
if ((tmp = gnrc_pktbuf_start_write(pkt)) == NULL) {
|
if (gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, nh, pkt) == 0) {
|
||||||
DEBUG("ipv6: could not get a copy of pkt\n");
|
gnrc_pktbuf_release(pkt);
|
||||||
gnrc_pktbuf_release(pkt);
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
pkt = tmp;
|
|
||||||
|
|
||||||
ext_snip = gnrc_pktbuf_mark(pkt, offset, GNRC_NETTYPE_IPV6_EXT);
|
|
||||||
next = pkt;
|
|
||||||
|
|
||||||
if (ext_snip == NULL) {
|
|
||||||
gnrc_pktbuf_release(pkt);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* the header is already marked */
|
|
||||||
|
|
||||||
next = NULL;
|
|
||||||
|
|
||||||
for (tmp = pkt; tmp != NULL; tmp = tmp->next) {
|
|
||||||
if (tmp->next == current) {
|
|
||||||
next = tmp;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(next != NULL);
|
default:
|
||||||
|
gnrc_ipv6_demux(iface, current, pkt, nh); /* demultiplex next header */
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gnrc_ipv6_demux(iface, next, pkt, nh); /* demultiplex next header */
|
assert(false); /* never reaches here */
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gnrc_pktsnip_t *gnrc_ipv6_ext_build(gnrc_pktsnip_t *ipv6, gnrc_pktsnip_t *next,
|
gnrc_pktsnip_t *gnrc_ipv6_ext_build(gnrc_pktsnip_t *ipv6, gnrc_pktsnip_t *next,
|
||||||
|
|||||||
@ -69,9 +69,6 @@ kernel_pid_t gnrc_ipv6_pid = KERNEL_PID_UNDEF;
|
|||||||
|
|
||||||
/* handles GNRC_NETAPI_MSG_TYPE_RCV commands */
|
/* handles GNRC_NETAPI_MSG_TYPE_RCV commands */
|
||||||
static void _receive(gnrc_pktsnip_t *pkt);
|
static void _receive(gnrc_pktsnip_t *pkt);
|
||||||
/* dispatches received IPv6 packet for upper layer */
|
|
||||||
static void _dispatch_rcv_pkt(gnrc_nettype_t type, uint32_t demux_ctx,
|
|
||||||
gnrc_pktsnip_t *pkt);
|
|
||||||
/* Sends packet over the appropriate interface(s).
|
/* Sends packet over the appropriate interface(s).
|
||||||
* prep_hdr: prepare header for sending (call to _fill_ipv6_hdr()), otherwise
|
* prep_hdr: prepare header for sending (call to _fill_ipv6_hdr()), otherwise
|
||||||
* assume it is already prepared */
|
* assume it is already prepared */
|
||||||
@ -100,6 +97,9 @@ kernel_pid_t gnrc_ipv6_init(void)
|
|||||||
return gnrc_ipv6_pid;
|
return gnrc_ipv6_pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _dispatch_next_header(gnrc_pktsnip_t *current, gnrc_pktsnip_t *pkt,
|
||||||
|
uint8_t nh, bool interested);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* current pkt
|
* current pkt
|
||||||
* | |
|
* | |
|
||||||
@ -108,10 +108,9 @@ kernel_pid_t gnrc_ipv6_init(void)
|
|||||||
*/
|
*/
|
||||||
void gnrc_ipv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *current, gnrc_pktsnip_t *pkt, uint8_t nh)
|
void gnrc_ipv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *current, gnrc_pktsnip_t *pkt, uint8_t nh)
|
||||||
{
|
{
|
||||||
int receiver_num;
|
|
||||||
bool interested = false;
|
bool interested = false;
|
||||||
|
|
||||||
pkt->type = gnrc_nettype_from_protnum(nh);
|
current->type = gnrc_nettype_from_protnum(nh);
|
||||||
|
|
||||||
switch (nh) {
|
switch (nh) {
|
||||||
#ifdef MODULE_GNRC_ICMPV6
|
#ifdef MODULE_GNRC_ICMPV6
|
||||||
@ -139,76 +138,106 @@ void gnrc_ipv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *current, gnrc_pktsnip_t
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
(void)iface;
|
(void)iface;
|
||||||
|
#ifdef MODULE_GNRC_SIXLOWPAN_IPHC_NHC
|
||||||
|
/* second statement is true for small 6LoWPAN NHC decompressed frames
|
||||||
|
* since in this case it looks like
|
||||||
|
*
|
||||||
|
* * GNRC_NETTYPE_UNDEF <- pkt
|
||||||
|
* v
|
||||||
|
* * GNRC_NETTYPE_UDP <- current
|
||||||
|
* v
|
||||||
|
* * GNRC_NETTYPE_EXT
|
||||||
|
* v
|
||||||
|
* * GNRC_NETTYPE_IPV6
|
||||||
|
*/
|
||||||
|
assert((current == pkt) || (current == pkt->next));
|
||||||
|
#else
|
||||||
|
assert(current == pkt);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG("ipv6: forward nh = %u to other threads\n", nh);
|
_dispatch_next_header(current, pkt, nh, interested);
|
||||||
receiver_num = gnrc_netreg_num(pkt->type, GNRC_NETREG_DEMUX_CTX_ALL) +
|
|
||||||
gnrc_netreg_num(GNRC_NETTYPE_IPV6, nh);
|
|
||||||
|
|
||||||
if (receiver_num == 0) {
|
if (!interested) {
|
||||||
DEBUG("ipv6: unable to forward packet as no one is interested in it\n");
|
return;
|
||||||
|
|
||||||
if (!interested) {
|
|
||||||
assert(current == pkt);
|
|
||||||
gnrc_pktbuf_release(pkt);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!interested) {
|
|
||||||
assert(current == pkt);
|
|
||||||
/* IPv6 is not interested anymore so `- 1` */
|
|
||||||
receiver_num--;
|
|
||||||
}
|
|
||||||
|
|
||||||
gnrc_pktbuf_hold(current, receiver_num);
|
|
||||||
|
|
||||||
/* XXX can't use gnrc_netapi_dispatch_receive() twice here since a call to that function
|
|
||||||
* implicitly hands all rights to the packet to one of the receiving threads. As a
|
|
||||||
* result, the second call to gnrc_netapi_dispatch_receive() would be invalid */
|
|
||||||
_dispatch_rcv_pkt(current->type, GNRC_NETREG_DEMUX_CTX_ALL, current);
|
|
||||||
_dispatch_rcv_pkt(GNRC_NETTYPE_IPV6, nh, current);
|
|
||||||
|
|
||||||
if (!interested) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (nh) {
|
switch (nh) {
|
||||||
#ifdef MODULE_GNRC_ICMPV6
|
#ifdef MODULE_GNRC_ICMPV6
|
||||||
case PROTNUM_ICMPV6:
|
case PROTNUM_ICMPV6:
|
||||||
DEBUG("ipv6: handle ICMPv6 packet (nh = %u)\n", nh);
|
DEBUG("ipv6: handle ICMPv6 packet (nh = %u)\n", nh);
|
||||||
gnrc_icmpv6_demux(iface, pkt);
|
gnrc_icmpv6_demux(iface, pkt);
|
||||||
break;
|
gnrc_pktbuf_release(pkt);
|
||||||
|
return;
|
||||||
#endif
|
#endif
|
||||||
#ifdef MODULE_GNRC_IPV6_EXT
|
#ifdef MODULE_GNRC_IPV6_EXT
|
||||||
case PROTNUM_IPV6_EXT_HOPOPT:
|
case PROTNUM_IPV6_EXT_HOPOPT:
|
||||||
case PROTNUM_IPV6_EXT_DST:
|
case PROTNUM_IPV6_EXT_DST:
|
||||||
case PROTNUM_IPV6_EXT_RH:
|
case PROTNUM_IPV6_EXT_RH:
|
||||||
case PROTNUM_IPV6_EXT_FRAG:
|
case PROTNUM_IPV6_EXT_FRAG:
|
||||||
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:
|
||||||
DEBUG("ipv6: handle extension header (nh = %u)\n", nh);
|
DEBUG("ipv6: handle extension header (nh = %u)\n", nh);
|
||||||
|
|
||||||
gnrc_ipv6_ext_demux(iface, current, pkt, nh);
|
gnrc_ipv6_ext_demux(iface, current, pkt, nh);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
case PROTNUM_IPV6:
|
case PROTNUM_IPV6:
|
||||||
DEBUG("ipv6: handle encapsulated IPv6 packet (nh = %u)\n", nh);
|
DEBUG("ipv6: handle encapsulated IPv6 packet (nh = %u)\n", nh);
|
||||||
_decapsulate(pkt);
|
_decapsulate(pkt);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
break;
|
assert(false);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(current == pkt);
|
assert(false);
|
||||||
gnrc_pktbuf_release(pkt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* internal functions */
|
/* internal functions */
|
||||||
|
static void _dispatch_next_header(gnrc_pktsnip_t *current, gnrc_pktsnip_t *pkt,
|
||||||
|
uint8_t nh, bool interested)
|
||||||
|
{
|
||||||
|
#ifdef MODULE_GNRC_IPV6_EXT
|
||||||
|
const bool should_dispatch_current_type = ((current->type != GNRC_NETTYPE_IPV6_EXT) ||
|
||||||
|
(current->next->type == GNRC_NETTYPE_IPV6));
|
||||||
|
#else
|
||||||
|
const bool should_dispatch_current_type = (current->next->type == GNRC_NETTYPE_IPV6);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DEBUG("ipv6: forward nh = %u to other threads\n", nh);
|
||||||
|
|
||||||
|
/* dispatch IPv6 extension header only once */
|
||||||
|
if (should_dispatch_current_type) {
|
||||||
|
bool should_release = (gnrc_netreg_num(GNRC_NETTYPE_IPV6, nh) == 0) &&
|
||||||
|
(!interested);
|
||||||
|
|
||||||
|
if (!should_release) {
|
||||||
|
gnrc_pktbuf_hold(pkt, 1); /* don't remove from packet buffer in
|
||||||
|
* next dispatch */
|
||||||
|
}
|
||||||
|
if (gnrc_netapi_dispatch_receive(current->type,
|
||||||
|
GNRC_NETREG_DEMUX_CTX_ALL,
|
||||||
|
pkt) == 0) {
|
||||||
|
gnrc_pktbuf_release(pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_release) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (interested) {
|
||||||
|
gnrc_pktbuf_hold(pkt, 1); /* don't remove from packet buffer in
|
||||||
|
* next dispatch */
|
||||||
|
}
|
||||||
|
if (gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6, nh, pkt) == 0) {
|
||||||
|
gnrc_pktbuf_release(pkt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void *_event_loop(void *args)
|
static void *_event_loop(void *args)
|
||||||
{
|
{
|
||||||
msg_t msg, reply, msg_q[GNRC_IPV6_MSG_QUEUE_SIZE];
|
msg_t msg, reply, msg_q[GNRC_IPV6_MSG_QUEUE_SIZE];
|
||||||
@ -743,22 +772,6 @@ static inline bool _pkt_not_for_me(kernel_pid_t *iface, ipv6_hdr_t *hdr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _dispatch_rcv_pkt(gnrc_nettype_t type, uint32_t demux_ctx,
|
|
||||||
gnrc_pktsnip_t *pkt)
|
|
||||||
{
|
|
||||||
gnrc_netreg_entry_t *entry = gnrc_netreg_lookup(type, demux_ctx);
|
|
||||||
|
|
||||||
while (entry) {
|
|
||||||
DEBUG("ipv6: Send receive command for %p to %" PRIu16 "\n", (void *)pkt,
|
|
||||||
entry->pid);
|
|
||||||
if (gnrc_netapi_receive(entry->pid, pkt) < 1) {
|
|
||||||
DEBUG("ipv6: unable to deliver packet\n");
|
|
||||||
gnrc_pktbuf_release(pkt);
|
|
||||||
}
|
|
||||||
entry = gnrc_netreg_getnext(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _receive(gnrc_pktsnip_t *pkt)
|
static void _receive(gnrc_pktsnip_t *pkt)
|
||||||
{
|
{
|
||||||
kernel_pid_t iface = KERNEL_PID_UNDEF;
|
kernel_pid_t iface = KERNEL_PID_UNDEF;
|
||||||
@ -868,7 +881,7 @@ static void _receive(gnrc_pktsnip_t *pkt)
|
|||||||
* links."
|
* links."
|
||||||
*/
|
*/
|
||||||
if ((ipv6_addr_is_link_local(&(hdr->src))) || (ipv6_addr_is_link_local(&(hdr->dst)))) {
|
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"\
|
DEBUG("ipv6: do not forward packets with link-local source or"
|
||||||
" destination address\n");
|
" destination address\n");
|
||||||
gnrc_pktbuf_release(pkt);
|
gnrc_pktbuf_release(pkt);
|
||||||
return;
|
return;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user