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 /*---------------------------------------------------------------------------*/
189 int
190 uip_ds6_route_count_nexthop_neighbors(void)
191 {
192 #if (UIP_MAX_ROUTES != 0)
193  struct uip_ds6_route_neighbor_routes *entry;
194  int count = 0;
195  for(entry = nbr_table_head(nbr_routes); entry != NULL; entry = nbr_table_next(nbr_routes, entry)) {
196  count++;
197  }
198  return count;
199 #else /* (UIP_MAX_ROUTES != 0) */
200  return 0;
201 #endif /* (UIP_MAX_ROUTES != 0) */
202 }
203 #if (UIP_MAX_ROUTES != 0)
204 /*---------------------------------------------------------------------------*/
205 static uip_lladdr_t *
206 uip_ds6_route_nexthop_lladdr(uip_ds6_route_t *route)
207 {
208  if(route != NULL) {
209  return (uip_lladdr_t *)nbr_table_get_lladdr(nbr_routes,
210  route->neighbor_routes);
211  } else {
212  return NULL;
213  }
214 }
215 #endif /* (UIP_MAX_ROUTES != 0) */
216 /*---------------------------------------------------------------------------*/
217 const uip_ipaddr_t *
218 uip_ds6_route_nexthop(uip_ds6_route_t *route)
219 {
220 #if (UIP_MAX_ROUTES != 0)
221  if(route != NULL) {
222  return uip_ds6_nbr_ipaddr_from_lladdr(uip_ds6_route_nexthop_lladdr(route));
223  } else {
224  return NULL;
225  }
226 #else /* (UIP_MAX_ROUTES != 0) */
227  return NULL;
228 #endif /* (UIP_MAX_ROUTES != 0) */
229 }
230 /*---------------------------------------------------------------------------*/
232 uip_ds6_route_head(void)
233 {
234 #if (UIP_MAX_ROUTES != 0)
235  return list_head(routelist);
236 #else /* (UIP_MAX_ROUTES != 0) */
237  return NULL;
238 #endif /* (UIP_MAX_ROUTES != 0) */
239 }
240 /*---------------------------------------------------------------------------*/
242 uip_ds6_route_next(uip_ds6_route_t *r)
243 {
244 #if (UIP_MAX_ROUTES != 0)
245  if(r != NULL) {
247  return n;
248  }
249 #endif /* (UIP_MAX_ROUTES != 0) */
250  return NULL;
251 }
252 /*---------------------------------------------------------------------------*/
253 int
254 uip_ds6_route_is_nexthop(const uip_ipaddr_t *ipaddr)
255 {
256 #if (UIP_MAX_ROUTES != 0)
257  const uip_lladdr_t *lladdr;
258  lladdr = uip_ds6_nbr_lladdr_from_ipaddr(ipaddr);
259 
260  if(lladdr == NULL) {
261  return 0;
262  }
263 
264  return nbr_table_get_from_lladdr(nbr_routes, (linkaddr_t *)lladdr) != NULL;
265 #else /* (UIP_MAX_ROUTES != 0) */
266  return 0;
267 #endif /* (UIP_MAX_ROUTES != 0) */
268 }
269 /*---------------------------------------------------------------------------*/
270 int
271 uip_ds6_route_num_routes(void)
272 {
273 #if (UIP_MAX_ROUTES != 0)
274  return num_routes;
275 #else /* (UIP_MAX_ROUTES != 0) */
276  return 0;
277 #endif /* (UIP_MAX_ROUTES != 0) */
278 }
279 /*---------------------------------------------------------------------------*/
281 uip_ds6_route_lookup(const uip_ipaddr_t *addr)
282 {
283 #if (UIP_MAX_ROUTES != 0)
284  uip_ds6_route_t *r;
285  uip_ds6_route_t *found_route;
286  uint8_t longestmatch;
287 
288  LOG_INFO("Looking up route for ");
289  LOG_INFO_6ADDR(addr);
290  LOG_INFO_("\n");
291 
292  if(addr == NULL) {
293  return NULL;
294  }
295 
296  found_route = NULL;
297  longestmatch = 0;
298  for(r = uip_ds6_route_head();
299  r != NULL;
300  r = uip_ds6_route_next(r)) {
301  if(r->length >= longestmatch &&
302  uip_ipaddr_prefixcmp(addr, &r->ipaddr, r->length)) {
303  longestmatch = r->length;
304  found_route = r;
305  /* check if total match - e.g. all 128 bits do match */
306  if(longestmatch == 128) {
307  break;
308  }
309  }
310  }
311 
312  if(found_route != NULL) {
313  LOG_INFO("Found route: ");
314  LOG_INFO_6ADDR(addr);
315  LOG_INFO_(" via ");
316  LOG_INFO_6ADDR(uip_ds6_route_nexthop(found_route));
317  LOG_INFO_("\n");
318  } else {
319  LOG_WARN("No route found\n");
320  }
321 
322  if(found_route != NULL && found_route != list_head(routelist)) {
323  /* If we found a route, we put it at the start of the routeslist
324  list. The list is ordered by how recently we looked them up:
325  the least recently used route will be at the end of the
326  list - for fast lookups (assuming multiple packets to the same node). */
327 
328  list_remove(routelist, found_route);
329  list_push(routelist, found_route);
330  }
331 
332  return found_route;
333 #else /* (UIP_MAX_ROUTES != 0) */
334  return NULL;
335 #endif /* (UIP_MAX_ROUTES != 0) */
336 }
337 /*---------------------------------------------------------------------------*/
339 uip_ds6_route_add(const uip_ipaddr_t *ipaddr, uint8_t length,
340  const uip_ipaddr_t *nexthop)
341 {
342 #if (UIP_MAX_ROUTES != 0)
343  uip_ds6_route_t *r;
344  struct uip_ds6_route_neighbor_route *nbrr;
345 
346  if(LOG_DBG_ENABLED) {
347  assert_nbr_routes_list_sane();
348  }
349 
350  if(ipaddr == NULL || nexthop == NULL) {
351  return NULL;
352  }
353 
354  /* Get link-layer address of next hop, make sure it is in neighbor table */
355  const uip_lladdr_t *nexthop_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(nexthop);
356  if(nexthop_lladdr == NULL) {
357  LOG_WARN("Add: neighbor link-local address unknown for ");
358  LOG_WARN_6ADDR(nexthop);
359  LOG_WARN_("\n");
360  return NULL;
361  }
362 
363  /* First make sure that we don't add a route twice. If we find an
364  existing route for our destination, we'll delete the old
365  one first. */
366  r = uip_ds6_route_lookup(ipaddr);
367  if(r != NULL) {
368  const uip_ipaddr_t *current_nexthop;
369  current_nexthop = uip_ds6_route_nexthop(r);
370  if(current_nexthop != NULL && uip_ipaddr_cmp(nexthop, current_nexthop)) {
371  /* no need to update route - already correct! */
372  return r;
373  }
374  LOG_INFO("Add: old route for ");
375  LOG_INFO_6ADDR(ipaddr);
376  LOG_INFO_(" found, deleting it\n");
377 
378  uip_ds6_route_rm(r);
379  }
380  {
381  struct uip_ds6_route_neighbor_routes *routes;
382  /* If there is no routing entry, create one. We first need to
383  check if we have room for this route. If not, we remove the
384  least recently used one we have. */
385 
386  if(uip_ds6_route_num_routes() == UIP_DS6_ROUTE_NB) {
387  uip_ds6_route_t *oldest;
388  oldest = NULL;
389 #if UIP_DS6_ROUTE_REMOVE_LEAST_RECENTLY_USED
390  /* Removing the oldest route entry from the route table. The
391  least recently used route is the first route on the list. */
392  oldest = list_tail(routelist);
393 #endif
394  if(oldest == NULL) {
395  return NULL;
396  }
397  LOG_INFO("Add: dropping route to ");
398  LOG_INFO_6ADDR(&oldest->ipaddr);
399  LOG_INFO_("\n");
400  uip_ds6_route_rm(oldest);
401  }
402 
403 
404  /* Every neighbor on our neighbor table holds a struct
405  uip_ds6_route_neighbor_routes which holds a list of routes that
406  go through the neighbor. We add our route entry to this list.
407 
408  We first check to see if we already have this neighbor in our
409  nbr_route table. If so, the neighbor already has a route entry
410  list.
411  */
412  routes = nbr_table_get_from_lladdr(nbr_routes,
413  (linkaddr_t *)nexthop_lladdr);
414 
415  if(routes == NULL) {
416  /* If the neighbor did not have an entry in our neighbor table,
417  we create one. The nbr_table_add_lladdr() function returns a
418  pointer to a pointer that we may use for our own purposes. We
419  initialize this pointer with the list of routing entries that
420  are attached to this neighbor. */
421  routes = nbr_table_add_lladdr(nbr_routes,
422  (linkaddr_t *)nexthop_lladdr,
423  NBR_TABLE_REASON_ROUTE, NULL);
424  if(routes == NULL) {
425  /* This should not happen, as we explicitly deallocated one
426  route table entry above. */
427  LOG_ERR("Add: could not allocate neighbor table entry\n");
428  return NULL;
429  }
430  LIST_STRUCT_INIT(routes, route_list);
431 #ifdef NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK
432  NETSTACK_CONF_ROUTING_NEIGHBOR_ADDED_CALLBACK((const linkaddr_t *)nexthop_lladdr);
433 #endif
434  }
435 
436  /* Allocate a routing entry and populate it. */
437  r = memb_alloc(&routememb);
438 
439  if(r == NULL) {
440  /* This should not happen, as we explicitly deallocated one
441  route table entry above. */
442  LOG_ERR("Add: could not allocate route\n");
443  return NULL;
444  }
445 
446  /* add new routes first - assuming that there is a reason to add this
447  and that there is a packet coming soon. */
448  list_push(routelist, r);
449 
450  nbrr = memb_alloc(&neighborroutememb);
451  if(nbrr == NULL) {
452  /* This should not happen, as we explicitly deallocated one
453  route table entry above. */
454  LOG_ERR("Add: could not allocate neighbor route list entry\n");
455  memb_free(&routememb, r);
456  return NULL;
457  }
458 
459  nbrr->route = r;
460  /* Add the route to this neighbor */
461  list_add(routes->route_list, nbrr);
462  r->neighbor_routes = routes;
463  num_routes++;
464 
465  LOG_INFO("Add: num %d\n", num_routes);
466 
467  /* lock this entry so that nexthop is not removed */
468  nbr_table_lock(nbr_routes, routes);
469  }
470 
471  uip_ipaddr_copy(&(r->ipaddr), ipaddr);
472  r->length = length;
473 
474 #ifdef UIP_DS6_ROUTE_STATE_TYPE
475  memset(&r->state, 0, sizeof(UIP_DS6_ROUTE_STATE_TYPE));
476 #endif
477 
478  LOG_INFO("Add: adding route: ");
479  LOG_INFO_6ADDR(ipaddr);
480  LOG_INFO_(" via ");
481  LOG_INFO_6ADDR(nexthop);
482  LOG_INFO_("\n");
483  LOG_ANNOTATE("#L %u 1;blue\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
484 
485 #if UIP_DS6_NOTIFICATIONS
486  call_route_callback(UIP_DS6_NOTIFICATION_ROUTE_ADD, ipaddr, nexthop);
487 #endif
488 
489  if(LOG_DBG_ENABLED) {
490  assert_nbr_routes_list_sane();
491  }
492  return r;
493 
494 #else /* (UIP_MAX_ROUTES != 0) */
495  return NULL;
496 #endif /* (UIP_MAX_ROUTES != 0) */
497 }
498 
499 /*---------------------------------------------------------------------------*/
500 void
501 uip_ds6_route_rm(uip_ds6_route_t *route)
502 {
503 #if (UIP_MAX_ROUTES != 0)
504  struct uip_ds6_route_neighbor_route *neighbor_route;
505 
506  if(LOG_DBG_ENABLED) {
507  assert_nbr_routes_list_sane();
508  }
509 
510  if(route != NULL && route->neighbor_routes != NULL) {
511 
512  LOG_INFO("Rm: removing route: ");
513  LOG_INFO_6ADDR(&route->ipaddr);
514  LOG_INFO_("\n");
515 
516  /* Remove the route from the route list */
517  list_remove(routelist, route);
518 
519  /* Find the corresponding neighbor_route and remove it. */
520  for(neighbor_route = list_head(route->neighbor_routes->route_list);
521  neighbor_route != NULL && neighbor_route->route != route;
522  neighbor_route = list_item_next(neighbor_route));
523 
524  if(neighbor_route == NULL) {
525  LOG_INFO("Rm: neighbor_route was NULL for ");
526  LOG_INFO_6ADDR(&route->ipaddr);
527  LOG_INFO_("\n");
528  }
529  list_remove(route->neighbor_routes->route_list, neighbor_route);
530  if(list_head(route->neighbor_routes->route_list) == NULL) {
531  /* If this was the only route using this neighbor, remove the
532  neighbor from the table - this implicitly unlocks nexthop */
533 #if LOG_WITH_ANNOTATE
534  const uip_ipaddr_t *nexthop = uip_ds6_route_nexthop(route);
535  if(nexthop != NULL) {
536  LOG_ANNOTATE("#L %u 0\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]);
537  }
538 #endif /* LOG_WITH_ANNOTATE */
539  LOG_INFO("Rm: removing neighbor too\n");
540  nbr_table_remove(nbr_routes, route->neighbor_routes->route_list);
541 #ifdef NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK
542  NETSTACK_CONF_ROUTING_NEIGHBOR_REMOVED_CALLBACK(
543  (const linkaddr_t *)nbr_table_get_lladdr(nbr_routes, route->neighbor_routes->route_list));
544 #endif
545  }
546  memb_free(&routememb, route);
547  memb_free(&neighborroutememb, neighbor_route);
548 
549  num_routes--;
550 
551  LOG_INFO("Rm: num %d\n", num_routes);
552 
553 #if UIP_DS6_NOTIFICATIONS
554  call_route_callback(UIP_DS6_NOTIFICATION_ROUTE_RM,
555  &route->ipaddr, uip_ds6_route_nexthop(route));
556 #endif
557  }
558 
559  if(LOG_DBG_ENABLED) {
560  assert_nbr_routes_list_sane();
561  }
562 
563 #endif /* (UIP_MAX_ROUTES != 0) */
564  return;
565 }
566 #if (UIP_MAX_ROUTES != 0)
567 /*---------------------------------------------------------------------------*/
568 static void
569 rm_routelist(struct uip_ds6_route_neighbor_routes *routes)
570 {
571  if(LOG_DBG_ENABLED) {
572  assert_nbr_routes_list_sane();
573  }
574 
575  if(routes != NULL && routes->route_list != NULL) {
577  r = list_head(routes->route_list);
578  while(r != NULL) {
579  uip_ds6_route_rm(r->route);
580  r = list_head(routes->route_list);
581  }
582  nbr_table_remove(nbr_routes, routes);
583  }
584 
585  if(LOG_DBG_ENABLED) {
586  assert_nbr_routes_list_sane();
587  }
588 }
589 /*---------------------------------------------------------------------------*/
590 static void
591 rm_routelist_callback(nbr_table_item_t *ptr)
592 {
593  rm_routelist((struct uip_ds6_route_neighbor_routes *)ptr);
594 }
595 #endif /* (UIP_MAX_ROUTES != 0) */
596 /*---------------------------------------------------------------------------*/
597 void
598 uip_ds6_route_rm_by_nexthop(const uip_ipaddr_t *nexthop)
599 {
600 #if (UIP_MAX_ROUTES != 0)
601  /* Get routing entry list of this neighbor */
602  const uip_lladdr_t *nexthop_lladdr;
603  struct uip_ds6_route_neighbor_routes *routes;
604 
605  nexthop_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(nexthop);
606  routes = nbr_table_get_from_lladdr(nbr_routes,
607  (linkaddr_t *)nexthop_lladdr);
608  rm_routelist(routes);
609 #endif /* (UIP_MAX_ROUTES != 0) */
610 }
611 /*---------------------------------------------------------------------------*/
613 uip_ds6_defrt_head(void)
614 {
615  return list_head(defaultrouterlist);
616 }
617 /*---------------------------------------------------------------------------*/
619 uip_ds6_defrt_add(const uip_ipaddr_t *ipaddr, unsigned long interval)
620 {
621  uip_ds6_defrt_t *d;
622 
623  if(LOG_DBG_ENABLED) {
624  assert_nbr_routes_list_sane();
625  }
626 
627  if(ipaddr == NULL) {
628  return NULL;
629  }
630 
631  d = uip_ds6_defrt_lookup(ipaddr);
632  if(d == NULL) {
633  d = memb_alloc(&defaultroutermemb);
634  if(d == NULL) {
635  LOG_ERR("Add default: could not add default route to ");
636  LOG_ERR_6ADDR(ipaddr);
637  LOG_ERR_(", out of memory\n");
638  return NULL;
639  } else {
640  LOG_INFO("Add default: adding default route to ");
641  LOG_INFO_6ADDR(ipaddr);
642  LOG_INFO_("\n");
643  }
644 
645  list_push(defaultrouterlist, d);
646  }
647  else {
648  LOG_INFO("Refreshing default\n");
649  }
650 
651  uip_ipaddr_copy(&d->ipaddr, ipaddr);
652  if(interval != 0) {
653  stimer_set(&d->lifetime, interval);
654  d->isinfinite = 0;
655  } else {
656  d->isinfinite = 1;
657  }
658 
659  LOG_ANNOTATE("#L %u 1\n", ipaddr->u8[sizeof(uip_ipaddr_t) - 1]);
660 
661 #if UIP_DS6_NOTIFICATIONS
662  call_route_callback(UIP_DS6_NOTIFICATION_DEFRT_ADD, ipaddr, ipaddr);
663 #endif
664 
665 if(LOG_DBG_ENABLED) {
666  assert_nbr_routes_list_sane();
667 }
668 
669  return d;
670 }
671 /*---------------------------------------------------------------------------*/
672 void
673 uip_ds6_defrt_rm(uip_ds6_defrt_t *defrt)
674 {
675  uip_ds6_defrt_t *d;
676 
677  if(LOG_DBG_ENABLED) {
678  assert_nbr_routes_list_sane();
679  }
680 
681  /* Make sure that the defrt is in the list before we remove it. */
682  for(d = list_head(defaultrouterlist);
683  d != NULL;
684  d = list_item_next(d)) {
685  if(d == defrt) {
686  LOG_INFO("Removing default\n");
687  list_remove(defaultrouterlist, defrt);
688  memb_free(&defaultroutermemb, defrt);
689  LOG_ANNOTATE("#L %u 0\n", defrt->ipaddr.u8[sizeof(uip_ipaddr_t) - 1]);
690 #if UIP_DS6_NOTIFICATIONS
691  call_route_callback(UIP_DS6_NOTIFICATION_DEFRT_RM,
692  &defrt->ipaddr, &defrt->ipaddr);
693 #endif
694  return;
695  }
696  }
697 
698  if(LOG_DBG_ENABLED) {
699  assert_nbr_routes_list_sane();
700  }
701 }
702 /*---------------------------------------------------------------------------*/
704 uip_ds6_defrt_lookup(const uip_ipaddr_t *ipaddr)
705 {
706  uip_ds6_defrt_t *d;
707  if(ipaddr == NULL) {
708  return NULL;
709  }
710  for(d = list_head(defaultrouterlist);
711  d != NULL;
712  d = list_item_next(d)) {
713  if(uip_ipaddr_cmp(&d->ipaddr, ipaddr)) {
714  return d;
715  }
716  }
717  return NULL;
718 }
719 /*---------------------------------------------------------------------------*/
720 const uip_ipaddr_t *
721 uip_ds6_defrt_choose(void)
722 {
723  uip_ds6_defrt_t *d;
724  uip_ds6_nbr_t *bestnbr;
725  uip_ipaddr_t *addr;
726 
727  addr = NULL;
728  for(d = list_head(defaultrouterlist);
729  d != NULL;
730  d = list_item_next(d)) {
731  LOG_INFO("Default route, IP address ");
732  LOG_INFO_6ADDR(&d->ipaddr);
733  LOG_INFO_("\n");
734  bestnbr = uip_ds6_nbr_lookup(&d->ipaddr);
735  if(bestnbr != NULL && bestnbr->state != NBR_INCOMPLETE) {
736  LOG_INFO("Default route found, IP address ");
737  LOG_INFO_6ADDR(&d->ipaddr);
738  LOG_INFO_("\n");
739  return &d->ipaddr;
740  } else {
741  addr = &d->ipaddr;
742  LOG_INFO("Default route Incomplete found, IP address ");
743  LOG_INFO_6ADDR(&d->ipaddr);
744  LOG_INFO_("\n");
745  }
746  }
747  return addr;
748 }
749 /*---------------------------------------------------------------------------*/
750 void
751 uip_ds6_defrt_periodic(void)
752 {
753  uip_ds6_defrt_t *d;
754  d = list_head(defaultrouterlist);
755  while(d != NULL) {
756  if(!d->isinfinite &&
757  stimer_expired(&d->lifetime)) {
758  LOG_INFO("Default route periodic: defrt lifetime expired\n");
759  uip_ds6_defrt_rm(d);
760  d = list_head(defaultrouterlist);
761  } else {
762  d = list_item_next(d);
763  }
764  }
765 }
766 /*---------------------------------------------------------------------------*/
767 /** @} */
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.
static volatile uint64_t count
Num.
Definition: clock.c:50
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