Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ipv6: rpl: add source routing header for RPL #4774

Merged
merged 2 commits into from
Feb 27, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions sys/include/net/gnrc/ipv6/ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ extern "C" {
* @param[in] pkt A packet.
* @param[in] nh A protocol number (see @ref net_protnum).
*
* @return true, on success.
* @return false, on failure.
* @return true, on success - continue packet processing.
* @return false, on failure - stop packet processing.
*/
bool gnrc_ipv6_ext_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
uint8_t nh);
Expand Down
14 changes: 10 additions & 4 deletions sys/include/net/gnrc/rpl/srh.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#ifndef GNRC_RPL_SRH_H_
#define GNRC_RPL_SRH_H_

#include "net/ipv6/hdr.h"
#include "net/ipv6/addr.h"

#ifdef __cplusplus
Expand All @@ -48,17 +49,22 @@ typedef struct __attribute__((packed)) {
uint8_t len; /**< length in 8 octets without first octet */
uint8_t type; /**< identifier of a particular routing header type */
uint8_t seg_left; /**< number of route segments remaining */
uint8_t compr; /**< number of prefix octets (comprI and comprE) */
uint8_t pad_resv; /**< padding and reserved */
uint16_t resv; /**< reserved */
} gnrc_rpl_srh_t;

/**
* @brief Extract next hop from the RPL source routing header.
* @brief Process the RPL source routing header.
*
* @param[in,out] ipv6 The IPv6 header of the incoming packet.
* @param[in] rh A RPL source routing header.
*
* @return next hop, on success
* @return NULL, if not found.
* @return EXT_RH_CODE_ERROR
* @return EXT_RH_CODE_FORWARD
* @return EXT_RH_CODE_OK
*/
ipv6_addr_t *gnrc_rpl_srh_next_hop(gnrc_rpl_srh_t *rh);
int gnrc_rpl_srh_process(ipv6_hdr_t *ipv6, gnrc_rpl_srh_t *rh);

#ifdef __cplusplus
}
Expand Down
24 changes: 19 additions & 5 deletions sys/include/net/ipv6/ext/rh.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,24 @@
#include <stdint.h>

#include "net/ipv6/addr.h"
#include "net/ipv6/ext.h"
#include "net/ipv6/hdr.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
* @name Return codes for routing header processing
* @{
*/
#define EXT_RH_CODE_ERROR (-1)
#define EXT_RH_CODE_FORWARD (0)
#define EXT_RH_CODE_OK (1)
/**
* @}
*/

/**
* @brief IPv6 routing extension header.
*
Expand All @@ -46,14 +58,16 @@ typedef struct __attribute__((packed)) {
} ipv6_ext_rh_t;

/**
* @brief Extract next hop from the routing header of an IPv6 packet.
* @brief Process the routing header of an IPv6 packet.
*
* @param[in] ipv6 An IPv6 packet.
* @param[in, out] ipv6 An IPv6 packet.
* @param[in] ext A routing header of @ipv6.
*
* @return next hop on success, on success
* @return NULL, if not found.
* @return EXT_RH_CODE_ERROR
* @return EXT_RH_CODE_FORWARD
* @return EXT_RH_CODE_OK
*/
ipv6_addr_t *ipv6_ext_rh_next_hop(ipv6_hdr_t *ipv6);
int ipv6_ext_rh_process(ipv6_hdr_t *ipv6, ipv6_ext_rh_t *ext);

#ifdef __cplusplus
}
Expand Down
37 changes: 36 additions & 1 deletion sys/net/gnrc/network_layer/ipv6/ext/gnrc_ipv6_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@

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

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

bool gnrc_ipv6_ext_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
uint8_t nh)
{
gnrc_pktsnip_t *ext_snip;
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)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ext is also updated by ipv6_ext_rh_process.
Please insert
ext = ((ipv6_ext_t *)(((uint8_t *)pkt->data) + sizeof(ipv6_hdr_t) + offset));
before res = ipv6_ext_rh_process(hdr, (ipv6_ext_rh_t *)ext);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why we need to update ext before the call to ipv6_ext_rh_process?
ext will be updated for each header extension (that is not a routing header extension) that was encountered before. Once we reach the routing header extension, ext should point to the right place? That's why nh is updated before getting the next ext in line ~79.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If pkt is referred from multiple pointers, gnrc_pktbuf_start_write duplicates the packet data:

pkt

ext must point to the new byte array.

Note that the buffer referred from ext is updated by this line:
https://github.com/RIOT-OS/RIOT/pull/4774/files#diff-6906777c73d641182b398573d3bdba0bR87

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed in cgundogan@4b18686


Expand All @@ -36,6 +41,35 @@ bool gnrc_ipv6_ext_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return false; EDIT: addressed below

return false;
}
pkt = tmp;
hdr = pkt->data;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pkt = tmp; before this line.

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 */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gnrc_pktbuf_release(pkt);

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:
Expand All @@ -57,6 +91,7 @@ bool gnrc_ipv6_ext_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt,
ext_snip = gnrc_pktbuf_mark(pkt, offset, GNRC_NETTYPE_IPV6);

if (ext_snip == NULL) {
gnrc_pktbuf_release(pkt);
return false;
}

Expand Down
3 changes: 1 addition & 2 deletions sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,7 @@ void gnrc_ipv6_demux(kernel_pid_t iface, gnrc_pktsnip_t *pkt, uint8_t nh)
case PROTNUM_IPV6_EXT_MOB:
DEBUG("ipv6: handle extension header (nh = %u)\n", nh);
if (!gnrc_ipv6_ext_demux(iface, pkt, nh)) {
DEBUG("ipv6: unable to parse extension headers.\n");
gnrc_pktbuf_release(pkt);
DEBUG("ipv6: stop packet processing.\n");
return;
}
#endif
Expand Down
8 changes: 0 additions & 8 deletions sys/net/gnrc/network_layer/ndp/node/gnrc_ndp_node.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,6 @@ kernel_pid_t gnrc_ndp_node_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_len,
ipv6_addr_t *next_hop_ip = NULL, *prefix = NULL;
bool dst_link_local = ipv6_addr_is_link_local(dst);

#ifdef MODULE_GNRC_IPV6_EXT_RH
ipv6_hdr_t *hdr;
gnrc_pktsnip_t *ipv6;
ipv6 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6);
assert(ipv6);
hdr = ipv6->data;
next_hop_ip = ipv6_ext_rh_next_hop(hdr);
#endif
#ifdef MODULE_FIB
ipv6_addr_t next_hop_actual; /* FIB copies address into this variable */
/* don't look-up link local addresses in FIB */
Expand Down
8 changes: 0 additions & 8 deletions sys/net/gnrc/network_layer/sixlowpan/nd/gnrc_sixlowpan_nd.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,6 @@ kernel_pid_t gnrc_sixlowpan_nd_next_hop_l2addr(uint8_t *l2addr, uint8_t *l2addr_
ipv6_addr_t *next_hop = NULL;
gnrc_ipv6_nc_t *nc_entry = NULL;

#ifdef MODULE_GNRC_IPV6_EXT_RH
ipv6_hdr_t *hdr;
gnrc_pktsnip_t *ipv6;
ipv6 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6);
assert(ipv6);
hdr = ipv6->data;
next_hop = ipv6_ext_rh_next_hop(hdr);
#endif
#ifdef MODULE_FIB
kernel_pid_t fib_iface;
ipv6_addr_t next_hop_actual; /* FIB copies address into this variable */
Expand Down
3 changes: 3 additions & 0 deletions sys/net/gnrc/routing/rpl/srh/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MODULE = gnrc_rpl_srh

include $(RIOTBASE)/Makefile.base
79 changes: 76 additions & 3 deletions sys/net/gnrc/routing/rpl/srh/gnrc_rpl_srh.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,86 @@
* @file
*/

#include <string.h>
#include "net/gnrc/ipv6/netif.h"
#include "net/gnrc/rpl/srh.h"

ipv6_addr_t *gnrc_rpl_srh_next_hop(gnrc_rpl_srh_t *rh)
#define ENABLE_DEBUG (0)
#include "debug.h"

#if ENABLE_DEBUG
static char addr_str[IPV6_ADDR_MAX_STR_LEN];
#endif

#define GNRC_RPL_SRH_PADDING(X) ((X & 0xF0) >> 4)
#define GNRC_RPL_SRH_COMPRE(X) (X & 0x0F)
#define GNRC_RPL_SRH_COMPRI(X) ((X & 0xF0) >> 4)

int gnrc_rpl_srh_process(ipv6_hdr_t *ipv6, gnrc_rpl_srh_t *rh)
{
/* TODO */
if (rh->seg_left == 0) {
return EXT_RH_CODE_OK;
}

uint8_t n = (((rh->len * 8) - GNRC_RPL_SRH_PADDING(rh->pad_resv) -
(16 - GNRC_RPL_SRH_COMPRE(rh->compr))) /
(16 - GNRC_RPL_SRH_COMPRI(rh->compr))) + 1;
ipv6_addr_t addr = ipv6->dst, tmp;
uint8_t i, pref_elided, tmp_pref_elided, addr_len, compri_addr_len, tmp_addr_len, found_pos = 0;
uint8_t *addr_vec = (uint8_t *) (rh + 1);
bool found = false;

DEBUG("RPL SRH: %" PRIu8 " addresses in the routing header\n", n);

if (rh->seg_left > n) {
DEBUG("RPL SRH: number of segments left > number of addresses - discard\n");
/* TODO ICMP Parameter Problem - Code 0 */
return EXT_RH_CODE_ERROR;
}

rh->seg_left--;
i = n - rh->seg_left;
pref_elided = rh->seg_left ? GNRC_RPL_SRH_COMPRI(rh->compr) : GNRC_RPL_SRH_COMPRE(rh->compr);
compri_addr_len = sizeof(ipv6_addr_t) - GNRC_RPL_SRH_COMPRI(rh->compr);
addr_len = sizeof(ipv6_addr_t) - pref_elided;
memcpy(&addr.u8[pref_elided], &addr_vec[(i - 1) * compri_addr_len], addr_len);

if (ipv6_addr_is_multicast(&ipv6->dst) || ipv6_addr_is_multicast(&addr)) {
DEBUG("RPL SRH: found a multicast address - discard\n");
/* TODO discard the packet */
return EXT_RH_CODE_ERROR;
}

/* check if multiple addresses of my interface exist */
tmp_pref_elided = GNRC_RPL_SRH_COMPRI(rh->compr);
tmp_addr_len = sizeof(ipv6_addr_t) - tmp_pref_elided;
tmp = ipv6->dst;
for (uint8_t k = 0; k < n; k++) {
if (k == n - 1) {
tmp_pref_elided = GNRC_RPL_SRH_COMPRE(rh->compr);
tmp_addr_len = sizeof(ipv6_addr_t) - tmp_pref_elided;
tmp = ipv6->dst;
}
memcpy(&tmp.u8[tmp_pref_elided], &addr_vec[k * compri_addr_len], tmp_addr_len);
if (gnrc_ipv6_netif_find_by_addr(NULL, &tmp) != KERNEL_PID_UNDEF) {
if (found && ((k - found_pos) > 1)) {
DEBUG("RPL SRH: found multiple addresses that belong to me - discard\n");
/* TODO send an ICMP Parameter Problem (Code 0) and discard the packet */
return EXT_RH_CODE_ERROR;
}
found_pos = k;
found = true;
}
}

memcpy(&addr_vec[(i - 1) * compri_addr_len], &ipv6->dst.u8[pref_elided], addr_len);

DEBUG("RPL SRH: Next hop: %s at position %d\n",
ipv6_addr_to_str(addr_str, &addr, sizeof(addr_str)), i);

ipv6->dst = addr;

return NULL;
return EXT_RH_CODE_FORWARD;
}

/** @} */
3 changes: 3 additions & 0 deletions sys/net/network_layer/ipv6/ext/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MODULE = ipv6_ext

include $(RIOTBASE)/Makefile.base
42 changes: 9 additions & 33 deletions sys/net/network_layer/ipv6/ext/rh/ipv6_ext_rh.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,48 +15,24 @@
#include <stdbool.h>

#include "net/protnum.h"
#include "net/ipv6/ext.h"
#include "net/ipv6/ext/rh.h"
#include "net/gnrc/rpl/srh.h"

ipv6_addr_t *ipv6_ext_rh_next_hop(ipv6_hdr_t *ipv6)
int ipv6_ext_rh_process(ipv6_hdr_t *hdr, ipv6_ext_rh_t *ext)
{
ipv6_ext_rh_t *ext = (ipv6_ext_rh_t *)(ipv6 + 1);
bool c = true;
(void) hdr;

while (c) {
switch (ext->type) {
case PROTNUM_IPV6_EXT_HOPOPT:
case PROTNUM_IPV6_EXT_DST:
case PROTNUM_IPV6_EXT_FRAG:
case PROTNUM_IPV6_EXT_AH:
case PROTNUM_IPV6_EXT_ESP:
case PROTNUM_IPV6_EXT_MOB:
ext = (ipv6_ext_rh_t *)ipv6_ext_get_next((ipv6_ext_t *)ext);
break;

case PROTNUM_IPV6_EXT_RH:
c = false;
break;

default:
c = false;
break;
}
}

if (ipv6->nh == PROTNUM_IPV6_EXT_RH) {
switch (ext->type) {
switch (ext->type) {
#ifdef MODULE_GNRC_RPL_SRH
case GNRC_RPL_SRH_TYPE:
return gnrc_rpl_srh_next_hop((gnrc_rpl_srh_t *)ext);
case GNRC_RPL_SRH_TYPE:
return gnrc_rpl_srh_process(hdr, (gnrc_rpl_srh_t *)ext);
#endif

default:
break;
}
default:
break;
}

return NULL;
return EXT_RH_CODE_ERROR;
}

/** @} */
1 change: 1 addition & 0 deletions tests/unittests/tests-rpl_srh/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base
3 changes: 3 additions & 0 deletions tests/unittests/tests-rpl_srh/Makefile.include
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
USEMODULE += gnrc_ipv6
USEMODULE += ipv6_addr
USEMODULE += gnrc_rpl_srh
Loading