Skip to content

Commit

Permalink
Merge pull request #4774 from cgundogan/pr/rpl/srh
Browse files Browse the repository at this point in the history
ipv6: rpl: add source routing header for RPL
  • Loading branch information
OlegHahm committed Feb 27, 2016
2 parents 30e4266 + 170acbc commit b40b630
Show file tree
Hide file tree
Showing 15 changed files with 324 additions and 66 deletions.
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)));

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);
return false;
}
pkt = tmp;
hdr = pkt->data;
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 */
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

0 comments on commit b40b630

Please sign in to comment.