Contiki-NG
uip-ds6-route.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * 3. Neither the name of the copyright holder nor the names of its
15  * contributors may be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29  * OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 /**
33  * \addtogroup uip
34  * @{
35  */
36 
37 /**
38  * \file
39  * Routing table manipulation
40  */
41 #include "net/ipv6/uip-ds6.h"
42 #include "net/ipv6/uip-ds6-route.h"
43 #include "net/ipv6/uip.h"
44 
45 #include "lib/list.h"
46 #include "lib/memb.h"
47 #include "net/nbr-table.h"
48 
49 /* Log configuration */
50 #include "sys/log.h"
51 #define LOG_MODULE "IPv6 Route"
52 #define LOG_LEVEL LOG_LEVEL_IPV6
53 
54 #if BUILD_WITH_ORCHESTRA
55 
56 #ifndef NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK
57 #define NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK orchestra_callback_child_added
58 #endif /* NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK */
59 
60 #ifndef NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK
61 #define NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK orchestra_callback_child_removed
62 #endif /* NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK */
63 
64 #endif /* BUILD_WITH_ORCHESTRA */
65 
66 /* A configurable function called after adding a new neighbor as next hop */
67 #ifdef NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK
68 void NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK(const linkaddr_t *addr);
69 #endif /* NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK */
70 
71 /* A configurable function called after removing a next hop neighbor */
72 #ifdef NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK
73 void NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK(const linkaddr_t *addr);
74 #endif /* NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK */
75 
76 #if (UIP_MAX_ROUTES != 0)
77 /* The nbr_routes holds a neighbor table to be able to maintain
78  information about what routes go through what neighbor. This
79  neighbor table is registered with the central nbr-table repository
80  so that it will be maintained along with the rest of the neighbor
81  tables in the system. */
82 NBR_TABLE_GLOBAL(struct uip_ds6_route_neighbor_routes, nbr_routes);
83 MEMB(neighborroutememb, struct uip_ds6_route_neighbor_route, UIP_DS6_ROUTE_NB);
84 
85 /* Each route is repressented by a uip_ds6_route_t structure and
86  memory for each route is allocated from the routememb memory
87  block. These routes are maintained on the routelist. */
88 LIST(routelist);
89 MEMB(routememb, uip_ds6_route_t, UIP_DS6_ROUTE_NB);
90 
91 static int num_routes = 0;
92 static void rm_routelist_callback(nbr_table_item_t *ptr);
93 
94 #endif /* (UIP_MAX_ROUTES != 0) */
95 
96 /* Default routes are held on the defaultrouterlist and their
97  structures are allocated from the defaultroutermemb memory block.*/
98 LIST(defaultrouterlist);
99 MEMB(defaultroutermemb, uip_ds6_defrt_t, UIP_DS6_DEFRT_NB);
100 
101 #if UIP_DS6_NOTIFICATIONS
102 LIST(notificationlist);
103 #endif
104 
105 /*---------------------------------------------------------------------------*/
106 static void
107 assert_nbr_routes_list_sane(void)
108 {
109  uip_ds6_route_t *r;
110  int count;
111 
112  /* Check if the route list has an infinite loop. */
113  for(r = uip_ds6_route_head(),
114  count = 0;
115  r != NULL &&
116  count < UIP_DS6_ROUTE_NB * 2;
117  r = uip_ds6_route_next(r),
118  count++);
119 
120  if(count > UIP_DS6_ROUTE_NB) {
121  printf("uip-ds6-route.c: assert_nbr_routes_list_sane route list is in infinite loop\n");
122  }
123 
124 #if (UIP_MAX_ROUTES != 0)
125  /* Make sure that the route list has as many entries as the
126  num_routes vairable. */
127  if(count < num_routes) {
128  printf("uip-ds6-route.c: assert_nbr_routes_list_sane too few entries on route list: should be %d, is %d, max %d\n",
129  num_routes, count, UIP_MAX_ROUTES);
130  }
131 #endif /* (UIP_MAX_ROUTES != 0) */
132 }
133 /*---------------------------------------------------------------------------*/
134 #if UIP_DS6_NOTIFICATIONS
135 static void
136 call_route_callback(int event, const uip_ipaddr_t *route,
137  const uip_ipaddr_t *nexthop)
138 {
139  int num;
140  struct uip_ds6_notification *n;
141  for(n = list_head(notificationlist);
142  n != NULL;
143  n = list_item_next(n)) {
144  if(event == UIP_DS6_NOTIFICATION_DEFRT_ADD ||
145  event == UIP_DS6_NOTIFICATION_DEFRT_RM) {
146  num = list_length(defaultrouterlist);
147  } else {
148  num = num_routes;
149  }
150  n->callback(event, route, nexthop, num);
151  }
152 }
153 /*---------------------------------------------------------------------------*/
154 void
155 uip_ds6_notification_add(struct uip_ds6_notification *n,
156  uip_ds6_notification_callback c)
157 {
158  if(n != NULL && c != NULL) {
159  n->callback = c;
160  list_add(notificationlist, n);
161  }
162 }
163 /*---------------------------------------------------------------------------*/
164 void
165 uip_ds6_notification_rm(struct uip_ds6_notification *n)
166 {
167  list_remove(notificationlist, n);
168 }
169 #endif
170 /*---------------------------------------------------------------------------*/
171 void
172 uip_ds6_route_init(void)
173 {
174 #if (UIP_MAX_ROUTES != 0)
175  memb_init(&routememb);
176  list_init(routelist);
177  nbr_table_register(nbr_routes,
178  (nbr_table_callback *)rm_routelist_callback);
179 #endif /* (UIP_MAX_ROUTES != 0) */
180 
181  memb_init(&defaultroutermemb);
182  list_init(defaultrouterlist);
183 
184 #if UIP_DS6_NOTIFICATIONS
185  list_init(notificationlist);
186 #endif
187 }
188 #if (UIP_MAX_ROUTES != 0)
189 /*---------------------------------------------------------------------------*/
190 static uip_lladdr_t *
191 uip_ds6_route_nexthop_lladdr(uip_ds6_route_t *route)
192 {
193  if(route != NULL) {
194  return (uip_lladdr_t *)nbr_table_get_lladdr(nbr_routes,
195  route->neighbor_routes);
196  } else {
197  return NULL;
198  }
199 }
200 #endif /* (UIP_MAX_ROUTES != 0) */
201 /*---------------------------------------------------------------------------*/
202 const uip_ipaddr_t *
203 uip_ds6_route_nexthop(uip_ds6_route_t *route)
204 {
205 #if (UIP_MAX_ROUTES != 0)
206  if(route != NULL) {
207  return uip_ds6_nbr_ipaddr_from_lladdr(uip_ds6_route_nexthop_lladdr(route));
208  } else {
209  return NULL;
210  }
211 #else /* (UIP_MAX_ROUTES != 0) */
212  return NULL;
213 #endif /* (UIP_MAX_ROUTES != 0) */
214 }
215 /*---------------------------------------------------------------------------*/
217 uip_ds6_route_head(void)
218 {
219 #if (UIP_MAX_ROUTES != 0)
220  return list_head(routelist);
221 #else /* (UIP_MAX_ROUTES != 0) */
222  return NULL;
223 #endif /* (UIP_MAX_ROUTES != 0) */
224 }
225 /*---------------------------------------------------------------------------*/
227 uip_ds6_route_next(uip_ds6_route_t *r)
228 {
229 #if (UIP_MAX_ROUTES != 0)
230  if(r != NULL) {
232  return n;
233  }
234 #endif /* (UIP_MAX_ROUTES != 0) */
235  return NULL;
236 }
237 /*---------------------------------------------------------------------------*/
238 int
239 uip_ds6_route_is_nexthop(const uip_ipaddr_t *ipaddr)
240 {
241 #if (UIP_MAX_ROUTES != 0)
242  const uip_lladdr_t *lladdr;
243  lladdr = uip_ds6_nbr_lladdr_from_ipaddr(ipaddr);
244 
245  if(lladdr == NULL) {
246  return 0;
247  }
248 
249  return nbr_table_get_from_lladdr(nbr_routes, (linkaddr_t *)lladdr) != NULL;
250 #else /* (UIP_MAX_ROUTES != 0) */
251  return 0;
252 #endif /* (UIP_MAX_ROUTES != 0) */
253 }
254 /*---------------------------------------------------------------------------*/
255 int
256 uip_ds6_route_num_routes(void)
257 {
258 #if (UIP_MAX_ROUTES != 0)
259  return num_routes;
260 #else /* (UIP_MAX_ROUTES != 0) */
261  return 0;
262 #endif /* (UIP_MAX_ROUTES != 0) */
263 }
264 /*---------------------------------------------------------------------------*/
266 uip_ds6_route_lookup(const uip_ipaddr_t *addr)
267 {
268 #if (UIP_MAX_ROUTES != 0)
269  uip_ds6_route_t *r;
270  uip_ds6_route_t *found_route;
271  uint8_t longestmatch;
272 
273  LOG_INFO("Looking up route for ");
274  LOG_INFO_6ADDR(addr);
275  LOG_INFO_("\n");
276 
277  if(addr == NULL) {
278  return NULL;
279  }
280 
281  found_route = NULL;
282  longestmatch = 0;
283  for(r = uip_ds6_route_head();
284  r != NULL;
285  r = uip_ds6_route_next(r)) {
286  if(r->length >= longestmatch &&
287  uip_ipaddr_prefixcmp(addr, &r->ipaddr, r->length)) {
288  longestmatch = r->length;
289  found_route = r;
290  /* check if total match - e.g. all 128 bits do match */
291  if(longestmatch == 128) {
292  break;
293  }
294  }
295  }
296 
297  if(found_route != NULL) {
298  LOG_INFO("Found route: ");
299  LOG_INFO_6ADDR(addr);
300  LOG_INFO_(" via ");
301  LOG_INFO_6ADDR(uip_ds6_route_nexthop(found_route));
302  LOG_INFO_("\n");
303  } else {
304  LOG_WARN("No route found\n");
305  }
306 
307  if(found_route != NULL && found_route != list_head(routelist)) {
308  /* If we found a route, we put it at the start of the routeslist
309  list. The list is ordered by how recently we looked them up:
310  the least recently used route will be at the end of the
311  list - for fast lookups (assuming multiple packets to the same node). */
312 
313  list_remove(routelist, found_route);
314  list_push(routelist, found_route);
315  }
316 
317  return found_route;
318 #else /* (UIP_MAX_ROUTES != 0) */
319  return NULL;
320 #endif /* (UIP_MAX_ROUTES != 0) */
321 }
322 /*---------------------------------------------------------------------------*/
324 uip_ds6_route_add(const uip_ipaddr_t *ipaddr, uint8_t length,
325  const uip_ipaddr_t *nexthop)
326 {
327 #if (UIP_MAX_ROUTES != 0)
328  uip_ds6_route_t *r;
329  struct uip_ds6_route_neighbor_route *nbrr;
330 
331  if(LOG_DBG_ENABLED) {
332  assert_nbr_routes_list_sane();
333  }
334 
335  if(ipaddr == NULL || nexthop == NULL) {
336  return NULL;
337  }
338 
339  /* Get link-layer address of next hop, make sure it is in neighbor table */
340  const uip_lladdr_t *nexthop_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(nexthop);
341  if(nexthop_lladdr == NULL) {
342  LOG_WARN("Add: neighbor link-local address unknown for ");
343  LOG_WARN_6ADDR(nexthop);
344  LOG_WARN_("\n");
345  return NULL;
346  }
347 
348  /* First make sure that we don't add a route twice. If we find an
349  existing route for our destination, we'll delete the old
350  one first. */
351  r = uip_ds6_route_lookup(ipaddr);
352  if(r != NULL) {
353  const uip_ipaddr_t *current_nexthop;
354  current_nexthop = uip_ds6_route_nexthop(r);
355  if(current_nexthop != NULL && uip_ipaddr_cmp(nexthop, current_nexthop)) {
356  /* no need to update route - already correct! */
357  return r;
358  }
359  LOG_INFO("Add: old route for ");
360  LOG_INFO_6ADDR(ipaddr);
361  LOG_INFO_(" found, deleting it\n");
362 
363  uip_ds6_route_rm(r);
364  }
365  {
366  struct uip_ds6_route_neighbor_routes *routes;
367  /* If there is no routing entry, create one. We first need to
368  check if we have room for this route. If not, we remove the
369  least recently used one we have. */
370 
371  if(uip_ds6_route_num_routes() == UIP_DS6_ROUTE_NB) {
372  uip_ds6_route_t *oldest;
373  oldest = NULL;
374 #if UIP_DS6_ROUTE_REMOVE_LEAST_RECENTLY_USED
375  /* Removing the oldest route entry from the route table. The
376  least recently used route is the first route on the list. */
377  oldest = list_tail(routelist);
378 #endif
379  if(oldest == NULL) {
380  return NULL;
381  }
382  LOG_INFO("Add: dropping route to ");
383  LOG_INFO_6ADDR(&oldest->ipaddr);
384  LOG_INFO_("\n");
385  uip_ds6_route_rm(oldest);
386  }
387 
388 
389  /* Every neighbor on our neighbor table holds a struct
390  uip_ds6_route_neighbor_routes which holds a list of routes that
391  go through the neighbor. We add our route entry to this list.
392 
393  We first check to see if we already have this neighbor in our
394  nbr_route table. If so, the neighbor already has a route entry
395  list.
396  */
397  routes = nbr_table_get_from_lladdr(nbr_routes,
398  (linkaddr_t *)nexthop_lladdr);
399 
400  if(routes == NULL) {
401  /* If the neighbor did not have an entry in our neighbor table,
402  we create one. The nbr_table_add_lladdr() function returns a
403  pointer to a pointer that we may use for our own purposes. We
404  initialize this pointer with the list of routing entries that
405  are attached to this neighbor. */
406  routes = nbr_table_add_lladdr(nbr_routes,
407  (linkaddr_t *)nexthop_lladdr,
408  NBR_TABLE_REASON_ROUTE, NULL);
409  if(routes == NULL) {
410  /* This should not happen, as we explicitly deallocated one
411  route table entry above. */
412  LOG_ERR("Add: could not allocate neighbor table entry\n");
413  return NULL;
414  }
415  LIST_STRUCT_INIT(routes, route_list);
416 #ifdef NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK
417  NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK((const linkaddr_t *)nexthop_lladdr);
418 #endif
419  }
420 
421  /* Allocate a routing entry and populate it. */
422  r = memb_alloc(&routememb);
423 
424  if(r == NULL) {
425  /* This should not happen, as we explicitly deallocated one
426  route table entry above. */
427  LOG_ERR("Add: could not allocate route\n");
428  return NULL;
429  }
430 
431  /* add new routes first - assuming that there is a reason to add this
432  and that there is a packet coming soon. */
433  list_push(routelist, r);
434 
435  nbrr = memb_alloc(&neighborroutememb);
436  if(nbrr == NULL) {
437  /* This should not happen, as we explicitly deallocated one
438  route table entry above. */
439  LOG_ERR("Add: could not allocate neighbor route list entry\n");
440  memb_free(&routememb, r);
441  return NULL;
442  }
443 
444  nbrr->route = r;
445  /* Add the route to this neighbor */
446  list_add(routes->route_list, nbrr);
447  r->neighbor_routes = routes;
448  num_routes++;
449 
450  LOG_INFO("Add: num %d\n", num_routes);
451 
452  /* lock this entry so that nexthop is not removed */
453  nbr_table_lock(nbr_routes, routes);
454  }
455 
456  uip_ipaddr_copy(&(r->ipaddr), ipaddr);
457  r->length = length;
458 
459 #ifdef UIP_DS6_ROUTE_STATE_TYPE
460  memset(&r->state, 0, sizeof(UIP_DS6_ROUTE_STATE_TYPE));
461 #endif
462 
463  LOG_INFO("Add: adding route: ");
464  LOG_INFO_6ADDR(ipaddr);
465  LOG_INFO_(" via ");
466  LOG_INFO_6ADDR(nexthop);
467  LOG_INFO_("\n");
468  LOG_ANNOTATE("#L %u 1;blue\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
469 
470 #if UIP_DS6_NOTIFICATIONS
471  call_route_callback(UIP_DS6_NOTIFICATION_ROUTE_ADD, ipaddr, nexthop);
472 #endif
473 
474  if(LOG_DBG_ENABLED) {
475  assert_nbr_routes_list_sane();
476  }
477  return r;
478 
479 #else /* (UIP_MAX_ROUTES != 0) */
480  return NULL;
481 #endif /* (UIP_MAX_ROUTES != 0) */
482 }
483 
484 /*---------------------------------------------------------------------------*/
485 void
486 uip_ds6_route_rm(uip_ds6_route_t *route)
487 {
488 #if (UIP_MAX_ROUTES != 0)
489  struct uip_ds6_route_neighbor_route *neighbor_route;
490 
491  if(LOG_DBG_ENABLED) {
492  assert_nbr_routes_list_sane();
493  }
494 
495  if(route != NULL && route->neighbor_routes != NULL) {
496 
497  LOG_INFO("Rm: removing route: ");
498  LOG_INFO_6ADDR(&route->ipaddr);
499  LOG_INFO_("\n");
500 
501  /* Remove the route from the route list */
502  list_remove(routelist, route);
503 
504  /* Find the corresponding neighbor_route and remove it. */
505  for(neighbor_route = list_head(route->neighbor_routes->route_list);
506  neighbor_route != NULL && neighbor_route->route != route;
507  neighbor_route = list_item_next(neighbor_route));
508 
509  if(neighbor_route == NULL) {
510  LOG_INFO("Rm: neighbor_route was NULL for ");
511  LOG_INFO_6ADDR(&route->ipaddr);
512  LOG_INFO_("\n");
513  }
514  list_remove(route->neighbor_routes->route_list, neighbor_route);
515  if(list_head(route->neighbor_routes->route_list) == NULL) {
516  /* If this was the only route using this neighbor, remove the
517  neighbor from the table - this implicitly unlocks nexthop */
518 #if LOG_WITH_ANNOTATE
519  const uip_ipaddr_t *nexthop = uip_ds6_route_nexthop(route);
520  if(nexthop != NULL) {
521  LOG_ANNOTATE("#L %u 0\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
522  }
523 #endif /* LOG_WITH_ANNOTATE */
524  LOG_INFO("Rm: removing neighbor too\n");
525  nbr_table_remove(nbr_routes, route->neighbor_routes->route_list);
526 #ifdef NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK
527  NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK(
528  (const linkaddr_t *)nbr_table_get_lladdr(nbr_routes, route->neighbor_routes->route_list));
529 #endif
530  }
531  memb_free(&routememb, route);
532  memb_free(&neighborroutememb, neighbor_route);
533 
534  num_routes--;
535 
536  LOG_INFO("Rm: num %d\n", num_routes);
537 
538 #if UIP_DS6_NOTIFICATIONS
539  call_route_callback(UIP_DS6_NOTIFICATION_ROUTE_RM,
540  &route->ipaddr, uip_ds6_route_nexthop(route));
541 #endif
542  }
543 
544  if(LOG_DBG_ENABLED) {
545  assert_nbr_routes_list_sane();
546  }
547 
548 #endif /* (UIP_MAX_ROUTES != 0) */
549  return;
550 }
551 #if (UIP_MAX_ROUTES != 0)
552 /*---------------------------------------------------------------------------*/
553 static void
554 rm_routelist(struct uip_ds6_route_neighbor_routes *routes)
555 {
556  if(LOG_DBG_ENABLED) {
557  assert_nbr_routes_list_sane();
558  }
559 
560  if(routes != NULL && routes->route_list != NULL) {
562  r = list_head(routes->route_list);
563  while(r != NULL) {
564  uip_ds6_route_rm(r->route);
565  r = list_head(routes->route_list);
566  }
567  nbr_table_remove(nbr_routes, routes);
568  }
569 
570  if(LOG_DBG_ENABLED) {
571  assert_nbr_routes_list_sane();
572  }
573 }
574 /*---------------------------------------------------------------------------*/
575 static void
576 rm_routelist_callback(nbr_table_item_t *ptr)
577 {
578  rm_routelist((struct uip_ds6_route_neighbor_routes *)ptr);
579 }
580 #endif /* (UIP_MAX_ROUTES != 0) */
581 /*---------------------------------------------------------------------------*/
582 void
583 uip_ds6_route_rm_by_nexthop(const uip_ipaddr_t *nexthop)
584 {
585 #if (UIP_MAX_ROUTES != 0)
586  /* Get routing entry list of this neighbor */
587  const uip_lladdr_t *nexthop_lladdr;
588  struct uip_ds6_route_neighbor_routes *routes;
589 
590  nexthop_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(nexthop);
591  routes = nbr_table_get_from_lladdr(nbr_routes,
592  (linkaddr_t *)nexthop_lladdr);
593  rm_routelist(routes);
594 #endif /* (UIP_MAX_ROUTES != 0) */
595 }
596 /*---------------------------------------------------------------------------*/
598 uip_ds6_defrt_head(void)
599 {
600  return list_head(defaultrouterlist);
601 }
602 /*---------------------------------------------------------------------------*/
604 uip_ds6_defrt_add(const uip_ipaddr_t *ipaddr, unsigned long interval)
605 {
606  uip_ds6_defrt_t *d;
607 
608  if(LOG_DBG_ENABLED) {
609  assert_nbr_routes_list_sane();
610  }
611 
612  if(ipaddr == NULL) {
613  return NULL;
614  }
615 
616  d = uip_ds6_defrt_lookup(ipaddr);
617  if(d == NULL) {
618  d = memb_alloc(&defaultroutermemb);
619  if(d == NULL) {
620  LOG_ERR("Add default: could not add default route to ");
621  LOG_ERR_6ADDR(ipaddr);
622  LOG_ERR_(", out of memory\n");
623  return NULL;
624  } else {
625  LOG_INFO("Add default: adding default route to ");
626  LOG_INFO_6ADDR(ipaddr);
627  LOG_INFO_("\n");
628  }
629 
630  list_push(defaultrouterlist, d);
631  }
632  else {
633  LOG_INFO("Refreshing default\n");
634  }
635 
636  uip_ipaddr_copy(&d->ipaddr, ipaddr);
637  if(interval != 0) {
638  stimer_set(&d->lifetime, interval);
639  d->isinfinite = 0;
640  } else {
641  d->isinfinite = 1;
642  }
643 
644  LOG_ANNOTATE("#L %u 1\n", ipaddr->u8[sizeof(uip_ipaddr_t) - 1]);
645 
646 #if UIP_DS6_NOTIFICATIONS
647  call_route_callback(UIP_DS6_NOTIFICATION_DEFRT_ADD, ipaddr, ipaddr);
648 #endif
649 
650 if(LOG_DBG_ENABLED) {
651  assert_nbr_routes_list_sane();
652 }
653 
654  return d;
655 }
656 /*---------------------------------------------------------------------------*/
657 void
658 uip_ds6_defrt_rm(uip_ds6_defrt_t *defrt)
659 {
660  uip_ds6_defrt_t *d;
661 
662  if(LOG_DBG_ENABLED) {
663  assert_nbr_routes_list_sane();
664  }
665 
666  /* Make sure that the defrt is in the list before we remove it. */
667  for(d = list_head(defaultrouterlist);
668  d != NULL;
669  d = list_item_next(d)) {
670  if(d == defrt) {
671  LOG_INFO("Removing default\n");
672  list_remove(defaultrouterlist, defrt);
673  memb_free(&defaultroutermemb, defrt);
674  LOG_ANNOTATE("#L %u 0\n", defrt->ipaddr.u8[sizeof(uip_ipaddr_t) - 1]);
675 #if UIP_DS6_NOTIFICATIONS
676  call_route_callback(UIP_DS6_NOTIFICATION_DEFRT_RM,
677  &defrt->ipaddr, &defrt->ipaddr);
678 #endif
679  return;
680  }
681  }
682 
683  if(LOG_DBG_ENABLED) {
684  assert_nbr_routes_list_sane();
685  }
686 }
687 /*---------------------------------------------------------------------------*/
689 uip_ds6_defrt_lookup(const uip_ipaddr_t *ipaddr)
690 {
691  uip_ds6_defrt_t *d;
692  if(ipaddr == NULL) {
693  return NULL;
694  }
695  for(d = list_head(defaultrouterlist);
696  d != NULL;
697  d = list_item_next(d)) {
698  if(uip_ipaddr_cmp(&d->ipaddr, ipaddr)) {
699  return d;
700  }
701  }
702  return NULL;
703 }
704 /*---------------------------------------------------------------------------*/
705 const uip_ipaddr_t *
706 uip_ds6_defrt_choose(void)
707 {
708  uip_ds6_defrt_t *d;
709  uip_ds6_nbr_t *bestnbr;
710  uip_ipaddr_t *addr;
711 
712  addr = NULL;
713  for(d = list_head(defaultrouterlist);
714  d != NULL;
715  d = list_item_next(d)) {
716  LOG_INFO("Default route, IP address ");
717  LOG_INFO_6ADDR(&d->ipaddr);
718  LOG_INFO_("\n");
719  bestnbr = uip_ds6_nbr_lookup(&d->ipaddr);
720  if(bestnbr != NULL && bestnbr->state != NBR_INCOMPLETE) {
721  LOG_INFO("Default route found, IP address ");
722  LOG_INFO_6ADDR(&d->ipaddr);
723  LOG_INFO_("\n");
724  return &d->ipaddr;
725  } else {
726  addr = &d->ipaddr;
727  LOG_INFO("Default route Incomplete found, IP address ");
728  LOG_INFO_6ADDR(&d->ipaddr);
729  LOG_INFO_("\n");
730  }
731  }
732  return addr;
733 }
734 /*---------------------------------------------------------------------------*/
735 void
736 uip_ds6_defrt_periodic(void)
737 {
738  uip_ds6_defrt_t *d;
739  d = list_head(defaultrouterlist);
740  while(d != NULL) {
741  if(!d->isinfinite &&
742  stimer_expired(&d->lifetime)) {
743  LOG_INFO("Default route periodic: defrt lifetime expired\n");
744  uip_ds6_defrt_rm(d);
745  d = list_head(defaultrouterlist);
746  } else {
747  d = list_item_next(d);
748  }
749  }
750 }
751 /*---------------------------------------------------------------------------*/
752 /** @} */
static uip_ipaddr_t ipaddr
Pointer to prefix information option in uip_buf.
Definition: uip-nd6.c:116
#define LIST_STRUCT_INIT(struct_ptr, name)
Initialize a linked list that is part of a structure.
Definition: list.h:125
An entry in the default router list.
int memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition: memb.c:78
void list_push(list_t list, void *item)
Add an item to the start of the list.
Definition: list.c:164
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:107
A neighbor route list entry, used on the uip_ds6_route->neighbor_routes->route_list list...
The neighbor routes hold a list of routing table entries that are attached to a specific neihbor...
int stimer_expired(struct stimer *t)
Check if a timer has expired.
Definition: stimer.c:127
void * list_tail(list_t list)
Get the tail of a list.
Definition: list.c:117
Header file for IPv6-related data structures.
An entry in the routing table.
void stimer_set(struct stimer *t, unsigned long interval)
Set a timer.
Definition: stimer.c:67
uip_ipaddr_t * uip_ds6_nbr_ipaddr_from_lladdr(const uip_lladdr_t *lladdr)
Get an IPv6 address associated with a specified link-layer address.
Definition: uip-ds6-nbr.c:505
Linked list manipulation routines.
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:82
uip_ds6_nbr_t * uip_ds6_nbr_lookup(const uip_ipaddr_t *ipaddr)
Get the neighbor cache associated with a specified IPv6 address.
Definition: uip-ds6-nbr.c:467
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1015
const uip_lladdr_t * uip_ds6_nbr_lladdr_from_ipaddr(const uip_ipaddr_t *ipaddr)
Get the link-layer address associated with a specified IPv6 address.
Definition: uip-ds6-nbr.c:513
Memory block allocation routines.
#define NBR_INCOMPLETE
Possible states for the nbr cache entries.
Definition: uip-ds6-nbr.h:64
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:142
void list_init(list_t list)
Initialize a list.
Definition: list.c:65
Header file for the uIP TCP/IP stack.
#define LIST(name)
Declare a linked list.
Definition: list.h:89
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition: memb.c:59
#define UIP_DS6_ROUTE_STATE_TYPE
define some additional RPL related route state and neighbor callback for RPL - if not a DS6_ROUTE_STA...
Header file for routing table manipulation.
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition: memb.c:52
static uip_ds6_defrt_t * defrt
Pointer to an interface address.
Definition: uip-nd6.c:111
Header file for the logging system
void list_remove(list_t list, void *item)
Remove a specific element from a list.
Definition: list.c:237
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:322
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:90
int list_length(list_t list)
Get the length of a list.
Definition: list.c:272
The default nbr_table entry (when UIP_DS6_NBR_MULTI_IPV6_ADDRS is disabled), that implements nbr cach...
Definition: uip-ds6-nbr.h:105