From b3e31e14564bf8ceba886178975073e78c559fc0 Mon Sep 17 00:00:00 2001 From: Simon Duquennoy Date: Mon, 1 Feb 2016 18:02:33 +0100 Subject: [PATCH] Implement RPL non-storing mode --- core/net/ip/tcpip.c | 26 +- core/net/ip/uip.h | 7 + core/net/ipv6/uip-ds6-route.c | 47 ++- core/net/ipv6/uip-ds6-route.h | 2 +- core/net/ipv6/uip-icmp6.c | 122 +++---- core/net/ipv6/uip6.c | 20 +- core/net/rpl/rpl-conf.h | 27 +- core/net/rpl/rpl-dag-root.c | 10 +- core/net/rpl/rpl-dag.c | 73 +++-- core/net/rpl/rpl-ext-header.c | 590 ++++++++++++++++++++++++++-------- core/net/rpl/rpl-icmp6.c | 190 ++++++++++- core/net/rpl/rpl-ns.c | 211 ++++++++++++ core/net/rpl/rpl-ns.h | 72 +++++ core/net/rpl/rpl-private.h | 3 + core/net/rpl/rpl-timers.c | 12 +- core/net/rpl/rpl.c | 5 + core/net/rpl/rpl.h | 10 +- 17 files changed, 1149 insertions(+), 278 deletions(-) create mode 100644 core/net/rpl/rpl-ns.c create mode 100644 core/net/rpl/rpl-ns.h diff --git a/core/net/ip/tcpip.c b/core/net/ip/tcpip.c index ff514a186..df3f0608d 100644 --- a/core/net/ip/tcpip.c +++ b/core/net/ip/tcpip.c @@ -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 #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 */ diff --git a/core/net/ip/uip.h b/core/net/ip/uip.h index 900bd45fb..12d77ff10 100644 --- a/core/net/ip/uip.h +++ b/core/net/ip/uip.h @@ -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; diff --git a/core/net/ipv6/uip-ds6-route.c b/core/net/ipv6/uip-ds6-route.c index 043ca78d4..bb7b7b18e 100644 --- a/core/net/ipv6/uip-ds6-route.c +++ b/core/net/ipv6/uip-ds6-route.c @@ -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 * diff --git a/core/net/ipv6/uip-ds6-route.h b/core/net/ipv6/uip-ds6-route.h index 6ca533c9b..6855fc2cd 100644 --- a/core/net/ipv6/uip-ds6-route.h +++ b/core/net/ipv6/uip-ds6-route.h @@ -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 diff --git a/core/net/ipv6/uip-icmp6.c b/core/net/ipv6/uip-icmp6.c index 80d7a5582..fae84b4de 100644 --- a/core/net/ipv6/uip-icmp6.c +++ b/core/net/ipv6/uip-icmp6.c @@ -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 diff --git a/core/net/ipv6/uip6.c b/core/net/ipv6/uip6.c index e3f2c6fc0..a54754371 100644 --- a/core/net/ipv6/uip6.c +++ b/core/net/ipv6/uip6.c @@ -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 /*---------------------------------------------------------------------------*/ @@ -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 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"); diff --git a/core/net/rpl/rpl-conf.h b/core/net/rpl/rpl-conf.h index 1da6c5ea8..0148e11e5 100644 --- a/core/net/rpl/rpl-conf.h +++ b/core/net/rpl/rpl-conf.h @@ -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. diff --git a/core/net/rpl/rpl-dag-root.c b/core/net/rpl/rpl-dag-root.c index d053a1a13..57a10ef80 100644 --- a/core/net/rpl/rpl-dag-root.c +++ b/core/net/rpl/rpl-dag-root.c @@ -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); diff --git a/core/net/rpl/rpl-dag.c b/core/net/rpl/rpl-dag.c index c4108fd5a..ced73990f 100644 --- a/core/net/rpl/rpl-dag.c +++ b/core/net/rpl/rpl-dag.c @@ -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"); diff --git a/core/net/rpl/rpl-ext-header.c b/core/net/rpl/rpl-ext-header.c index fd7cf8604..85f770dfc 100644 --- a/core/net/rpl/rpl-ext-header.c +++ b/core/net/rpl/rpl-ext-header.c @@ -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; + } +} /** @}*/ diff --git a/core/net/rpl/rpl-icmp6.c b/core/net/rpl/rpl-icmp6.c index 6ea9b3e02..02f1d2244 100644 --- a/core/net/rpl/rpl-icmp6.c +++ b/core/net/rpl/rpl-icmp6.c @@ -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); } } /*---------------------------------------------------------------------------*/ diff --git a/core/net/rpl/rpl-ns.c b/core/net/rpl/rpl-ns.c new file mode 100644 index 000000000..fecd6767e --- /dev/null +++ b/core/net/rpl/rpl-ns.c @@ -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 + */ + +#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 +#include + +/* 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 */ diff --git a/core/net/rpl/rpl-ns.h b/core/net/rpl/rpl-ns.h new file mode 100644 index 000000000..8abc68df2 --- /dev/null +++ b/core/net/rpl/rpl-ns.h @@ -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 + */ + + +#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 */ diff --git a/core/net/rpl/rpl-private.h b/core/net/rpl/rpl-private.h index b127bb9c4..72ac12198 100644 --- a/core/net/rpl/rpl-private.h +++ b/core/net/rpl/rpl-private.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 diff --git a/core/net/rpl/rpl-timers.c b/core/net/rpl/rpl-timers.c index abb668174..1a159e5bb 100644 --- a/core/net/rpl/rpl-timers.c +++ b/core/net/rpl/rpl-timers.c @@ -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); } diff --git a/core/net/rpl/rpl.c b/core/net/rpl/rpl.c index 145ec1cd1..fd03e3cb6 100644 --- a/core/net/rpl/rpl.c +++ b/core/net/rpl/rpl.c @@ -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 */ } /*---------------------------------------------------------------------------*/ diff --git a/core/net/rpl/rpl.h b/core/net/rpl/rpl.h index 89bc70ae8..26ee71edc 100644 --- a/core/net/rpl/rpl.h +++ b/core/net/rpl/rpl.h @@ -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);