Implement RPL non-storing mode
This commit is contained in:
parent
d14b76d869
commit
b3e31e1456
|
@ -47,6 +47,11 @@
|
|||
#include "net/ipv6/uip-ds6.h"
|
||||
#endif
|
||||
|
||||
#if UIP_CONF_IPV6_RPL
|
||||
#include "net/rpl/rpl.h"
|
||||
#include "net/rpl/rpl-private.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
|
@ -525,7 +530,7 @@ void
|
|||
tcpip_ipv6_output(void)
|
||||
{
|
||||
uip_ds6_nbr_t *nbr = NULL;
|
||||
uip_ipaddr_t *nexthop;
|
||||
uip_ipaddr_t *nexthop = NULL;
|
||||
|
||||
if(uip_len == 0) {
|
||||
return;
|
||||
|
@ -545,14 +550,25 @@ tcpip_ipv6_output(void)
|
|||
|
||||
if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
|
||||
/* Next hop determination */
|
||||
|
||||
#if UIP_CONF_IPV6_RPL && RPL_WITH_NON_STORING
|
||||
uip_ipaddr_t ipaddr;
|
||||
/* Look for a RPL Source Route */
|
||||
if(rpl_srh_get_next_hop(&ipaddr)) {
|
||||
nexthop = &ipaddr;
|
||||
}
|
||||
#endif /* UIP_CONF_IPV6_RPL && RPL_WITH_NON_STORING */
|
||||
|
||||
nbr = NULL;
|
||||
|
||||
/* We first check if the destination address is on our immediate
|
||||
link. If so, we simply use the destination address as our
|
||||
nexthop address. */
|
||||
if(uip_ds6_is_addr_onlink(&UIP_IP_BUF->destipaddr)){
|
||||
if(nexthop == NULL && uip_ds6_is_addr_onlink(&UIP_IP_BUF->destipaddr)){
|
||||
nexthop = &UIP_IP_BUF->destipaddr;
|
||||
} else {
|
||||
}
|
||||
|
||||
if(nexthop == NULL) {
|
||||
uip_ds6_route_t *route;
|
||||
/* Check if we have a route to the destination address. */
|
||||
route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr);
|
||||
|
@ -636,7 +652,7 @@ tcpip_ipv6_output(void)
|
|||
/* End of next hop determination */
|
||||
|
||||
#if UIP_CONF_IPV6_RPL
|
||||
if(rpl_update_header_final(nexthop)) {
|
||||
if(!rpl_finalize_header(nexthop)) {
|
||||
uip_clear_buf();
|
||||
return;
|
||||
}
|
||||
|
@ -646,6 +662,7 @@ tcpip_ipv6_output(void)
|
|||
#if UIP_ND6_SEND_NA
|
||||
if((nbr = uip_ds6_nbr_add(nexthop, NULL, 0, NBR_INCOMPLETE, NBR_TABLE_REASON_IPV6_ND, NULL)) == NULL) {
|
||||
uip_clear_buf();
|
||||
PRINTF("tcpip_ipv6_output: failed to add neighbor to cache\n");
|
||||
return;
|
||||
} else {
|
||||
#if UIP_CONF_IPV6_QUEUE_PKT
|
||||
|
@ -672,6 +689,7 @@ tcpip_ipv6_output(void)
|
|||
/* Send the first NS try from here (multicast destination IP address). */
|
||||
}
|
||||
#else /* UIP_ND6_SEND_NA */
|
||||
PRINTF("tcpip_ipv6_output: neighbor not in cache\n");
|
||||
uip_len = 0;
|
||||
return;
|
||||
#endif /* UIP_ND6_SEND_NA */
|
||||
|
|
|
@ -1801,6 +1801,13 @@ typedef struct uip_routing_hdr {
|
|||
uint8_t seg_left;
|
||||
} uip_routing_hdr;
|
||||
|
||||
/* RPL Source Routing Header */
|
||||
typedef struct uip_rpl_srh_hdr {
|
||||
uint8_t cmpr; /* CmprI and CmprE */
|
||||
uint8_t pad;
|
||||
uint8_t reserved[2];
|
||||
} uip_rpl_srh_hdr;
|
||||
|
||||
/* fragmentation header */
|
||||
typedef struct uip_frag_hdr {
|
||||
uint8_t next;
|
||||
|
|
|
@ -57,6 +57,7 @@ void NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK(const linkaddr_t *addr);
|
|||
void NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK(const linkaddr_t *addr);
|
||||
#endif /* NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK */
|
||||
|
||||
#if (UIP_CONF_MAX_ROUTES != 0)
|
||||
/* The nbr_routes holds a neighbor table to be able to maintain
|
||||
information about what routes go through what neighbor. This
|
||||
neighbor table is registered with the central nbr-table repository
|
||||
|
@ -71,6 +72,11 @@ MEMB(neighborroutememb, struct uip_ds6_route_neighbor_route, UIP_DS6_ROUTE_NB);
|
|||
LIST(routelist);
|
||||
MEMB(routememb, uip_ds6_route_t, UIP_DS6_ROUTE_NB);
|
||||
|
||||
static int num_routes = 0;
|
||||
static void rm_routelist_callback(nbr_table_item_t *ptr);
|
||||
|
||||
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
|
||||
/* Default routes are held on the defaultrouterlist and their
|
||||
structures are allocated from the defaultroutermemb memory block.*/
|
||||
LIST(defaultrouterlist);
|
||||
|
@ -80,13 +86,10 @@ MEMB(defaultroutermemb, uip_ds6_defrt_t, UIP_DS6_DEFRT_NB);
|
|||
LIST(notificationlist);
|
||||
#endif
|
||||
|
||||
static int num_routes = 0;
|
||||
|
||||
#undef DEBUG
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "net/ip/uip-debug.h"
|
||||
|
||||
static void rm_routelist_callback(nbr_table_item_t *ptr);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#if DEBUG != DEBUG_NONE
|
||||
static void
|
||||
|
@ -156,10 +159,12 @@ uip_ds6_notification_rm(struct uip_ds6_notification *n)
|
|||
void
|
||||
uip_ds6_route_init(void)
|
||||
{
|
||||
#if (UIP_CONF_MAX_ROUTES != 0)
|
||||
memb_init(&routememb);
|
||||
list_init(routelist);
|
||||
nbr_table_register(nbr_routes,
|
||||
(nbr_table_callback *)rm_routelist_callback);
|
||||
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
|
||||
memb_init(&defaultroutermemb);
|
||||
list_init(defaultrouterlist);
|
||||
|
@ -168,6 +173,7 @@ uip_ds6_route_init(void)
|
|||
list_init(notificationlist);
|
||||
#endif
|
||||
}
|
||||
#if (UIP_CONF_MAX_ROUTES != 0)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uip_lladdr_t *
|
||||
uip_ds6_route_nexthop_lladdr(uip_ds6_route_t *route)
|
||||
|
@ -179,36 +185,48 @@ uip_ds6_route_nexthop_lladdr(uip_ds6_route_t *route)
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uip_ipaddr_t *
|
||||
uip_ds6_route_nexthop(uip_ds6_route_t *route)
|
||||
{
|
||||
#if (UIP_CONF_MAX_ROUTES != 0)
|
||||
if(route != NULL) {
|
||||
return uip_ds6_nbr_ipaddr_from_lladdr(uip_ds6_route_nexthop_lladdr(route));
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
#else /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
return NULL;
|
||||
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uip_ds6_route_t *
|
||||
uip_ds6_route_head(void)
|
||||
{
|
||||
#if (UIP_CONF_MAX_ROUTES != 0)
|
||||
return list_head(routelist);
|
||||
#else /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
return NULL;
|
||||
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uip_ds6_route_t *
|
||||
uip_ds6_route_next(uip_ds6_route_t *r)
|
||||
{
|
||||
#if (UIP_CONF_MAX_ROUTES != 0)
|
||||
if(r != NULL) {
|
||||
uip_ds6_route_t *n = list_item_next(r);
|
||||
return n;
|
||||
}
|
||||
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
return NULL;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
uip_ds6_route_is_nexthop(const uip_ipaddr_t *ipaddr)
|
||||
{
|
||||
#if (UIP_CONF_MAX_ROUTES != 0)
|
||||
const uip_lladdr_t *lladdr;
|
||||
lladdr = uip_ds6_nbr_lladdr_from_ipaddr(ipaddr);
|
||||
|
||||
|
@ -217,17 +235,25 @@ uip_ds6_route_is_nexthop(const uip_ipaddr_t *ipaddr)
|
|||
}
|
||||
|
||||
return nbr_table_get_from_lladdr(nbr_routes, (linkaddr_t *)lladdr) != NULL;
|
||||
#else /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
return 0;
|
||||
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
uip_ds6_route_num_routes(void)
|
||||
{
|
||||
#if (UIP_CONF_MAX_ROUTES != 0)
|
||||
return num_routes;
|
||||
#else /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
return 0;
|
||||
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uip_ds6_route_t *
|
||||
uip_ds6_route_lookup(uip_ipaddr_t *addr)
|
||||
{
|
||||
#if (UIP_CONF_MAX_ROUTES != 0)
|
||||
uip_ds6_route_t *r;
|
||||
uip_ds6_route_t *found_route;
|
||||
uint8_t longestmatch;
|
||||
|
@ -274,12 +300,16 @@ uip_ds6_route_lookup(uip_ipaddr_t *addr)
|
|||
}
|
||||
|
||||
return found_route;
|
||||
#else /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
return NULL;
|
||||
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uip_ds6_route_t *
|
||||
uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length,
|
||||
uip_ipaddr_t *nexthop)
|
||||
{
|
||||
#if (UIP_CONF_MAX_ROUTES != 0)
|
||||
uip_ds6_route_t *r;
|
||||
struct uip_ds6_route_neighbor_route *nbrr;
|
||||
|
||||
|
@ -426,12 +456,17 @@ uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length,
|
|||
assert_nbr_routes_list_sane();
|
||||
#endif /* DEBUG != DEBUG_NONE */
|
||||
return r;
|
||||
|
||||
#else /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
return NULL;
|
||||
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
uip_ds6_route_rm(uip_ds6_route_t *route)
|
||||
{
|
||||
#if (UIP_CONF_MAX_ROUTES != 0)
|
||||
struct uip_ds6_route_neighbor_route *neighbor_route;
|
||||
#if DEBUG != DEBUG_NONE
|
||||
assert_nbr_routes_list_sane();
|
||||
|
@ -488,8 +523,11 @@ uip_ds6_route_rm(uip_ds6_route_t *route)
|
|||
#if DEBUG != DEBUG_NONE
|
||||
assert_nbr_routes_list_sane();
|
||||
#endif /* DEBUG != DEBUG_NONE */
|
||||
|
||||
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
return;
|
||||
}
|
||||
#if (UIP_CONF_MAX_ROUTES != 0)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
rm_routelist(struct uip_ds6_route_neighbor_routes *routes)
|
||||
|
@ -517,10 +555,12 @@ rm_routelist_callback(nbr_table_item_t *ptr)
|
|||
{
|
||||
rm_routelist((struct uip_ds6_route_neighbor_routes *)ptr);
|
||||
}
|
||||
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
uip_ds6_route_rm_by_nexthop(uip_ipaddr_t *nexthop)
|
||||
{
|
||||
#if (UIP_CONF_MAX_ROUTES != 0)
|
||||
/* Get routing entry list of this neighbor */
|
||||
const uip_lladdr_t *nexthop_lladdr;
|
||||
struct uip_ds6_route_neighbor_routes *routes;
|
||||
|
@ -529,6 +569,7 @@ uip_ds6_route_rm_by_nexthop(uip_ipaddr_t *nexthop)
|
|||
routes = nbr_table_get_from_lladdr(nbr_routes,
|
||||
(linkaddr_t *)nexthop_lladdr);
|
||||
rm_routelist(routes);
|
||||
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uip_ds6_defrt_t *
|
||||
|
|
|
@ -50,7 +50,7 @@ NBR_TABLE_DECLARE(nbr_routes);
|
|||
void uip_ds6_route_init(void);
|
||||
|
||||
#ifndef UIP_CONF_UIP_DS6_NOTIFICATIONS
|
||||
#define UIP_DS6_NOTIFICATIONS 1
|
||||
#define UIP_DS6_NOTIFICATIONS (UIP_CONF_MAX_ROUTES != 0)
|
||||
#else
|
||||
#define UIP_DS6_NOTIFICATIONS UIP_CONF_UIP_DS6_NOTIFICATIONS
|
||||
#endif
|
||||
|
|
|
@ -120,9 +120,6 @@ uip_icmp6_register_input_handler(uip_icmp6_input_handler_t *handler)
|
|||
static void
|
||||
echo_request_input(void)
|
||||
{
|
||||
#if UIP_CONF_IPV6_RPL
|
||||
uint8_t temp_ext_len;
|
||||
#endif /* UIP_CONF_IPV6_RPL */
|
||||
/*
|
||||
* we send an echo reply. It is trivial if there was no extension
|
||||
* headers in the request otherwise we need to remove the extension
|
||||
|
@ -147,44 +144,27 @@ echo_request_input(void)
|
|||
}
|
||||
|
||||
if(uip_ext_len > 0) {
|
||||
#if UIP_CONF_IPV6_RPL
|
||||
if((temp_ext_len = rpl_invert_header())) {
|
||||
/* If there were other extension headers*/
|
||||
UIP_FIRST_EXT_BUF->next = UIP_PROTO_ICMP6;
|
||||
if (uip_ext_len != temp_ext_len) {
|
||||
uip_len -= (uip_ext_len - temp_ext_len);
|
||||
UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
|
||||
UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
|
||||
/* move the echo request payload (starting after the icmp header)
|
||||
* to the new location in the reply.
|
||||
* The shift is equal to the length of the remaining extension headers present
|
||||
* Note: UIP_ICMP_BUF still points to the echo request at this stage
|
||||
*/
|
||||
memmove((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN - (uip_ext_len - temp_ext_len),
|
||||
(uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN,
|
||||
(uip_len - UIP_IPH_LEN - temp_ext_len - UIP_ICMPH_LEN));
|
||||
}
|
||||
uip_ext_len = temp_ext_len;
|
||||
} else {
|
||||
#endif /* UIP_CONF_IPV6_RPL */
|
||||
/* If there were extension headers*/
|
||||
UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
|
||||
uip_len -= uip_ext_len;
|
||||
UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
|
||||
UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
|
||||
/* move the echo request payload (starting after the icmp header)
|
||||
* to the new location in the reply.
|
||||
* The shift is equal to the length of the extension headers present
|
||||
* Note: UIP_ICMP_BUF still points to the echo request at this stage
|
||||
*/
|
||||
memmove((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN - uip_ext_len,
|
||||
(uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN,
|
||||
(uip_len - UIP_IPH_LEN - UIP_ICMPH_LEN));
|
||||
uip_ext_len = 0;
|
||||
#if UIP_CONF_IPV6_RPL
|
||||
}
|
||||
#endif /* UIP_CONF_IPV6_RPL */
|
||||
/* Remove extension headers if any */
|
||||
UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
|
||||
uip_len -= uip_ext_len;
|
||||
UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
|
||||
UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
|
||||
/* move the echo request payload (starting after the icmp header)
|
||||
* to the new location in the reply.
|
||||
* The shift is equal to the length of the extension headers present
|
||||
* Note: UIP_ICMP_BUF still points to the echo request at this stage
|
||||
*/
|
||||
memmove((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN - uip_ext_len,
|
||||
(uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN,
|
||||
(uip_len - UIP_IPH_LEN - UIP_ICMPH_LEN));
|
||||
uip_ext_len = 0;
|
||||
}
|
||||
|
||||
/* Insert RPL extension headers */
|
||||
#if UIP_CONF_IPV6_RPL
|
||||
rpl_insert_header();
|
||||
#endif /* UIP_CONF_IPV6_RPL */
|
||||
|
||||
/* Below is important for the correctness of UIP_ICMP_BUF and the
|
||||
* checksum
|
||||
*/
|
||||
|
@ -329,53 +309,31 @@ echo_reply_input(void)
|
|||
{
|
||||
int ttl;
|
||||
uip_ipaddr_t sender;
|
||||
#if UIP_CONF_IPV6_RPL
|
||||
uint8_t temp_ext_len;
|
||||
#endif /* UIP_CONF_IPV6_RPL */
|
||||
|
||||
PRINTF("Received Echo Reply from ");
|
||||
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
|
||||
PRINTF(" to ");
|
||||
PRINT6ADDR(&UIP_IP_BUF->destipaddr);
|
||||
PRINTF("\n");
|
||||
|
||||
uip_ipaddr_copy(&sender, &UIP_IP_BUF->srcipaddr);
|
||||
ttl = UIP_IP_BUF->ttl;
|
||||
|
||||
if(uip_ext_len > 0) {
|
||||
#if UIP_CONF_IPV6_RPL
|
||||
if((temp_ext_len = rpl_invert_header())) {
|
||||
/* If there were other extension headers*/
|
||||
UIP_FIRST_EXT_BUF->next = UIP_PROTO_ICMP6;
|
||||
if (uip_ext_len != temp_ext_len) {
|
||||
uip_len -= (uip_ext_len - temp_ext_len);
|
||||
UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
|
||||
UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
|
||||
/* move the echo reply payload (starting after the icmp
|
||||
* header) to the new location in the reply. The shift is
|
||||
* equal to the length of the remaining extension headers
|
||||
* present Note: UIP_ICMP_BUF still points to the echo reply
|
||||
* at this stage
|
||||
*/
|
||||
memmove((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN - (uip_ext_len - temp_ext_len),
|
||||
(uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN,
|
||||
(uip_len - UIP_IPH_LEN - temp_ext_len - UIP_ICMPH_LEN));
|
||||
}
|
||||
uip_ext_len = temp_ext_len;
|
||||
uip_len -= uip_ext_len;
|
||||
} else {
|
||||
#endif /* UIP_CONF_IPV6_RPL */
|
||||
/* If there were extension headers*/
|
||||
UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
|
||||
uip_len -= uip_ext_len;
|
||||
UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
|
||||
UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
|
||||
/* move the echo reply payload (starting after the icmp header)
|
||||
* to the new location in the reply. The shift is equal to the
|
||||
* length of the extension headers present Note: UIP_ICMP_BUF
|
||||
* still points to the echo request at this stage
|
||||
*/
|
||||
memmove((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN - uip_ext_len,
|
||||
(uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN,
|
||||
(uip_len - UIP_IPH_LEN - UIP_ICMPH_LEN));
|
||||
uip_ext_len = 0;
|
||||
#if UIP_CONF_IPV6_RPL
|
||||
}
|
||||
#endif /* UIP_CONF_IPV6_RPL */
|
||||
/* Remove extension headers if any */
|
||||
UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
|
||||
uip_len -= uip_ext_len;
|
||||
UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8);
|
||||
UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff);
|
||||
/* move the echo reply payload (starting after the icmp header)
|
||||
* to the new location in the reply. The shift is equal to the
|
||||
* length of the extension headers present Note: UIP_ICMP_BUF
|
||||
* still points to the echo request at this stage
|
||||
*/
|
||||
memmove((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN - uip_ext_len,
|
||||
(uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN,
|
||||
(uip_len - UIP_IPH_LEN - UIP_ICMPH_LEN));
|
||||
uip_ext_len = 0;
|
||||
}
|
||||
|
||||
/* Call all registered applications to let them know an echo reply
|
||||
|
|
|
@ -79,6 +79,11 @@
|
|||
#include "net/ipv6/uip-ds6.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6.h"
|
||||
|
||||
#if UIP_CONF_IPV6_RPL
|
||||
#include "rpl/rpl.h"
|
||||
#include "rpl/rpl-private.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -88,10 +93,6 @@
|
|||
#define DEBUG DEBUG_NONE
|
||||
#include "net/ip/uip-debug.h"
|
||||
|
||||
#if UIP_CONF_IPV6_RPL
|
||||
#include "rpl/rpl.h"
|
||||
#endif /* UIP_CONF_IPV6_RPL */
|
||||
|
||||
#if UIP_LOGGING == 1
|
||||
#include <stdio.h>
|
||||
void uip_log(char *msg);
|
||||
|
@ -889,7 +890,7 @@ ext_hdr_options_process(void)
|
|||
*/
|
||||
#if UIP_CONF_IPV6_RPL
|
||||
PRINTF("Processing RPL option\n");
|
||||
if(rpl_verify_header(uip_ext_opt_offset)) {
|
||||
if(rpl_verify_hbh_header(uip_ext_opt_offset)) {
|
||||
PRINTF("RPL Option Error: Dropping Packet\n");
|
||||
return 1;
|
||||
}
|
||||
|
@ -1228,9 +1229,9 @@ uip_process(uint8_t flag)
|
|||
}
|
||||
|
||||
#if UIP_CONF_IPV6_RPL
|
||||
if(rpl_update_header_empty()) {
|
||||
if(!rpl_update_header()) {
|
||||
/* Packet can not be forwarded */
|
||||
PRINTF("RPL Forward Option Error\n");
|
||||
PRINTF("RPL header update error\n");
|
||||
goto drop;
|
||||
}
|
||||
#endif /* UIP_CONF_IPV6_RPL */
|
||||
|
@ -1368,6 +1369,11 @@ uip_process(uint8_t flag)
|
|||
|
||||
PRINTF("Processing Routing header\n");
|
||||
if(UIP_ROUTING_BUF->seg_left > 0) {
|
||||
#if UIP_CONF_IPV6_RPL && RPL_WITH_NON_STORING
|
||||
if(rpl_process_srh_header()) {
|
||||
goto send; /* Proceed to forwarding */
|
||||
}
|
||||
#endif /* UIP_CONF_IPV6_RPL && RPL_WITH_NON_STORING */
|
||||
uip_icmp6_error_output(ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, UIP_IPH_LEN + uip_ext_len + 2);
|
||||
UIP_STAT(++uip_stat.ip.drop);
|
||||
UIP_LOG("ip6: unrecognized routing type");
|
||||
|
|
|
@ -236,16 +236,25 @@
|
|||
#endif
|
||||
|
||||
/*
|
||||
* Hop-by-hop option
|
||||
* This option control the insertion of the RPL Hop-by-Hop extension header
|
||||
* into packets originating from this node. Incoming Hop-by-hop extension
|
||||
* header are still processed and forwarded.
|
||||
* Embed support for storing mode
|
||||
*/
|
||||
#ifdef RPL_CONF_INSERT_HBH_OPTION
|
||||
#define RPL_INSERT_HBH_OPTION RPL_CONF_INSERT_HBH_OPTION
|
||||
#else
|
||||
#define RPL_INSERT_HBH_OPTION 1
|
||||
#endif
|
||||
#ifdef RPL_CONF_WITH_STORING
|
||||
#define RPL_WITH_STORING RPL_CONF_WITH_STORING
|
||||
#else /* RPL_CONF_WITH_STORING */
|
||||
#define RPL_WITH_STORING 1
|
||||
#endif /* RPL_CONF_WITH_STORING */
|
||||
|
||||
/*
|
||||
* Embed support for non-storing mode
|
||||
*/
|
||||
#ifdef RPL_CONF_WITH_NON_STORING
|
||||
#define RPL_WITH_NON_STORING RPL_CONF_WITH_NON_STORING
|
||||
#else /* RPL_CONF_WITH_NON_STORING */
|
||||
#define RPL_WITH_NON_STORING 0
|
||||
#endif /* RPL_CONF_WITH_NON_STORING */
|
||||
|
||||
#define RPL_IS_STORING(instance) (RPL_WITH_STORING && ((instance) != NULL) && ((instance)->mop > RPL_MOP_NON_STORING))
|
||||
#define RPL_IS_NON_STORING(instance) (RPL_WITH_NON_STORING && ((instance) != NULL) && ((instance)->mop == RPL_MOP_NON_STORING))
|
||||
|
||||
/*
|
||||
* RPL DAO ACK support. When enabled, DAO ACK will be sent and requested.
|
||||
|
|
|
@ -43,7 +43,9 @@
|
|||
|
||||
#define RPL_DAG_GRACE_PERIOD (CLOCK_SECOND * 20 * 1)
|
||||
|
||||
#if (UIP_CONF_MAX_ROUTES != 0)
|
||||
static struct uip_ds6_notification n;
|
||||
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
static uint8_t to_become_root;
|
||||
static struct ctimer c;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -121,6 +123,7 @@ create_dag_callback(void *ptr)
|
|||
ctimer_set(&c, RPL_DAG_GRACE_PERIOD, create_dag_callback, NULL);
|
||||
}
|
||||
}
|
||||
#if (UIP_CONF_MAX_ROUTES != 0)
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
route_callback(int event, uip_ipaddr_t *route, uip_ipaddr_t *ipaddr,
|
||||
|
@ -136,6 +139,7 @@ route_callback(int event, uip_ipaddr_t *route, uip_ipaddr_t *ipaddr,
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uip_ipaddr_t *
|
||||
set_global_address(void)
|
||||
|
@ -171,7 +175,9 @@ rpl_dag_root_init(void)
|
|||
if(!initialized) {
|
||||
to_become_root = 0;
|
||||
set_global_address();
|
||||
#if (UIP_CONF_MAX_ROUTES != 0)
|
||||
uip_ds6_notification_add(&n, route_callback);
|
||||
#endif /* (UIP_CONF_MAX_ROUTES != 0) */
|
||||
initialized = 1;
|
||||
}
|
||||
}
|
||||
|
@ -206,7 +212,9 @@ rpl_dag_root_init_dag_immediately(void)
|
|||
|
||||
/* If there are routes in this dag, we remove them all as we are
|
||||
from now on the new dag root and the old routes are wrong */
|
||||
rpl_remove_routes(dag);
|
||||
if(RPL_IS_STORING(dag->instance)) {
|
||||
rpl_remove_routes(dag);
|
||||
}
|
||||
if(dag->instance != NULL &&
|
||||
dag->instance->def_route != NULL) {
|
||||
uip_ds6_defrt_rm(dag->instance->def_route);
|
||||
|
|
|
@ -98,8 +98,8 @@ rpl_print_neighbor_list(void)
|
|||
rpl_parent_t *p = nbr_table_head(rpl_parents);
|
||||
clock_time_t clock_now = clock_time();
|
||||
|
||||
printf("RPL: OCP %u rank %u dioint %u, nbr count %u\n",
|
||||
default_instance->of->ocp, curr_rank, curr_dio_interval, uip_ds6_nbr_num());
|
||||
printf("RPL: MOP %u OCP %u rank %u dioint %u, nbr count %u\n",
|
||||
default_instance->mop, default_instance->of->ocp, curr_rank, curr_dio_interval, uip_ds6_nbr_num());
|
||||
while(p != NULL) {
|
||||
const struct link_stats *stats = rpl_get_parent_link_stats(p);
|
||||
printf("RPL: nbr %3u %5u, %5u => %5u -- %2u %c%c (last tx %u min ago)\n",
|
||||
|
@ -418,7 +418,9 @@ rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id)
|
|||
|
||||
if(instance->current_dag != dag && instance->current_dag != NULL) {
|
||||
/* Remove routes installed by DAOs. */
|
||||
rpl_remove_routes(instance->current_dag);
|
||||
if(RPL_IS_STORING(instance)) {
|
||||
rpl_remove_routes(instance->current_dag);
|
||||
}
|
||||
|
||||
instance->current_dag->joined = 0;
|
||||
}
|
||||
|
@ -667,7 +669,9 @@ rpl_free_dag(rpl_dag_t *dag)
|
|||
dag->joined = 0;
|
||||
|
||||
/* Remove routes installed by DAOs. */
|
||||
rpl_remove_routes(dag);
|
||||
if(RPL_IS_STORING(dag->instance)) {
|
||||
rpl_remove_routes(dag);
|
||||
}
|
||||
|
||||
/* Remove autoconfigured address */
|
||||
if((dag->prefix_info.flags & UIP_ND6_RA_FLAG_AUTONOMOUS)) {
|
||||
|
@ -787,7 +791,9 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
|
|||
|
||||
if(instance->current_dag != best_dag) {
|
||||
/* Remove routes installed by DAOs. */
|
||||
rpl_remove_routes(instance->current_dag);
|
||||
if(RPL_IS_STORING(instance)) {
|
||||
rpl_remove_routes(instance->current_dag);
|
||||
}
|
||||
|
||||
PRINTF("RPL: New preferred DAG: ");
|
||||
PRINT6ADDR(&best_dag->dag_id);
|
||||
|
@ -816,7 +822,7 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
|
|||
if(!acceptable_rank(best_dag, best_dag->rank)) {
|
||||
PRINTF("RPL: New rank unacceptable!\n");
|
||||
rpl_set_preferred_parent(instance->current_dag, NULL);
|
||||
if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES && last_parent != NULL) {
|
||||
if(RPL_IS_STORING(instance) && last_parent != NULL) {
|
||||
/* Send a No-Path DAO to the removed preferred parent. */
|
||||
dao_output(last_parent, RPL_ZERO_LIFETIME);
|
||||
}
|
||||
|
@ -828,15 +834,13 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
|
|||
PRINTF("RPL: Changed preferred parent, rank changed from %u to %u\n",
|
||||
(unsigned)old_rank, best_dag->rank);
|
||||
RPL_STAT(rpl_stats.parent_switch++);
|
||||
if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
|
||||
if(last_parent != NULL) {
|
||||
/* Send a No-Path DAO to the removed preferred parent. */
|
||||
dao_output(last_parent, RPL_ZERO_LIFETIME);
|
||||
}
|
||||
/* The DAO parent set changed - schedule a DAO transmission. */
|
||||
RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
|
||||
rpl_schedule_dao(instance);
|
||||
if(RPL_IS_STORING(instance) && last_parent != NULL) {
|
||||
/* Send a No-Path DAO to the removed preferred parent. */
|
||||
dao_output(last_parent, RPL_ZERO_LIFETIME);
|
||||
}
|
||||
/* The DAO parent set changed - schedule a DAO transmission. */
|
||||
RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
|
||||
rpl_schedule_dao(instance);
|
||||
rpl_reset_dio_timer(instance);
|
||||
#if DEBUG
|
||||
rpl_print_neighbor_list();
|
||||
|
@ -954,9 +958,11 @@ rpl_nullify_parent(rpl_parent_t *parent)
|
|||
uip_ds6_defrt_rm(dag->instance->def_route);
|
||||
dag->instance->def_route = NULL;
|
||||
}
|
||||
/* Send No-Path DAO only to preferred parent, if any */
|
||||
/* Send No-Path DAO only when nullifying preferred parent */
|
||||
if(parent == dag->preferred_parent) {
|
||||
dao_output(parent, RPL_ZERO_LIFETIME);
|
||||
if(RPL_IS_STORING(dag->instance)) {
|
||||
dao_output(parent, RPL_ZERO_LIFETIME);
|
||||
}
|
||||
rpl_set_preferred_parent(dag, NULL);
|
||||
}
|
||||
}
|
||||
|
@ -982,8 +988,10 @@ rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent)
|
|||
dag_src->instance->def_route = NULL;
|
||||
}
|
||||
} else if(dag_src->joined) {
|
||||
/* Remove uIPv6 routes that have this parent as the next hop. */
|
||||
rpl_remove_routes_by_nexthop(rpl_get_parent_ipaddr(parent), dag_src);
|
||||
if(RPL_IS_STORING(dag_src->instance)) {
|
||||
/* Remove uIPv6 routes that have this parent as the next hop. */
|
||||
rpl_remove_routes_by_nexthop(rpl_get_parent_ipaddr(parent), dag_src);
|
||||
}
|
||||
}
|
||||
|
||||
PRINTF("RPL: Moving parent ");
|
||||
|
@ -1006,6 +1014,25 @@ rpl_has_downward_route(void)
|
|||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
rpl_dag_t *
|
||||
rpl_get_dag(const uip_ipaddr_t *addr)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for(i = 0; i < RPL_MAX_INSTANCES; ++i) {
|
||||
if(instance_table[i].used) {
|
||||
for(j = 0; j < RPL_MAX_DAG_PER_INSTANCE; ++j) {
|
||||
if(instance_table[i].dag_table[j].joined
|
||||
&& uip_ipaddr_prefixcmp(&instance_table[i].dag_table[j].dag_id, addr,
|
||||
instance_table[i].dag_table[j].prefix_info.length)) {
|
||||
return &instance_table[i].dag_table[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
rpl_dag_t *
|
||||
rpl_get_any_dag(void)
|
||||
{
|
||||
int i;
|
||||
|
@ -1055,6 +1082,12 @@ rpl_join_instance(uip_ipaddr_t *from, rpl_dio_t *dio)
|
|||
rpl_parent_t *p;
|
||||
rpl_of_t *of;
|
||||
|
||||
if((!RPL_WITH_NON_STORING && dio->mop == RPL_MOP_NON_STORING)
|
||||
|| (!RPL_WITH_STORING && (dio->mop == RPL_MOP_STORING_NO_MULTICAST
|
||||
|| dio->mop == RPL_MOP_STORING_MULTICAST))) {
|
||||
PRINTF("RPL: DIO advertising a non-supported MOP %u\n", dio->mop);
|
||||
}
|
||||
|
||||
/* Determine the objective function by using the
|
||||
objective code point of the DIO. */
|
||||
of = rpl_find_of(dio->ocp);
|
||||
|
@ -1333,7 +1366,9 @@ rpl_process_parent_event(rpl_instance_t *instance, rpl_parent_t *p)
|
|||
|
||||
return_value = 1;
|
||||
|
||||
if(uip_ds6_route_is_nexthop(rpl_get_parent_ipaddr(p)) && !rpl_parent_is_reachable(p)) {
|
||||
if(RPL_IS_STORING(instance)
|
||||
&& uip_ds6_route_is_nexthop(rpl_get_parent_ipaddr(p))
|
||||
&& !rpl_parent_is_reachable(p) && instance->mop > RPL_MOP_NON_STORING) {
|
||||
PRINTF("RPL: Unacceptable link %u, removing routes via: ", rpl_get_parent_link_metric(p));
|
||||
PRINT6ADDR(rpl_get_parent_ipaddr(p));
|
||||
PRINTF("\n");
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "net/ip/tcpip.h"
|
||||
#include "net/ipv6/uip-ds6.h"
|
||||
#include "net/rpl/rpl-private.h"
|
||||
#include "net/rpl/rpl-ns.h"
|
||||
#include "net/packetbuf.h"
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
|
@ -61,12 +62,14 @@
|
|||
#define UIP_EXT_BUF ((struct uip_ext_hdr *)&uip_buf[uip_l2_l3_hdr_len])
|
||||
#define UIP_HBHO_BUF ((struct uip_hbho_hdr *)&uip_buf[uip_l2_l3_hdr_len])
|
||||
#define UIP_HBHO_NEXT_BUF ((struct uip_ext_hdr *)&uip_buf[uip_l2_l3_hdr_len + RPL_HOP_BY_HOP_LEN])
|
||||
#define UIP_RH_BUF ((struct uip_routing_hdr *)&uip_buf[uip_l2_l3_hdr_len])
|
||||
#define UIP_RPL_SRH_BUF ((struct uip_rpl_srh_hdr *)&uip_buf[uip_l2_l3_hdr_len + RPL_RH_LEN])
|
||||
#define UIP_EXT_HDR_OPT_BUF ((struct uip_ext_hdr_opt *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset])
|
||||
#define UIP_EXT_HDR_OPT_PADN_BUF ((struct uip_ext_hdr_opt_padn *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset])
|
||||
#define UIP_EXT_HDR_OPT_RPL_BUF ((struct uip_ext_hdr_opt_rpl *)&uip_buf[uip_l2_l3_hdr_len + uip_ext_opt_offset])
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
rpl_verify_header(int uip_ext_opt_offset)
|
||||
rpl_verify_hbh_header(int uip_ext_opt_offset)
|
||||
{
|
||||
rpl_instance_t *instance;
|
||||
int down;
|
||||
|
@ -100,12 +103,14 @@ rpl_verify_header(int uip_ext_opt_offset)
|
|||
if(UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_FWD_ERR) {
|
||||
PRINTF("RPL: Forward error!\n");
|
||||
/* We should try to repair it by removing the neighbor that caused
|
||||
the packet to be forwareded in the first place. We drop any
|
||||
routes that go through the neighbor that sent the packet to
|
||||
us. */
|
||||
route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr);
|
||||
if(route != NULL) {
|
||||
uip_ds6_route_rm(route);
|
||||
the packet to be forwareded in the first place. We drop any
|
||||
routes that go through the neighbor that sent the packet to
|
||||
us. */
|
||||
if(RPL_IS_STORING(instance)) {
|
||||
route = uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr);
|
||||
if(route != NULL) {
|
||||
uip_ds6_route_rm(route);
|
||||
}
|
||||
}
|
||||
RPL_STAT(rpl_stats.forward_errors++);
|
||||
/* Trigger DAO retransmission */
|
||||
|
@ -166,35 +171,299 @@ rpl_verify_header(int uip_ext_opt_offset)
|
|||
}
|
||||
|
||||
PRINTF("RPL: Rank OK\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
set_rpl_opt(unsigned uip_ext_opt_offset)
|
||||
#if RPL_WITH_NON_STORING
|
||||
int
|
||||
rpl_srh_get_next_hop(uip_ipaddr_t *ipaddr)
|
||||
{
|
||||
uint8_t temp_len;
|
||||
uint8_t *uip_next_hdr;
|
||||
int last_uip_ext_len = uip_ext_len;
|
||||
|
||||
memmove(UIP_HBHO_NEXT_BUF, UIP_EXT_BUF, uip_len - UIP_IPH_LEN);
|
||||
memset(UIP_HBHO_BUF, 0, RPL_HOP_BY_HOP_LEN);
|
||||
UIP_HBHO_BUF->next = UIP_IP_BUF->proto;
|
||||
UIP_IP_BUF->proto = UIP_PROTO_HBHO;
|
||||
UIP_HBHO_BUF->len = RPL_HOP_BY_HOP_LEN - 8;
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->opt_type = UIP_EXT_HDR_OPT_RPL;
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->opt_len = RPL_HDR_OPT_LEN;
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->flags = 0;
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->instance = 0;
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->senderrank = 0;
|
||||
uip_len += RPL_HOP_BY_HOP_LEN;
|
||||
temp_len = UIP_IP_BUF->len[1];
|
||||
UIP_IP_BUF->len[1] += UIP_HBHO_BUF->len + 8;
|
||||
if(UIP_IP_BUF->len[1] < temp_len) {
|
||||
UIP_IP_BUF->len[0]++;
|
||||
uip_ext_len = 0;
|
||||
uip_next_hdr = &UIP_IP_BUF->proto;
|
||||
|
||||
/* Look for routing header */
|
||||
while(uip_next_hdr != NULL && *uip_next_hdr != UIP_PROTO_ROUTING) {
|
||||
switch(*uip_next_hdr) {
|
||||
case UIP_PROTO_TCP:
|
||||
case UIP_PROTO_UDP:
|
||||
case UIP_PROTO_ICMP6:
|
||||
case UIP_PROTO_NONE:
|
||||
uip_next_hdr = NULL;
|
||||
break;
|
||||
case UIP_PROTO_HBHO:
|
||||
case UIP_PROTO_DESTO:
|
||||
case UIP_PROTO_FRAG:
|
||||
/* Move to next header */
|
||||
if(uip_next_hdr != &UIP_IP_BUF->proto) {
|
||||
uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
|
||||
}
|
||||
uip_next_hdr = &UIP_EXT_BUF->next;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(uip_next_hdr != NULL && *uip_next_hdr == UIP_PROTO_ROUTING
|
||||
&& UIP_RH_BUF->routing_type == RPL_RH_TYPE_SRH) {
|
||||
/* Routing header found. The next hop should be already copied as the IPv6 destination
|
||||
* address, via rpl_process_srh_header. We turn this address into a link-local to enable
|
||||
* forwarding to next hop */
|
||||
uip_ipaddr_copy(ipaddr, &UIP_IP_BUF->destipaddr);
|
||||
uip_create_linklocal_prefix(ipaddr);
|
||||
uip_ext_len = last_uip_ext_len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
uip_ext_len = last_uip_ext_len;
|
||||
return 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
rpl_update_header_empty(void)
|
||||
rpl_process_srh_header(void)
|
||||
{
|
||||
uint8_t *uip_next_hdr;
|
||||
int last_uip_ext_len = uip_ext_len;
|
||||
|
||||
uip_ext_len = 0;
|
||||
uip_next_hdr = &UIP_IP_BUF->proto;
|
||||
|
||||
/* Look for routing header */
|
||||
while(uip_next_hdr != NULL && *uip_next_hdr != UIP_PROTO_ROUTING) {
|
||||
switch(*uip_next_hdr) {
|
||||
case UIP_PROTO_TCP:
|
||||
case UIP_PROTO_UDP:
|
||||
case UIP_PROTO_ICMP6:
|
||||
case UIP_PROTO_NONE:
|
||||
uip_next_hdr = NULL;
|
||||
break;
|
||||
case UIP_PROTO_HBHO:
|
||||
case UIP_PROTO_DESTO:
|
||||
case UIP_PROTO_FRAG:
|
||||
/* Move to next header */
|
||||
if(uip_next_hdr != &UIP_IP_BUF->proto) {
|
||||
uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
|
||||
}
|
||||
uip_next_hdr = &UIP_EXT_BUF->next;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(uip_next_hdr != NULL && *uip_next_hdr == UIP_PROTO_ROUTING
|
||||
&& UIP_RH_BUF->routing_type == RPL_RH_TYPE_SRH) {
|
||||
/* SRH found, now look for next hop */
|
||||
uint8_t cmpri, cmpre;
|
||||
uint8_t ext_len;
|
||||
uint8_t padding;
|
||||
uint8_t path_len;
|
||||
uint8_t segments_left;
|
||||
uip_ipaddr_t current_dest_addr;
|
||||
|
||||
segments_left = UIP_RH_BUF->seg_left;
|
||||
ext_len = (UIP_RH_BUF->len * 8) + 8;
|
||||
cmpri = UIP_RPL_SRH_BUF->cmpr >> 4;
|
||||
cmpre = UIP_RPL_SRH_BUF->cmpr & 0x0f;
|
||||
padding = UIP_RPL_SRH_BUF->pad >> 4;
|
||||
path_len = ((ext_len - padding - RPL_RH_LEN - RPL_SRH_LEN - (16 - cmpre)) / (16 - cmpri)) + 1;
|
||||
(void)path_len;
|
||||
|
||||
PRINTF("RPL: read SRH, path len %u, segments left %u, Cmpri %u, Cmpre %u, ext len %u (padding %u)\n",
|
||||
path_len, segments_left, cmpri, cmpre, ext_len, padding);
|
||||
|
||||
if(segments_left == 0) {
|
||||
/* We are the final destination, do nothing */
|
||||
} else {
|
||||
uint8_t i = path_len - segments_left; /* The index of the next address to be visited */
|
||||
uint8_t *addr_ptr = ((uint8_t *)UIP_RH_BUF) + RPL_RH_LEN + RPL_SRH_LEN + (i * (16 - cmpri));
|
||||
uint8_t cmpr = segments_left == 1 ? cmpre : cmpri;
|
||||
|
||||
/* As per RFC6554: swap the IPv6 destination address and address[i] */
|
||||
|
||||
/* First, copy the current IPv6 destination address */
|
||||
uip_ipaddr_copy(¤t_dest_addr, &UIP_IP_BUF->destipaddr);
|
||||
/* Second, update the IPv6 destination address with addresses[i] */
|
||||
memcpy(((uint8_t *)&UIP_IP_BUF->destipaddr) + cmpr, addr_ptr, 16 - cmpr);
|
||||
/* Third, write current_dest_addr to addresses[i] */
|
||||
memcpy(addr_ptr, ((uint8_t *)¤t_dest_addr) + cmpr, 16 - cmpr);
|
||||
|
||||
/* Update segments left field */
|
||||
UIP_RH_BUF->seg_left--;
|
||||
|
||||
PRINTF("RPL: SRH next hop ");
|
||||
PRINT6ADDR(&UIP_IP_BUF->destipaddr);
|
||||
PRINTF("\n");
|
||||
}
|
||||
uip_ext_len = last_uip_ext_len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
uip_ext_len = last_uip_ext_len;
|
||||
return 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
count_matching_bytes(const void *p1, const void *p2, size_t n)
|
||||
{
|
||||
int i = 0;
|
||||
for(i = 0; i < n; i++) {
|
||||
if(((uint8_t *)p1)[i] != ((uint8_t *)p2)[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
insert_srh_header(void)
|
||||
{
|
||||
/* Implementation of RFC6554 */
|
||||
uint8_t temp_len;
|
||||
uint8_t path_len;
|
||||
uint8_t ext_len;
|
||||
uint8_t cmpri, cmpre; /* ComprI and ComprE fields of the RPL Source Routing Header */
|
||||
uint8_t *hop_ptr;
|
||||
uint8_t padding;
|
||||
rpl_ns_node_t *dest_node;
|
||||
rpl_ns_node_t *root_node;
|
||||
rpl_ns_node_t *node;
|
||||
rpl_dag_t *dag;
|
||||
uip_ipaddr_t node_addr;
|
||||
|
||||
PRINTF("RPL: SRH creating source routing header with destination ");
|
||||
PRINT6ADDR(&UIP_IP_BUF->destipaddr);
|
||||
PRINTF(" \n");
|
||||
|
||||
/* Construct source route. We do not do this recursively to keep the runtime stack usage constant. */
|
||||
|
||||
/* Get link of the destination and root */
|
||||
dag = rpl_get_dag(&UIP_IP_BUF->destipaddr);
|
||||
|
||||
if(dag == NULL) {
|
||||
PRINTF("RPL: SRH DAG not found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dest_node = rpl_ns_get_node(dag, &UIP_IP_BUF->destipaddr);
|
||||
if(dest_node == NULL) {
|
||||
/* The destination is not found, skip SRH insertion */
|
||||
return 1;
|
||||
}
|
||||
|
||||
root_node = rpl_ns_get_node(dag, &dag->dag_id);
|
||||
if(root_node == NULL) {
|
||||
PRINTF("RPL: SRH root node not found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!rpl_ns_is_node_reachable(dag, &UIP_IP_BUF->destipaddr)) {
|
||||
PRINTF("RPL: SRH no path found to destination\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute path length and compression factors (we use cmpri == cmpre) */
|
||||
path_len = 0;
|
||||
node = dest_node->parent;
|
||||
/* For simplicity, we use cmpri = cmpre */
|
||||
cmpri = 15;
|
||||
cmpre = 15;
|
||||
while(node != NULL && node != root_node) {
|
||||
|
||||
rpl_ns_get_node_global_addr(&node_addr, node);
|
||||
|
||||
/* How many bytes in common between all nodes in the path? */
|
||||
cmpri = MIN(cmpri, count_matching_bytes(&node_addr, &UIP_IP_BUF->destipaddr, 16));
|
||||
cmpre = cmpri;
|
||||
|
||||
PRINTF("RPL: SRH Hop ");
|
||||
PRINT6ADDR(&node_addr);
|
||||
PRINTF("\n");
|
||||
node = node->parent;
|
||||
path_len++;
|
||||
}
|
||||
|
||||
if(((DEBUG) & DEBUG_PRINT) && node != NULL) {
|
||||
rpl_ns_get_node_global_addr(&node_addr, node);
|
||||
PRINTF("RPL: SRH Next Hop ");
|
||||
PRINT6ADDR(&node_addr);
|
||||
PRINTF("\n");
|
||||
}
|
||||
|
||||
/* Extension header length: fixed headers + (n-1) * (16-ComprI) + (16-ComprE)*/
|
||||
ext_len = RPL_RH_LEN + RPL_SRH_LEN
|
||||
+ (path_len - 1) * (16 - cmpre)
|
||||
+ (16 - cmpri);
|
||||
|
||||
padding = ext_len % 8 == 0 ? 0 : (8 - (ext_len % 8));
|
||||
ext_len += padding;
|
||||
|
||||
PRINTF("RPL: SRH Path len: %u, ComprI %u, ComprE %u, ext len %u (padding %u)\n",
|
||||
path_len, cmpri, cmpre, ext_len, padding);
|
||||
|
||||
/* Check if there is enough space to store the extension header */
|
||||
if(uip_len + ext_len > UIP_BUFSIZE) {
|
||||
PRINTF("RPL: Packet too long: impossible to add source routing header (%u bytes)\n", ext_len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Move existing ext headers and payload uip_ext_len further */
|
||||
memmove(uip_buf + uip_l2_l3_hdr_len + ext_len,
|
||||
uip_buf + uip_l2_l3_hdr_len, uip_len - UIP_IPH_LEN);
|
||||
memset(uip_buf + uip_l2_l3_hdr_len, 0, ext_len);
|
||||
|
||||
/* Insert source routing header */
|
||||
UIP_RH_BUF->next = UIP_IP_BUF->proto;
|
||||
UIP_IP_BUF->proto = UIP_PROTO_ROUTING;
|
||||
|
||||
/* Initialize IPv6 Routing Header */
|
||||
UIP_RH_BUF->len = (ext_len - 8) / 8;
|
||||
UIP_RH_BUF->routing_type = RPL_RH_TYPE_SRH;
|
||||
UIP_RH_BUF->seg_left = path_len;
|
||||
|
||||
/* Initialize RPL Source Routing Header */
|
||||
UIP_RPL_SRH_BUF->cmpr = (cmpri << 4) + cmpre;
|
||||
UIP_RPL_SRH_BUF->pad = padding << 4;
|
||||
|
||||
/* Initialize addresses field (the actual source route).
|
||||
* From last to first. */
|
||||
node = dest_node;
|
||||
hop_ptr = ((uint8_t *)UIP_RH_BUF) + ext_len - padding; /* Pointer where to write the next hop compressed address */
|
||||
|
||||
while(node != NULL && node->parent != root_node) {
|
||||
rpl_ns_get_node_global_addr(&node_addr, node);
|
||||
|
||||
hop_ptr -= (16 - cmpri);
|
||||
memcpy(hop_ptr, ((uint8_t*)&node_addr) + cmpri, 16 - cmpri);
|
||||
|
||||
node = node->parent;
|
||||
}
|
||||
|
||||
/* The next hop (i.e. node whose parent is the root) is placed as the current IPv6 destination */
|
||||
rpl_ns_get_node_global_addr(&node_addr, node);
|
||||
uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &node_addr);
|
||||
|
||||
/* In-place update of IPv6 length field */
|
||||
temp_len = UIP_IP_BUF->len[1];
|
||||
UIP_IP_BUF->len[1] += ext_len;
|
||||
if(UIP_IP_BUF->len[1] < temp_len) {
|
||||
UIP_IP_BUF->len[0]++;
|
||||
}
|
||||
|
||||
uip_ext_len += ext_len;
|
||||
uip_len += ext_len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#else /* RPL_WITH_NON_STORING */
|
||||
int insert_srh_header(void);
|
||||
#endif /* RPL_WITH_NON_STORING */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
update_hbh_header(void)
|
||||
{
|
||||
rpl_instance_t *instance;
|
||||
int uip_ext_opt_offset;
|
||||
|
@ -212,36 +481,27 @@ rpl_update_header_empty(void)
|
|||
if(UIP_HBHO_BUF->len != RPL_HOP_BY_HOP_LEN - 8) {
|
||||
PRINTF("RPL: Hop-by-hop extension header has wrong size\n");
|
||||
uip_ext_len = last_uip_ext_len;
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
if(UIP_EXT_HDR_OPT_RPL_BUF->opt_type != UIP_EXT_HDR_OPT_RPL) {
|
||||
PRINTF("RPL: Non RPL Hop-by-hop option support not implemented\n");
|
||||
uip_ext_len = last_uip_ext_len;
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
if(UIP_EXT_HDR_OPT_RPL_BUF->opt_len != RPL_HDR_OPT_LEN) {
|
||||
PRINTF("RPL: RPL Hop-by-hop option has wrong length\n");
|
||||
uip_ext_len = last_uip_ext_len;
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
instance = rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance);
|
||||
if(instance == NULL || !instance->used || !instance->current_dag->joined) {
|
||||
PRINTF("RPL: Unable to add hop-by-hop extension header: incorrect instance\n");
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
#if RPL_INSERT_HBH_OPTION
|
||||
PRINTF("RPL: No hop-by-hop option found, creating it\n");
|
||||
if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_BUFSIZE) {
|
||||
PRINTF("RPL: Packet too long: impossible to add hop-by-hop option\n");
|
||||
uip_ext_len = last_uip_ext_len;
|
||||
return 0;
|
||||
}
|
||||
set_rpl_opt(uip_ext_opt_offset);
|
||||
uip_ext_len = last_uip_ext_len + RPL_HOP_BY_HOP_LEN;
|
||||
#endif
|
||||
return 0;
|
||||
PRINTF("RPL: No hop-by-hop option found\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch(UIP_EXT_HDR_OPT_BUF->type) {
|
||||
|
@ -249,51 +509,98 @@ rpl_update_header_empty(void)
|
|||
PRINTF("RPL: Updating RPL option\n");
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(instance->current_dag->rank);
|
||||
|
||||
/* Check the direction of the down flag, as per Section 11.2.2.3,
|
||||
which states that if a packet is going down it should in
|
||||
general not go back up again. If this happens, a
|
||||
RPL_HDR_OPT_FWD_ERR should be flagged. */
|
||||
if((UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN)) {
|
||||
if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_FWD_ERR;
|
||||
PRINTF("RPL forwarding error\n");
|
||||
/* We should send back the packet to the originating parent,
|
||||
but it is not feasible yet, so we send a No-Path DAO instead */
|
||||
PRINTF("RPL generate No-Path DAO\n");
|
||||
parent = rpl_get_parent((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
||||
if(parent != NULL) {
|
||||
dao_output_target(parent, &UIP_IP_BUF->destipaddr, RPL_ZERO_LIFETIME);
|
||||
if(RPL_IS_STORING(instance)) { /* In non-storing mode, downwards traffic does not have the HBH option */
|
||||
/* Check the direction of the down flag, as per Section 11.2.2.3,
|
||||
which states that if a packet is going down it should in
|
||||
general not go back up again. If this happens, a
|
||||
RPL_HDR_OPT_FWD_ERR should be flagged. */
|
||||
if((UIP_EXT_HDR_OPT_RPL_BUF->flags & RPL_HDR_OPT_DOWN)) {
|
||||
if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_FWD_ERR;
|
||||
PRINTF("RPL forwarding error\n");
|
||||
/* We should send back the packet to the originating parent,
|
||||
but it is not feasible yet, so we send a No-Path DAO instead */
|
||||
PRINTF("RPL generate No-Path DAO\n");
|
||||
parent = rpl_get_parent((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
||||
if(parent != NULL) {
|
||||
dao_output_target(parent, &UIP_IP_BUF->destipaddr, RPL_ZERO_LIFETIME);
|
||||
}
|
||||
/* Drop packet */
|
||||
return 0;
|
||||
}
|
||||
/* Drop packet */
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
/* Set the down extension flag correctly as described in Section
|
||||
11.2 of RFC6550. If the packet progresses along a DAO route,
|
||||
the down flag should be set. */
|
||||
if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
|
||||
/* No route was found, so this packet will go towards the RPL
|
||||
root. If so, we should not set the down flag. */
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_DOWN;
|
||||
PRINTF("RPL option going up\n");
|
||||
} else {
|
||||
/* A DAO route was found so we set the down flag. */
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_DOWN;
|
||||
PRINTF("RPL option going down\n");
|
||||
/* Set the down extension flag correctly as described in Section
|
||||
11.2 of RFC6550. If the packet progresses along a DAO route,
|
||||
the down flag should be set. */
|
||||
if(uip_ds6_route_lookup(&UIP_IP_BUF->destipaddr) == NULL) {
|
||||
/* No route was found, so this packet will go towards the RPL
|
||||
root. If so, we should not set the down flag. */
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->flags &= ~RPL_HDR_OPT_DOWN;
|
||||
PRINTF("RPL option going up\n");
|
||||
} else {
|
||||
/* A DAO route was found so we set the down flag. */
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->flags |= RPL_HDR_OPT_DOWN;
|
||||
PRINTF("RPL option going down\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uip_ext_len = last_uip_ext_len;
|
||||
return 0;
|
||||
return 1;
|
||||
default:
|
||||
PRINTF("RPL: Multi Hop-by-hop options not implemented\n");
|
||||
uip_ext_len = last_uip_ext_len;
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
insert_hbh_header(void)
|
||||
{
|
||||
int uip_ext_opt_offset;
|
||||
int last_uip_ext_len;
|
||||
uint8_t temp_len;
|
||||
|
||||
last_uip_ext_len = uip_ext_len;
|
||||
uip_ext_len = 0;
|
||||
uip_ext_opt_offset = 2;
|
||||
|
||||
/* Insert hop-by-hop header */
|
||||
PRINTF("RPL: Creating hop-by-hop option\n");
|
||||
if(uip_len + RPL_HOP_BY_HOP_LEN > UIP_BUFSIZE) {
|
||||
PRINTF("RPL: Packet too long: impossible to add hop-by-hop option\n");
|
||||
uip_ext_len = last_uip_ext_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Move existing ext headers and payload UIP_EXT_BUF further */
|
||||
memmove(UIP_HBHO_NEXT_BUF, UIP_EXT_BUF, uip_len - UIP_IPH_LEN);
|
||||
memset(UIP_HBHO_BUF, 0, RPL_HOP_BY_HOP_LEN);
|
||||
|
||||
/* Update IP and HBH protocol and fields */
|
||||
UIP_HBHO_BUF->next = UIP_IP_BUF->proto;
|
||||
UIP_IP_BUF->proto = UIP_PROTO_HBHO;
|
||||
|
||||
/* Initialize HBH option */
|
||||
UIP_HBHO_BUF->len = (RPL_HOP_BY_HOP_LEN - 8) / 8;
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->opt_type = UIP_EXT_HDR_OPT_RPL;
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->opt_len = RPL_HDR_OPT_LEN;
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->flags = 0;
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->instance = 0;
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->senderrank = 0;
|
||||
uip_len += RPL_HOP_BY_HOP_LEN;
|
||||
temp_len = UIP_IP_BUF->len[1];
|
||||
UIP_IP_BUF->len[1] += UIP_HBHO_BUF->len + 8;
|
||||
if(UIP_IP_BUF->len[1] < temp_len) {
|
||||
UIP_IP_BUF->len[0]++;
|
||||
}
|
||||
|
||||
uip_ext_len = last_uip_ext_len + RPL_HOP_BY_HOP_LEN;
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
rpl_update_header_final(uip_ipaddr_t *addr)
|
||||
rpl_finalize_header(uip_ipaddr_t *addr)
|
||||
{
|
||||
rpl_parent_t *parent;
|
||||
int uip_ext_opt_offset;
|
||||
|
@ -307,7 +614,7 @@ rpl_update_header_final(uip_ipaddr_t *addr)
|
|||
if(UIP_HBHO_BUF->len != RPL_HOP_BY_HOP_LEN - 8) {
|
||||
PRINTF("RPL: Non RPL Hop-by-hop options support not implemented\n");
|
||||
uip_ext_len = last_uip_ext_len;
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(UIP_EXT_HDR_OPT_BUF->type == UIP_EXT_HDR_OPT_RPL) {
|
||||
|
@ -315,7 +622,7 @@ rpl_update_header_final(uip_ipaddr_t *addr)
|
|||
PRINTF("RPL: Updating RPL option\n");
|
||||
if(default_instance == NULL || !default_instance->used || !default_instance->current_dag->joined) {
|
||||
PRINTF("RPL: Unable to add hop-by-hop extension header: incorrect default instance\n");
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
parent = rpl_find_parent(default_instance->current_dag, addr);
|
||||
if(parent == NULL || parent != parent->dag->preferred_parent) {
|
||||
|
@ -326,78 +633,101 @@ rpl_update_header_final(uip_ipaddr_t *addr)
|
|||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_remove_header(void)
|
||||
{
|
||||
uint8_t temp_len;
|
||||
uint8_t rpl_ext_hdr_len;
|
||||
uint8_t *uip_next_hdr;
|
||||
|
||||
uip_ext_len = 0;
|
||||
uip_next_hdr = &UIP_IP_BUF->proto;
|
||||
|
||||
PRINTF("RPL: Verifying the presence of the RPL header option\n");
|
||||
switch(UIP_IP_BUF->proto){
|
||||
case UIP_PROTO_HBHO:
|
||||
PRINTF("RPL: Removing the RPL header option\n");
|
||||
UIP_IP_BUF->proto = UIP_HBHO_BUF->next;
|
||||
temp_len = UIP_IP_BUF->len[1];
|
||||
uip_len -= UIP_HBHO_BUF->len + 8;
|
||||
UIP_IP_BUF->len[1] -= UIP_HBHO_BUF->len + 8;
|
||||
if(UIP_IP_BUF->len[1] > temp_len) {
|
||||
UIP_IP_BUF->len[0]--;
|
||||
PRINTF("RPL: Verifying the presence of RPL extension headers\n");
|
||||
|
||||
/* Look for hop-by-hop and routing headers */
|
||||
while(uip_next_hdr != NULL) {
|
||||
switch(*uip_next_hdr) {
|
||||
case UIP_PROTO_TCP:
|
||||
case UIP_PROTO_UDP:
|
||||
case UIP_PROTO_ICMP6:
|
||||
case UIP_PROTO_NONE:
|
||||
return;
|
||||
case UIP_PROTO_HBHO:
|
||||
case UIP_PROTO_ROUTING:
|
||||
/* Remove hop-by-hop and routing headers */
|
||||
*uip_next_hdr = UIP_EXT_BUF->next;
|
||||
rpl_ext_hdr_len = (UIP_EXT_BUF->len * 8) + 8;
|
||||
temp_len = UIP_IP_BUF->len[1];
|
||||
uip_len -= rpl_ext_hdr_len;
|
||||
UIP_IP_BUF->len[1] -= rpl_ext_hdr_len;
|
||||
if(UIP_IP_BUF->len[1] > temp_len) {
|
||||
UIP_IP_BUF->len[0]--;
|
||||
}
|
||||
PRINTF("RPL: Removing RPL extension header (type %u, len %u)\n", *uip_next_hdr, rpl_ext_hdr_len);
|
||||
memmove(UIP_EXT_BUF, ((uint8_t *)UIP_EXT_BUF) + rpl_ext_hdr_len, uip_len - UIP_IPH_LEN);
|
||||
break;
|
||||
default:
|
||||
/* Move to next header */
|
||||
if(uip_next_hdr != &UIP_IP_BUF->proto) {
|
||||
uip_ext_len += (UIP_EXT_BUF->len << 3) + 8;
|
||||
}
|
||||
uip_next_hdr = &UIP_EXT_BUF->next;
|
||||
break;
|
||||
}
|
||||
memmove(UIP_EXT_BUF, UIP_HBHO_NEXT_BUF, uip_len - UIP_IPH_LEN);
|
||||
break;
|
||||
default:
|
||||
PRINTF("RPL: No hop-by-hop Option found\n");
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint8_t
|
||||
rpl_invert_header(void)
|
||||
{
|
||||
uint8_t uip_ext_opt_offset;
|
||||
uint8_t last_uip_ext_len;
|
||||
|
||||
last_uip_ext_len = uip_ext_len;
|
||||
uip_ext_len = 0;
|
||||
uip_ext_opt_offset = 2;
|
||||
|
||||
PRINTF("RPL: Verifying the presence of the RPL header option\n");
|
||||
switch(UIP_IP_BUF->proto) {
|
||||
case UIP_PROTO_HBHO:
|
||||
break;
|
||||
default:
|
||||
PRINTF("RPL: No hop-by-hop Option found\n");
|
||||
uip_ext_len = last_uip_ext_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (UIP_EXT_HDR_OPT_BUF->type) {
|
||||
case UIP_EXT_HDR_OPT_RPL:
|
||||
PRINTF("RPL: Updating RPL option (switching direction)\n");
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->flags &= RPL_HDR_OPT_DOWN;
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->flags ^= RPL_HDR_OPT_DOWN;
|
||||
UIP_EXT_HDR_OPT_RPL_BUF->senderrank = UIP_HTONS(rpl_get_instance(UIP_EXT_HDR_OPT_RPL_BUF->instance)->current_dag->rank);
|
||||
uip_ext_len = last_uip_ext_len;
|
||||
return RPL_HOP_BY_HOP_LEN;
|
||||
default:
|
||||
PRINTF("RPL: Multi Hop-by-hop options not implemented\n");
|
||||
uip_ext_len = last_uip_ext_len;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_insert_header(void)
|
||||
{
|
||||
#if RPL_INSERT_HBH_OPTION
|
||||
if(default_instance != NULL && !uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
|
||||
rpl_update_header_empty();
|
||||
if(default_instance == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(RPL_IS_STORING(default_instance)) {
|
||||
if(!uip_is_addr_mcast(&UIP_IP_BUF->destipaddr)) {
|
||||
insert_hbh_header();
|
||||
}
|
||||
}
|
||||
|
||||
if(RPL_IS_NON_STORING(default_instance)) {
|
||||
if(default_instance->current_dag != NULL) {
|
||||
if(default_instance->current_dag->rank == ROOT_RANK(default_instance)) {
|
||||
insert_srh_header();
|
||||
} else {
|
||||
insert_hbh_header();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
rpl_update_header(void)
|
||||
{
|
||||
if(default_instance == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(default_instance->current_dag != NULL) {
|
||||
if(default_instance->current_dag->rank == ROOT_RANK(default_instance)) {
|
||||
/* At the root, remove headers if any, and insert SRH or HBH
|
||||
* (SRH is inserted only if the destination is in the DODAG) */
|
||||
rpl_remove_header();
|
||||
if(RPL_IS_NON_STORING(default_instance)) {
|
||||
return insert_srh_header();
|
||||
} else {
|
||||
return insert_hbh_header();
|
||||
}
|
||||
} else {
|
||||
return update_hbh_header();
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** @}*/
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "net/ipv6/uip-nd6.h"
|
||||
#include "net/ipv6/uip-icmp6.h"
|
||||
#include "net/rpl/rpl-private.h"
|
||||
#include "net/rpl/rpl-ns.h"
|
||||
#include "net/packetbuf.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6.h"
|
||||
#include "random.h"
|
||||
|
@ -119,6 +120,7 @@ find_route_entry_by_dao_ack(uint8_t seq)
|
|||
}
|
||||
#endif /* RPL_WITH_DAO_ACK */
|
||||
|
||||
#if RPL_WITH_STORING
|
||||
/* prepare for forwarding of DAO */
|
||||
static uint8_t
|
||||
prepare_for_dao_fwd(uint8_t sequence, uip_ds6_route_t *rep)
|
||||
|
@ -132,6 +134,7 @@ prepare_for_dao_fwd(uint8_t sequence, uip_ds6_route_t *rep)
|
|||
RPL_ROUTE_SET_DAO_PENDING(rep);
|
||||
return dao_sequence;
|
||||
}
|
||||
#endif /* RPL_WITH_STORING */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
get_global_addr(uip_ipaddr_t *addr)
|
||||
|
@ -626,8 +629,9 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
|
|||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
dao_input(void)
|
||||
dao_input_storing(void)
|
||||
{
|
||||
#if RPL_WITH_STORING
|
||||
uip_ipaddr_t dao_sender_addr;
|
||||
rpl_dag_t *dag;
|
||||
rpl_instance_t *instance;
|
||||
|
@ -665,11 +669,6 @@ dao_input(void)
|
|||
instance_id = buffer[pos++];
|
||||
|
||||
instance = rpl_get_instance(instance_id);
|
||||
if(instance == NULL) {
|
||||
PRINTF("RPL: Ignoring a DAO for an unknown RPL instance(%u)\n",
|
||||
instance_id);
|
||||
goto discard;
|
||||
}
|
||||
|
||||
lifetime = instance->default_lifetime;
|
||||
|
||||
|
@ -685,7 +684,7 @@ dao_input(void)
|
|||
if(flags & RPL_DAO_D_FLAG) {
|
||||
if(memcmp(&dag->dag_id, &buffer[pos], sizeof(dag->dag_id))) {
|
||||
PRINTF("RPL: Ignoring a DAO for a DAG different from ours\n");
|
||||
goto discard;
|
||||
return;
|
||||
}
|
||||
pos += 16;
|
||||
}
|
||||
|
@ -710,7 +709,7 @@ dao_input(void)
|
|||
DAG_RANK(parent->rank, instance), DAG_RANK(dag->rank, instance));
|
||||
parent->rank = INFINITE_RANK;
|
||||
parent->flags |= RPL_PARENT_FLAG_UPDATED;
|
||||
goto discard;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we get the DAO from our parent, we also have a loop. */
|
||||
|
@ -718,7 +717,7 @@ dao_input(void)
|
|||
PRINTF("RPL: Loop detected when receiving a unicast DAO from our parent\n");
|
||||
parent->rank = INFINITE_RANK;
|
||||
parent->flags |= RPL_PARENT_FLAG_UPDATED;
|
||||
goto discard;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -805,7 +804,7 @@ dao_input(void)
|
|||
dao_ack_output(instance, &dao_sender_addr, sequence,
|
||||
RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
|
||||
}
|
||||
goto discard;
|
||||
return;
|
||||
}
|
||||
|
||||
PRINTF("RPL: Adding DAO route\n");
|
||||
|
@ -823,7 +822,7 @@ dao_input(void)
|
|||
is_root ? RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT :
|
||||
RPL_DAO_ACK_UNABLE_TO_ACCEPT);
|
||||
}
|
||||
goto discard;
|
||||
return;
|
||||
}
|
||||
|
||||
rep = rpl_add_route(dag, &prefix, prefixlen, &dao_sender_addr);
|
||||
|
@ -836,7 +835,7 @@ dao_input(void)
|
|||
is_root ? RPL_DAO_ACK_UNABLE_TO_ADD_ROUTE_AT_ROOT :
|
||||
RPL_DAO_ACK_UNABLE_TO_ACCEPT);
|
||||
}
|
||||
goto discard;
|
||||
return;
|
||||
}
|
||||
|
||||
/* set lifetime and clear NOPATH bit */
|
||||
|
@ -892,6 +891,141 @@ fwd_dao:
|
|||
RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
|
||||
}
|
||||
}
|
||||
#endif /* RPL_WITH_STORING */
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
dao_input_nonstoring(void)
|
||||
{
|
||||
#if RPL_WITH_NON_STORING
|
||||
uip_ipaddr_t dao_sender_addr;
|
||||
uip_ipaddr_t dao_parent_addr;
|
||||
rpl_dag_t *dag;
|
||||
rpl_instance_t *instance;
|
||||
unsigned char *buffer;
|
||||
uint16_t sequence;
|
||||
uint8_t instance_id;
|
||||
uint8_t lifetime;
|
||||
uint8_t prefixlen;
|
||||
uint8_t flags;
|
||||
uint8_t subopt_type;
|
||||
uip_ipaddr_t prefix;
|
||||
uint8_t buffer_length;
|
||||
int pos;
|
||||
int len;
|
||||
int i;
|
||||
|
||||
prefixlen = 0;
|
||||
|
||||
uip_ipaddr_copy(&dao_sender_addr, &UIP_IP_BUF->srcipaddr);
|
||||
memset(&dao_parent_addr, 0, 16);
|
||||
|
||||
buffer = UIP_ICMP_PAYLOAD;
|
||||
buffer_length = uip_len - uip_l3_icmp_hdr_len;
|
||||
|
||||
pos = 0;
|
||||
instance_id = buffer[pos++];
|
||||
instance = rpl_get_instance(instance_id);
|
||||
lifetime = instance->default_lifetime;
|
||||
|
||||
flags = buffer[pos++];
|
||||
/* reserved */
|
||||
pos++;
|
||||
sequence = buffer[pos++];
|
||||
|
||||
dag = instance->current_dag;
|
||||
/* Is the DAG ID present? */
|
||||
if(flags & RPL_DAO_D_FLAG) {
|
||||
if(memcmp(&dag->dag_id, &buffer[pos], sizeof(dag->dag_id))) {
|
||||
PRINTF("RPL: Ignoring a DAO for a DAG different from ours\n");
|
||||
return;
|
||||
}
|
||||
pos += 16;
|
||||
}
|
||||
|
||||
/* Check if there are any RPL options present. */
|
||||
for(i = pos; i < buffer_length; i += len) {
|
||||
subopt_type = buffer[i];
|
||||
if(subopt_type == RPL_OPTION_PAD1) {
|
||||
len = 1;
|
||||
} else {
|
||||
/* The option consists of a two-byte header and a payload. */
|
||||
len = 2 + buffer[i + 1];
|
||||
}
|
||||
|
||||
switch(subopt_type) {
|
||||
case RPL_OPTION_TARGET:
|
||||
/* Handle the target option. */
|
||||
prefixlen = buffer[i + 3];
|
||||
memset(&prefix, 0, sizeof(prefix));
|
||||
memcpy(&prefix, buffer + i + 4, (prefixlen + 7) / CHAR_BIT);
|
||||
break;
|
||||
case RPL_OPTION_TRANSIT:
|
||||
/* The path sequence and control are ignored. */
|
||||
/* pathcontrol = buffer[i + 3];
|
||||
pathsequence = buffer[i + 4];*/
|
||||
lifetime = buffer[i + 5];
|
||||
if(len >= 20) {
|
||||
memcpy(&dao_parent_addr, buffer + i + 6, 16);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PRINTF("RPL: DAO lifetime: %u, prefix length: %u prefix: ",
|
||||
(unsigned)lifetime, (unsigned)prefixlen);
|
||||
PRINT6ADDR(&prefix);
|
||||
PRINTF(", parent: ");
|
||||
PRINT6ADDR(&dao_parent_addr);
|
||||
PRINTF(" \n");
|
||||
|
||||
if(lifetime == RPL_ZERO_LIFETIME) {
|
||||
PRINTF("RPL: No-Path DAO received\n");
|
||||
rpl_ns_expire_parent(dag, &prefix, &dao_parent_addr);
|
||||
} else {
|
||||
if(rpl_ns_update_node(dag, &prefix, &dao_parent_addr, RPL_LIFETIME(instance, lifetime)) == NULL) {
|
||||
PRINTF("RPL: failed to add link\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(flags & RPL_DAO_K_FLAG) {
|
||||
PRINTF("RPL: Sending DAO ACK\n");
|
||||
uip_clear_buf();
|
||||
dao_ack_output(instance, &dao_sender_addr, sequence,
|
||||
RPL_DAO_ACK_UNCONDITIONAL_ACCEPT);
|
||||
}
|
||||
#endif /* RPL_WITH_NON_STORING */
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
dao_input(void)
|
||||
{
|
||||
rpl_instance_t *instance;
|
||||
uint8_t instance_id;
|
||||
|
||||
/* Destination Advertisement Object */
|
||||
PRINTF("RPL: Received a DAO from ");
|
||||
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
|
||||
PRINTF("\n");
|
||||
|
||||
instance_id = UIP_ICMP_PAYLOAD[0];
|
||||
instance = rpl_get_instance(instance_id);
|
||||
if(instance == NULL) {
|
||||
PRINTF("RPL: Ignoring a DAO for an unknown RPL instance(%u)\n",
|
||||
instance_id);
|
||||
goto discard;
|
||||
}
|
||||
|
||||
if(instance->mop != RPL_MOP_NON_STORING) {
|
||||
if(RPL_IS_STORING(instance)) {
|
||||
dao_input_storing();
|
||||
}
|
||||
} else {
|
||||
if(RPL_IS_NON_STORING(instance)) {
|
||||
dao_input_nonstoring();
|
||||
}
|
||||
}
|
||||
|
||||
discard:
|
||||
uip_clear_buf();
|
||||
|
@ -1006,6 +1140,8 @@ dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix,
|
|||
unsigned char *buffer;
|
||||
uint8_t prefixlen;
|
||||
int pos;
|
||||
uip_ipaddr_t *parent_ipaddr = NULL;
|
||||
uip_ipaddr_t *dest_ipaddr = NULL;
|
||||
|
||||
/* Destination Advertisement Object */
|
||||
|
||||
|
@ -1019,6 +1155,12 @@ dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix,
|
|||
return;
|
||||
}
|
||||
|
||||
parent_ipaddr = rpl_get_parent_ipaddr(parent);
|
||||
if(parent_ipaddr == NULL) {
|
||||
PRINTF("RPL dao_output_target error parent IP address NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dag = parent->dag;
|
||||
if(dag == NULL) {
|
||||
PRINTF("RPL dao_output_target error dag NULL\n");
|
||||
|
@ -1071,21 +1213,37 @@ dao_output_target_seq(rpl_parent_t *parent, uip_ipaddr_t *prefix,
|
|||
|
||||
/* Create a transit information sub-option. */
|
||||
buffer[pos++] = RPL_OPTION_TRANSIT;
|
||||
buffer[pos++] = 4;
|
||||
buffer[pos++] = (instance->mop != RPL_MOP_NON_STORING) ? 4 : 20;
|
||||
buffer[pos++] = 0; /* flags - ignored */
|
||||
buffer[pos++] = 0; /* path control - ignored */
|
||||
buffer[pos++] = 0; /* path seq - ignored */
|
||||
buffer[pos++] = lifetime;
|
||||
|
||||
if(instance->mop != RPL_MOP_NON_STORING) {
|
||||
/* Send DAO to parent */
|
||||
dest_ipaddr = parent_ipaddr;
|
||||
} else {
|
||||
/* Include parent global IP address */
|
||||
memcpy(buffer + pos, &parent->dag->dag_id, 8); /* Prefix */
|
||||
pos += 8;
|
||||
memcpy(buffer + pos, ((const unsigned char *)parent_ipaddr) + 8, 8); /* Interface identifier */
|
||||
pos += 8;
|
||||
/* Send DAO to root */
|
||||
dest_ipaddr = &parent->dag->dag_id;
|
||||
}
|
||||
|
||||
PRINTF("RPL: Sending a %sDAO with sequence number %u, lifetime %u, prefix ",
|
||||
lifetime == RPL_ZERO_LIFETIME ? "No-Path " : "", seq_no, lifetime);
|
||||
|
||||
PRINT6ADDR(prefix);
|
||||
PRINTF(" to ");
|
||||
PRINT6ADDR(rpl_get_parent_ipaddr(parent));
|
||||
PRINT6ADDR(dest_ipaddr);
|
||||
PRINTF(" , parent ");
|
||||
PRINT6ADDR(parent_ipaddr);
|
||||
PRINTF("\n");
|
||||
|
||||
if(rpl_get_parent_ipaddr(parent) != NULL) {
|
||||
uip_icmp6_send(rpl_get_parent_ipaddr(parent), ICMP6_RPL, RPL_CODE_DAO, pos);
|
||||
if(dest_ipaddr != NULL) {
|
||||
uip_icmp6_send(dest_ipaddr, ICMP6_RPL, RPL_CODE_DAO, pos);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
|
211
core/net/rpl/rpl-ns.c
Normal file
211
core/net/rpl/rpl-ns.c
Normal file
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Inria.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* RPL non-storing mode specific functions. Includes support for
|
||||
* source routing.
|
||||
*
|
||||
* \author Simon Duquennoy <simon.duquennoy@inria.fr>
|
||||
*/
|
||||
|
||||
#include "net/rpl/rpl-conf.h"
|
||||
|
||||
#include "net/ip/uip.h"
|
||||
#include "net/ip/tcpip.h"
|
||||
#include "net/ipv6/uip-ds6.h"
|
||||
#include "net/ipv6/uip-icmp6.h"
|
||||
#include "net/rpl/rpl-private.h"
|
||||
#include "net/rpl/rpl-ns.h"
|
||||
#include "lib/list.h"
|
||||
#include "lib/memb.h"
|
||||
|
||||
#if RPL_WITH_NON_STORING
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "net/ip/uip-debug.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Total number of nodes */
|
||||
static int num_nodes;
|
||||
|
||||
/* Every known node in the network */
|
||||
LIST(nodelist);
|
||||
MEMB(nodememb, rpl_ns_node_t, RPL_NS_LINK_NUM);
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
rpl_ns_num_nodes()
|
||||
{
|
||||
return num_nodes;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
node_matches_address(const rpl_dag_t *dag, const rpl_ns_node_t *node, const uip_ipaddr_t *addr)
|
||||
{
|
||||
return addr != NULL
|
||||
&& node != NULL
|
||||
&& dag != NULL
|
||||
&& dag == node->dag
|
||||
&& !memcmp(addr, &node->dag->dag_id, 8)
|
||||
&& !memcmp(((const unsigned char *)addr) + 8, node->link_identifier, 8);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
rpl_ns_node_t *
|
||||
rpl_ns_get_node(const rpl_dag_t *dag, const uip_ipaddr_t *addr)
|
||||
{
|
||||
rpl_ns_node_t *l;
|
||||
for(l = list_head(nodelist); l != NULL; l = list_item_next(l)) {
|
||||
/* Compare prefix and node identifier */
|
||||
if(node_matches_address(dag, l, addr)) {
|
||||
return l;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
rpl_ns_is_node_reachable(const rpl_dag_t *dag, const uip_ipaddr_t *addr)
|
||||
{
|
||||
int max_depth = RPL_NS_LINK_NUM;
|
||||
rpl_ns_node_t *node = rpl_ns_get_node(dag, addr);
|
||||
rpl_ns_node_t *root_node = rpl_ns_get_node(dag, dag != NULL ? &dag->dag_id : NULL);
|
||||
while(node != NULL && node != root_node && max_depth > 0) {
|
||||
node = node->parent;
|
||||
max_depth--;
|
||||
}
|
||||
return node != NULL && node == root_node;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_ns_expire_parent(rpl_dag_t *dag, const uip_ipaddr_t *child, const uip_ipaddr_t *parent)
|
||||
{
|
||||
rpl_ns_node_t *l = rpl_ns_get_node(dag, child);
|
||||
/* Check if parent matches */
|
||||
if(l != NULL && node_matches_address(dag, l->parent, parent)) {
|
||||
l->lifetime = RPL_NOPATH_REMOVAL_DELAY;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
rpl_ns_node_t *
|
||||
rpl_ns_update_node(rpl_dag_t *dag, const uip_ipaddr_t *child, const uip_ipaddr_t *parent, uint32_t lifetime)
|
||||
{
|
||||
rpl_ns_node_t *child_node = rpl_ns_get_node(dag, child);
|
||||
rpl_ns_node_t *parent_node = rpl_ns_get_node(dag, parent);
|
||||
|
||||
if(parent != NULL) {
|
||||
/* No node for the parent, add one with infinite lifetime */
|
||||
if(parent_node == NULL) {
|
||||
parent_node = rpl_ns_update_node(dag, parent, NULL, 0xffffffff);
|
||||
if(parent_node == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* No node for this child, add one */
|
||||
if(child_node == NULL) {
|
||||
child_node = memb_alloc(&nodememb);
|
||||
/* No space left, abort */
|
||||
if(child_node == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
list_add(nodelist, child_node);
|
||||
num_nodes++;
|
||||
}
|
||||
|
||||
/* Initialize node */
|
||||
child_node->dag = dag;
|
||||
child_node->lifetime = lifetime;
|
||||
child_node->parent = parent_node;
|
||||
memcpy(child_node->link_identifier, ((const unsigned char *)child) + 8, 8);
|
||||
|
||||
return child_node;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_ns_init()
|
||||
{
|
||||
num_nodes = 0;
|
||||
memb_init(&nodememb);
|
||||
list_init(nodelist);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
rpl_ns_node_t *rpl_ns_node_head()
|
||||
{
|
||||
return list_head(nodelist);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
rpl_ns_node_t *rpl_ns_node_next(rpl_ns_node_t *item)
|
||||
{
|
||||
return list_item_next(item);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_ns_get_node_global_addr(uip_ipaddr_t *addr, rpl_ns_node_t *node)
|
||||
{
|
||||
if(addr != NULL && node != NULL && node->dag != NULL) {
|
||||
memcpy(addr, &node->dag->dag_id, 8);
|
||||
memcpy(((unsigned char *)addr) + 8, &node->link_identifier, 8);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_ns_periodic()
|
||||
{
|
||||
rpl_ns_node_t *l;
|
||||
/* First pass, decrement lifetime for all nodes with non-infinite lifetime */
|
||||
for(l = list_head(nodelist); l != NULL; l = list_item_next(l)) {
|
||||
/* Don't touch infinite lifetime nodes */
|
||||
if(l->lifetime != 0xffffffff && l->lifetime > 0) {
|
||||
l->lifetime--;
|
||||
}
|
||||
}
|
||||
/* Second pass, for all expire nodes, deallocate them iff no child points to them */
|
||||
for(l = list_head(nodelist); l != NULL; l = list_item_next(l)) {
|
||||
if(l->lifetime == 0) {
|
||||
rpl_ns_node_t *l2;
|
||||
for(l2 = list_head(nodelist); l2 != NULL; l2 = list_item_next(l2)) {
|
||||
if(l2->parent == l) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* No child found, deallocate node */
|
||||
list_remove(nodelist, l);
|
||||
memb_free(&nodememb, l);
|
||||
num_nodes--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* RPL_WITH_NON_STORING */
|
72
core/net/rpl/rpl-ns.h
Normal file
72
core/net/rpl/rpl-ns.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Inria.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* RPL non-storing mode specific functions. Includes support for
|
||||
* source routing.
|
||||
*
|
||||
* \author Simon Duquennoy <simon.duquennoy@inria.fr>
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RPL_NS_H
|
||||
#define RPL_NS_H
|
||||
|
||||
#include "rpl-conf.h"
|
||||
|
||||
#ifdef RPL_NS_CONF_LINK_NUM
|
||||
#define RPL_NS_LINK_NUM RPL_NS_CONF_LINK_NUM
|
||||
#else /* RPL_NS_CONF_LINK_NUM */
|
||||
#define RPL_NS_LINK_NUM 32
|
||||
#endif /* RPL_NS_CONF_LINK_NUM */
|
||||
|
||||
typedef struct rpl_ns_node {
|
||||
struct rpl_ns_node *next;
|
||||
uint32_t lifetime;
|
||||
rpl_dag_t *dag;
|
||||
/* Store only IPv6 link identifiers as all nodes in the DAG share the same prefix */
|
||||
unsigned char link_identifier[8];
|
||||
struct rpl_ns_node *parent;
|
||||
} rpl_ns_node_t;
|
||||
|
||||
int rpl_ns_num_nodes();
|
||||
void rpl_ns_expire_parent(rpl_dag_t *dag, const uip_ipaddr_t *child, const uip_ipaddr_t *parent);
|
||||
rpl_ns_node_t *rpl_ns_update_node(rpl_dag_t *dag, const uip_ipaddr_t *child, const uip_ipaddr_t *parent, uint32_t lifetime);
|
||||
void rpl_ns_init();
|
||||
rpl_ns_node_t *rpl_ns_node_head();
|
||||
rpl_ns_node_t *rpl_ns_node_next(rpl_ns_node_t *item);
|
||||
rpl_ns_node_t *rpl_ns_get_node(const rpl_dag_t *dag, const uip_ipaddr_t *addr);
|
||||
int rpl_ns_is_node_reachable(const rpl_dag_t *dag, const uip_ipaddr_t *addr);
|
||||
void rpl_ns_get_node_global_addr(uip_ipaddr_t *addr, rpl_ns_node_t *node);
|
||||
void rpl_ns_periodic();
|
||||
|
||||
#endif /* RPL_NS_H */
|
|
@ -102,6 +102,9 @@
|
|||
/* RPL IPv6 extension header option. */
|
||||
#define RPL_HDR_OPT_LEN 4
|
||||
#define RPL_HOP_BY_HOP_LEN (RPL_HDR_OPT_LEN + 2 + 2)
|
||||
#define RPL_RH_LEN 4
|
||||
#define RPL_SRH_LEN 4
|
||||
#define RPL_RH_TYPE_SRH 3
|
||||
#define RPL_HDR_OPT_DOWN 0x80
|
||||
#define RPL_HDR_OPT_DOWN_SHIFT 7
|
||||
#define RPL_HDR_OPT_RANK_ERR 0x40
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
|
||||
#include "contiki-conf.h"
|
||||
#include "net/rpl/rpl-private.h"
|
||||
#include "net/rpl/rpl-ns.h"
|
||||
#include "net/link-stats.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6.h"
|
||||
#include "lib/random.h"
|
||||
|
@ -80,14 +81,21 @@ static uint8_t dio_send_ok;
|
|||
static void
|
||||
handle_periodic_timer(void *ptr)
|
||||
{
|
||||
rpl_dag_t *dag = rpl_get_any_dag();
|
||||
|
||||
rpl_purge_dags();
|
||||
rpl_purge_routes();
|
||||
if(dag != NULL && RPL_IS_STORING(dag->instance)) {
|
||||
rpl_purge_routes();
|
||||
}
|
||||
if(dag != NULL && RPL_IS_NON_STORING(dag->instance)) {
|
||||
rpl_ns_periodic();
|
||||
}
|
||||
rpl_recalculate_ranks();
|
||||
|
||||
/* handle DIS */
|
||||
#if RPL_DIS_SEND
|
||||
next_dis++;
|
||||
if(rpl_get_any_dag() == NULL && next_dis >= RPL_DIS_INTERVAL) {
|
||||
if(dag == NULL && next_dis >= RPL_DIS_INTERVAL) {
|
||||
next_dis = 0;
|
||||
dis_output(NULL);
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "net/ipv6/uip-ds6.h"
|
||||
#include "net/ipv6/uip-icmp6.h"
|
||||
#include "net/rpl/rpl-private.h"
|
||||
#include "net/rpl/rpl-ns.h"
|
||||
#include "net/ipv6/multicast/uip-mcast6.h"
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
|
@ -344,6 +345,10 @@ rpl_init(void)
|
|||
#if RPL_CONF_STATS
|
||||
memset(&rpl_stats, 0, sizeof(rpl_stats));
|
||||
#endif
|
||||
|
||||
#if RPL_WITH_NON_STORING
|
||||
rpl_ns_init();
|
||||
#endif /* RPL_WITH_NON_STORING */
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
|
|
|
@ -271,14 +271,14 @@ rpl_dag_t *rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id);
|
|||
int rpl_set_prefix(rpl_dag_t *dag, uip_ipaddr_t *prefix, unsigned len);
|
||||
int rpl_repair_root(uint8_t instance_id);
|
||||
int rpl_set_default_route(rpl_instance_t *instance, uip_ipaddr_t *from);
|
||||
rpl_dag_t *rpl_get_dag(const uip_ipaddr_t *addr);
|
||||
rpl_dag_t *rpl_get_any_dag(void);
|
||||
rpl_instance_t *rpl_get_instance(uint8_t instance_id);
|
||||
int rpl_update_header_empty(void);
|
||||
int rpl_update_header_final(uip_ipaddr_t *addr);
|
||||
int rpl_verify_header(int);
|
||||
int rpl_update_header(void);
|
||||
int rpl_finalize_header(uip_ipaddr_t *addr);
|
||||
int rpl_verify_hbh_header(int);
|
||||
void rpl_insert_header(void);
|
||||
void rpl_remove_header(void);
|
||||
uint8_t rpl_invert_header(void);
|
||||
const struct link_stats *rpl_get_parent_link_stats(rpl_parent_t *p);
|
||||
int rpl_parent_is_fresh(rpl_parent_t *p);
|
||||
int rpl_parent_is_reachable(rpl_parent_t *p);
|
||||
|
@ -291,6 +291,8 @@ rpl_rank_t rpl_get_parent_rank(uip_lladdr_t *addr);
|
|||
void rpl_dag_init(void);
|
||||
uip_ds6_nbr_t *rpl_get_nbr(rpl_parent_t *parent);
|
||||
void rpl_print_neighbor_list(void);
|
||||
int rpl_process_srh_header(void);
|
||||
int rpl_srh_get_next_hop(uip_ipaddr_t *ipaddr);
|
||||
|
||||
/* Per-parent RPL information */
|
||||
NBR_TABLE_DECLARE(rpl_parents);
|
||||
|
|
Loading…
Reference in a new issue