50#include "net/routing/rpl-classic/rpl-private.h"
55#define LOG_MODULE "RPL"
56#define LOG_LEVEL LOG_LEVEL_RPL
65 rpl_instance_t *instance;
68 uint8_t sender_closer;
73 if(opt_offset < 0 || opt_offset & 1) {
74 LOG_ERR(
"Invalid RPL option offset: %d\n", opt_offset);
78 struct uip_hbho_hdr *hbh_hdr = (
struct uip_hbho_hdr *)ext_buf;
79 struct uip_ext_hdr_opt_rpl *rpl_opt = (
struct uip_ext_hdr_opt_rpl *)(ext_buf + opt_offset);
81 if(hbh_hdr->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8)
82 || rpl_opt->opt_type != UIP_EXT_HDR_OPT_RPL
83 || rpl_opt->opt_len != RPL_HDR_OPT_LEN) {
85 LOG_ERR(
"Hop-by-hop extension header has wrong size or type (%u %u %u)\n",
86 hbh_hdr->len, rpl_opt->opt_type, rpl_opt->opt_len);
90 instance = rpl_get_instance(rpl_opt->instance);
91 if(instance == NULL) {
92 LOG_ERR(
"Unknown instance: %u\n", rpl_opt->instance);
96 if(rpl_opt->flags & RPL_HDR_OPT_FWD_ERR) {
97 LOG_ERR(
"Forward error!\n");
103 if(RPL_IS_STORING(instance)) {
104 route = uip_ds6_route_lookup(&
UIP_IP_BUF->destipaddr);
106 uip_ds6_route_rm(route);
109 RPL_STAT(rpl_stats.forward_errors++);
111 rpl_reset_dio_timer(instance);
116 if(!instance->current_dag->joined) {
117 LOG_ERR(
"No DAG in the instance\n");
121 if(rpl_opt->flags & RPL_HDR_OPT_DOWN) {
125 sender_rank =
UIP_HTONS(rpl_opt->senderrank);
126 sender = nbr_table_get_from_lladdr(rpl_parents, packetbuf_addr(PACKETBUF_ADDR_SENDER));
128 if(sender != NULL && (rpl_opt->flags & RPL_HDR_OPT_RANK_ERR)) {
131 sender->rank = sender_rank;
132 if(RPL_IS_NON_STORING(instance)) {
139 rpl_select_dag(instance, sender);
143 sender_closer = sender_rank < instance->current_dag->rank;
146 LOG_DBG(
"Packet going %s, sender%s closer (%d < %d)\n",
147 down == 1 ?
"down" :
"up",
148 sender_closer ?
"" :
" not",
150 instance->current_dag->rank);
152 if((down && !sender_closer) || (!down && sender_closer)) {
153 LOG_WARN(
"Loop detected - senderrank: %d my-rank: %d sender_closer: %d\n",
154 sender_rank, instance->current_dag->rank,
159 instance->unicast_dio_target = sender;
160 rpl_schedule_unicast_dio_immediately(instance);
163 if(rpl_opt->flags & RPL_HDR_OPT_RANK_ERR) {
164 RPL_STAT(rpl_stats.loop_errors++);
165 LOG_ERR(
"Rank error signaled in RPL option!\n");
168 rpl_reset_dio_timer(instance);
172 LOG_WARN(
"One inconsistency along path is tolerated\n");
173 RPL_STAT(rpl_stats.loop_warnings++);
174 rpl_opt->flags |= RPL_HDR_OPT_RANK_ERR;
178 LOG_DBG(
"Rank OK\n");
185#if RPL_WITH_NON_STORING
186 struct uip_routing_hdr *rh_header;
192 rh_header = (
struct uip_routing_hdr *)uipbuf_search_header(
uip_buf,
uip_len, UIP_PROTO_ROUTING);
198 if((rh_header != NULL && rh_header->routing_type == RPL_RH_TYPE_SRH) ||
199 (dest_node != NULL && root_node != NULL &&
200 dest_node->parent == root_node)) {
209 uip_create_linklocal_prefix(
ipaddr);
219#if RPL_WITH_NON_STORING
221srh_is_valid(
struct uip_routing_hdr *rh_header,
222 struct uip_rpl_srh_hdr *srh_header)
224 uip_ipaddr_t hop_addr;
227 uint8_t segments_left = rh_header->seg_left;
228 uint8_t ext_len = rh_header->len * 8 + 8;
229 uint8_t cmpri = srh_header->cmpr >> 4;
230 uint8_t cmpre = srh_header->cmpr & 0x0f;
231 uint8_t padding = srh_header->pad >> 4;
232 uint8_t path_len = ((ext_len - padding - RPL_RH_LEN - RPL_SRH_LEN - (16 - cmpre)) / (16 - cmpri)) + 1;
234 bool prev_hop_is_my_addr =
false;
235 uint8_t my_addr_count = 0;
236 for(uint8_t i = path_len - segments_left; i < path_len; i++) {
237 uint8_t cmpr = segments_left == 1 ? cmpre : cmpri;
238 ptrdiff_t rh_offset = (uint8_t *)rh_header -
uip_buf;
239 size_t addr_offset = RPL_RH_LEN + RPL_SRH_LEN + (i * (16 - cmpri));
241 if(rh_offset + addr_offset + 16 - cmpr >
UIP_BUFSIZE) {
245 uint8_t *addr_ptr = (uint8_t *)rh_header + addr_offset;
246 memcpy((uint8_t *)&hop_addr + cmpr, addr_ptr, 16 - cmpr);
248 LOG_DBG(
"Processing SRH hop %u, IP addr ", i);
249 LOG_DBG_6ADDR(&hop_addr);
261 if(uip_ds6_is_my_addr(&hop_addr) ||
262 uip_ds6_is_my_maddr(&hop_addr)) {
264 if(!prev_hop_is_my_addr && my_addr_count > 1) {
265 LOG_WARN(
"SRH contains a loop\n");
268 prev_hop_is_my_addr =
true;
270 prev_hop_is_my_addr =
false;
276 LOG_WARN(
"SRH contains an invalid next hop address\n");
288#if RPL_WITH_NON_STORING
289 struct uip_routing_hdr *rh_header;
290 struct uip_rpl_srh_hdr *srh_header;
293 rh_header = (
struct uip_routing_hdr *)uipbuf_search_header(
uip_buf,
uip_len,
296 if(rh_header != NULL && rh_header->routing_type == RPL_RH_TYPE_SRH) {
298 uint8_t cmpri, cmpre;
302 uint8_t segments_left;
303 uip_ipaddr_t current_dest_addr;
305 srh_header = (
struct uip_rpl_srh_hdr *)(((uint8_t *)rh_header) + RPL_RH_LEN);
306 segments_left = rh_header->seg_left;
307 ext_len = rh_header->len * 8 + 8;
308 cmpri = srh_header->cmpr >> 4;
309 cmpre = srh_header->cmpr & 0x0f;
310 padding = srh_header->pad >> 4;
311 path_len = ((ext_len - padding - RPL_RH_LEN - RPL_SRH_LEN - (16 - cmpre)) / (16 - cmpri)) + 1;
314 LOG_DBG(
"read SRH, path len %u, segments left %u, Cmpri %u, Cmpre %u, ext len %u (padding %u)\n",
315 path_len, segments_left, cmpri, cmpre, ext_len, padding);
317 if(segments_left == 0) {
319 }
else if(segments_left > path_len) {
321 LOG_ERR(
"SRH with too many segments left (%u > %u)\n",
322 segments_left, path_len);
325 if(!srh_is_valid(rh_header, srh_header)) {
326 LOG_ERR(
"Invalid SRH hop sequence\n");
331 uint8_t i = path_len - segments_left;
332 uint8_t cmpr = segments_left == 1 ? cmpre : cmpri;
333 ptrdiff_t rh_offset = (uint8_t *)rh_header -
uip_buf;
334 size_t addr_offset = RPL_RH_LEN + RPL_SRH_LEN + (i * (16 - cmpri));
336 if(rh_offset + addr_offset + 16 - cmpr >
UIP_BUFSIZE) {
337 LOG_ERR(
"Invalid SRH address pointer\n");
341 uint8_t *addr_ptr = ((uint8_t *)rh_header) + addr_offset;
348 memcpy(((uint8_t *)&
UIP_IP_BUF->destipaddr) + cmpr, addr_ptr, 16 - cmpr);
350 memcpy(addr_ptr, ((uint8_t *)¤t_dest_addr) + cmpr, 16 - cmpr);
353 rh_header->seg_left--;
355 LOG_INFO(
"SRH next hop ");
369count_matching_bytes(
const void *p1,
const void *p2,
size_t n)
371 for(
size_t i = 0; i < n; i++) {
372 if(((uint8_t *)p1)[i] != ((uint8_t *)p2)[i]) {
380insert_srh_header(
void)
385 uint8_t cmpri, cmpre;
392 uip_ipaddr_t node_addr;
395 struct uip_routing_hdr *rh_hdr = (
struct uip_routing_hdr *)UIP_IP_PAYLOAD(0);
396 struct uip_rpl_srh_hdr *srh_hdr = (
struct uip_rpl_srh_hdr *)(UIP_IP_PAYLOAD(0) + RPL_RH_LEN);
398 LOG_INFO(
"SRH creating source routing header with destination ");
408 LOG_ERR(
"SRH DAG not found\n");
413 if(dest_node == NULL) {
419 if(root_node == NULL) {
420 LOG_ERR(
"SRH root node not found\n");
425 LOG_ERR(
"SRH no path found to destination\n");
431 node = dest_node->parent;
436 if(node == root_node) {
437 LOG_DBG(
"SRH no need to insert SRH\n");
441 while(node != NULL && node != root_node) {
443 NETSTACK_ROUTING.get_sr_node_ipaddr(&node_addr, node);
446 cmpri = MIN(cmpri, count_matching_bytes(&node_addr, &
UIP_IP_BUF->destipaddr, 16));
450 LOG_DBG_6ADDR(&node_addr);
458 ext_len = RPL_RH_LEN + RPL_SRH_LEN
459 + (path_len - 1) * (16 - cmpre)
462 padding = ext_len % 8 == 0 ? 0 : (8 - (ext_len % 8));
465 LOG_DBG(
"SRH Path len: %u, ComprI %u, ComprE %u, ext len %u (padding %u)\n",
466 path_len, cmpri, cmpre, ext_len, padding);
470 LOG_ERR(
"Too long packet: impossible to add SRH (%u bytes)\n", ext_len);
484 rh_hdr->len = (ext_len - 8) / 8;
485 rh_hdr->routing_type = RPL_RH_TYPE_SRH;
486 rh_hdr->seg_left = path_len;
489 srh_hdr->cmpr = (cmpri << 4) + cmpre;
490 srh_hdr->pad = padding << 4;
497 hop_ptr = ((uint8_t *)rh_hdr) + ext_len - padding;
499 while(node != NULL && node->parent != root_node) {
500 NETSTACK_ROUTING.get_sr_node_ipaddr(&node_addr, node);
502 hop_ptr -= (16 - cmpri);
503 memcpy(hop_ptr, ((uint8_t *)&node_addr) + cmpri, 16 - cmpri);
510 NETSTACK_ROUTING.get_sr_node_ipaddr(&node_addr, node);
514 uipbuf_add_ext_hdr(ext_len);
521update_hbh_header(
void)
523 rpl_instance_t *instance;
524 rpl_parent_t *parent;
525 struct uip_hbho_hdr *hbh_hdr = (
struct uip_hbho_hdr *)UIP_IP_PAYLOAD(0);
526 struct uip_ext_hdr_opt_rpl *rpl_opt = (
struct uip_ext_hdr_opt_rpl *)(UIP_IP_PAYLOAD(0) + 2);
529 rpl_opt->opt_type == UIP_EXT_HDR_OPT_RPL) {
530 if(hbh_hdr->len != ((RPL_HOP_BY_HOP_LEN - 8) / 8) ||
531 rpl_opt->opt_len != RPL_HDR_OPT_LEN) {
533 LOG_ERR(
"Hop-by-hop extension header has wrong size (%u)\n",
538 instance = rpl_get_instance(rpl_opt->instance);
539 if(instance == NULL || !instance->used || !instance->current_dag->joined) {
540 LOG_ERR(
"Unable to add/update hop-by-hop extension header: incorrect instance\n");
544 LOG_INFO(
"Updating RPL option\n");
546 rpl_opt->senderrank =
UIP_HTONS(instance->current_dag->rank);
547 rpl_opt->instance = instance->instance_id;
549 if(RPL_IS_STORING(instance)) {
558 if(rpl_opt->flags & RPL_HDR_OPT_DOWN) {
559 if(uip_ds6_route_lookup(&
UIP_IP_BUF->destipaddr) == NULL) {
560 rpl_opt->flags |= RPL_HDR_OPT_FWD_ERR;
561 LOG_WARN(
"RPL forwarding error\n");
564 LOG_WARN(
"RPL generate No-Path DAO\n");
565 parent = rpl_get_parent((uip_lladdr_t *)packetbuf_addr(PACKETBUF_ADDR_SENDER));
567 rpl_schedule_unicast_dao_immediately(instance, parent,
580 if(uip_ds6_route_lookup(&
UIP_IP_BUF->destipaddr) == NULL) {
583 rpl_opt->flags &= ~RPL_HDR_OPT_DOWN;
584 LOG_DBG(
"RPL option going up\n");
587 rpl_opt->flags |= RPL_HDR_OPT_DOWN;
588 LOG_DBG(
"RPL option going down\n");
598insert_hbh_header(
const rpl_instance_t *instance)
600 struct uip_hbho_hdr *hbh_hdr = (
struct uip_hbho_hdr *)UIP_IP_PAYLOAD(0);
601 struct uip_ext_hdr_opt_rpl *rpl_opt = (
struct uip_ext_hdr_opt_rpl *)(UIP_IP_PAYLOAD(2));
604 LOG_DBG(
"Creating hop-by-hop option\n");
606 LOG_ERR(
"Too long packet: impossible to add hop-by-hop option\n");
611 memmove(UIP_IP_PAYLOAD(RPL_HOP_BY_HOP_LEN), UIP_IP_PAYLOAD(0),
613 memset(UIP_IP_PAYLOAD(0), 0, RPL_HOP_BY_HOP_LEN);
620 hbh_hdr->len = (RPL_HOP_BY_HOP_LEN - 8) / 8;
621 rpl_opt->opt_type = UIP_EXT_HDR_OPT_RPL;
622 rpl_opt->opt_len = RPL_HDR_OPT_LEN;
624 rpl_opt->senderrank =
UIP_HTONS(instance->current_dag->rank);
625 rpl_opt->instance = instance->instance_id;
627 uipbuf_add_ext_hdr(RPL_HOP_BY_HOP_LEN);
631 return update_hbh_header();
637 uint8_t *prev_proto_ptr;
640 uint8_t *next_header;
641 struct uip_ext_hdr *ext_ptr;
642 struct uip_ext_hdr_opt *opt_ptr;
644 next_header = uipbuf_get_next_header(
uip_buf,
uip_len, &protocol,
true);
645 if(next_header == NULL) {
649 ext_ptr = (
struct uip_ext_hdr *)next_header;
652 while(uip_is_proto_ext_hdr(protocol)) {
653 opt_ptr = (
struct uip_ext_hdr_opt *)(next_header + 2);
654 if(protocol == UIP_PROTO_ROUTING ||
655 (protocol ==
UIP_PROTO_HBHO && opt_ptr->type == UIP_EXT_HDR_OPT_RPL)) {
657 *prev_proto_ptr = ext_ptr->next;
658 ext_len = ext_ptr->len * 8 + 8;
659 if(uipbuf_add_ext_hdr(-ext_len) ==
false) {
669 memmove(next_header, next_header + ext_len,
673 protocol = *prev_proto_ptr;
676 next_header = uipbuf_get_next_header(next_header,
679 if(next_header == NULL) {
683 ext_ptr = (
struct uip_ext_hdr *)next_header;
684 prev_proto_ptr = &ext_ptr->next;
694 if(default_instance == NULL || default_instance->current_dag == NULL ||
700 if(default_instance->current_dag->rank == ROOT_RANK(default_instance)) {
704 if(rpl_get_dag(&
UIP_IP_BUF->destipaddr) != NULL) {
706 if(RPL_IS_NON_STORING(default_instance)) {
707 return insert_srh_header();
709 return insert_hbh_header(default_instance);
723 return insert_hbh_header(default_instance);
726 return update_hbh_header();
uip_sr_node_t * uip_sr_get_node(const void *graph, const uip_ipaddr_t *addr)
Looks up for a source routing node from its IPv6 global address.
struct uip_ds6_route uip_ds6_route_t
An entry in the routing table.
int rpl_ext_header_update(void)
Adds/updates all RPL extension headers to current uIP packet.
#define uip_is_addr_unspecified(a)
Is IPv6 address a the unspecified address a is of type uip_ipaddr_t.
int uip_sr_is_addr_reachable(const void *graph, const uip_ipaddr_t *addr)
Telle whether an address is reachable, i.e.
#define uip_is_addr_mcast(a)
is address a multicast address, see RFC 4291 a is of type uip_ipaddr_t*
int rpl_ext_header_srh_get_next_hop(uip_ipaddr_t *ipaddr)
Look for next hop from SRH of current uIP packet.
#define uip_is_addr_linklocal(a)
is addr (a) a link local unicast address, see RFC 4291 i.e.
struct uip_sr_node uip_sr_node_t
A node in a source routing graph, stored at the root and representing all child-parent relationship.
int rpl_ext_header_srh_update(void)
Process and update SRH in-place, i.e.
bool rpl_ext_header_remove(void)
Removes all RPL extension headers.
int rpl_ext_header_hbh_update(uint8_t *ext_buf, int opt_offset)
Process and update the RPL hop-by-hop extension headers of the current uIP packet.
uip_ds6_netif_t uip_ds6_if
The single interface.
#define uip_is_addr_loopback(a)
Is IPv6 address a the unspecified address a is of type uip_ipaddr_t.
#define UIP_PROTO_HBHO
extension headers types
#define UIP_IP_BUF
Direct access to IPv6 header.
#define UIP_HTONS(n)
Convert 16-bit quantity from host byte order to network byte order.
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
#define uip_buf
Macro to access uip_aligned_buf as an array of bytes.
uint16_t uip_ext_len
The length of the extension headers.
uint16_t uip_len
The length of the packet in the uip_buf buffer.
#define UIP_BUFSIZE
The size of the uIP packet buffer.
#define UIP_LINK_MTU
The maximum transmission unit at the IP layer.
Header file for the logging system.
Header file for the Packet buffer (packetbuf) management.
Routing driver header file.
Header for the Contiki/uIP interface.
Header file for IPv6-related data structures.
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
Header file for the uIP TCP/IP stack.