Remove gateway if HNA 0/0 or originators TC is removed
[olsrd.git] / src / tc_set.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
5  * LSDB rewrite (c) 2007, Hannes Gredler (hannes@gredler.at)
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  *   notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above copyright
15  *   notice, this list of conditions and the following disclaimer in
16  *   the documentation and/or other materials provided with the
17  *   distribution.
18  * * Neither the name of olsr.org, olsrd nor the names of its
19  *   contributors may be used to endorse or promote products derived
20  *   from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * Visit http://www.olsr.org for more information.
36  *
37  * If you find this software useful feel free to make a donation
38  * to the project. For more information see the website or contact
39  * the copyright holders.
40  *
41  */
42
43 #include "tc_set.h"
44 #include "ipcalc.h"
45 #include "mid_set.h"
46 #include "link_set.h"
47 #include "olsr.h"
48 #include "scheduler.h"
49 #include "olsr_spf.h"
50 #include "common/avl.h"
51 #include "lq_packet.h"
52 #include "net_olsr.h"
53 #include "lq_plugin.h"
54 #include "olsr_cookie.h"
55 #include "duplicate_set.h"
56 #include "gateway.h"
57
58 #include <assert.h>
59
60 /* Root of the link state database */
61 struct avl_tree tc_tree;
62 struct tc_entry *tc_myself;            /* Shortcut to ourselves */
63
64 /* Some cookies for stats keeping */
65 struct olsr_cookie_info *tc_edge_gc_timer_cookie = NULL;
66 struct olsr_cookie_info *tc_validity_timer_cookie = NULL;
67 struct olsr_cookie_info *tc_edge_mem_cookie = NULL;
68 struct olsr_cookie_info *tc_mem_cookie = NULL;
69
70 /*
71  * Sven-Ola 2007-Dec: These four constants include an assumption
72  * on how long a typical olsrd mesh memorizes (TC) messages in the
73  * RAM of all nodes and how many neighbour changes between TC msgs.
74  * In Berlin, we encounter hop values up to 70 which means that
75  * messages may live up to ~15 minutes cycling between nodes and
76  * obviously breaking out of the timeout_dup() jail. It may be more
77  * correct to dynamically adapt those constants, e.g. by using the
78  * max hop number (denotes size-of-mesh) in some form or maybe
79  * a factor indicating how many (old) versions of olsrd are on.
80  */
81
82 /* Value window for ansn, identifies old messages to be ignored */
83 #define TC_ANSN_WINDOW 256
84
85 /* Value window for seqno, identifies old messages to be ignored */
86 #define TC_SEQNO_WINDOW 1024
87
88 /* Enlarges the value window for upcoming ansn/seqno to be accepted */
89 #define TC_ANSN_WINDOW_MULT 4
90
91 /* Enlarges the value window for upcoming ansn/seqno to be accepted */
92 #define TC_SEQNO_WINDOW_MULT 8
93
94 static bool
95 olsr_seq_inrange_low(int beg, int end, uint16_t seq)
96 {
97   if (beg < 0) {
98     if (seq >= (uint16_t) beg || seq < end) {
99       return true;
100     }
101   } else if (end >= 0x10000) {
102     if (seq >= beg || seq < (uint16_t) end) {
103       return true;
104     }
105   } else if (seq >= beg && seq < end) {
106     return true;
107   }
108   return false;
109 }
110
111 static bool
112 olsr_seq_inrange_high(int beg, int end, uint16_t seq)
113 {
114   if (beg < 0) {
115     if (seq > (uint16_t) beg || seq <= end) {
116       return true;
117     }
118   } else if (end >= 0x10000) {
119     if (seq > beg || seq <= (uint16_t) end) {
120       return true;
121     }
122   } else if (seq > beg && seq <= end) {
123     return true;
124   }
125   return false;
126 }
127
128 /**
129  * Add a new tc_entry to the tc tree
130  *
131  * @param (last)adr address of the entry
132  * @return a pointer to the created entry
133  */
134 static struct tc_entry *
135 olsr_add_tc_entry(union olsr_ip_addr *adr)
136 {
137 #ifdef DEBUG
138   struct ipaddr_str buf;
139 #endif
140   struct tc_entry *tc;
141
142   /*
143    * Safety net against loss of the last main IP address.
144    */
145   if (ipequal(&olsr_cnf->main_addr, &all_zero)) {
146     return NULL;
147   }
148 #ifdef DEBUG
149   OLSR_PRINTF(1, "TC: add entry %s\n", olsr_ip_to_string(&buf, adr));
150 #endif
151
152   tc = olsr_cookie_malloc(tc_mem_cookie);
153   if (!tc) {
154     return NULL;
155   }
156
157   /* Fill entry */
158   tc->addr = *adr;
159   tc->vertex_node.key = &tc->addr;
160
161   /*
162    * Insert into the global tc tree.
163    */
164   avl_insert(&tc_tree, &tc->vertex_node, AVL_DUP_NO);
165   olsr_lock_tc_entry(tc);
166
167   /*
168    * Initialize subtrees for edges and prefixes.
169    */
170   avl_init(&tc->edge_tree, avl_comp_default);
171   avl_init(&tc->prefix_tree, avl_comp_prefix_default);
172
173   /*
174    * Add a rt_path for ourselves.
175    */
176   olsr_insert_routing_table(adr, olsr_cnf->maxplen, adr, OLSR_RT_ORIGIN_INT);
177
178   return tc;
179 }
180
181 /**
182  * Initialize the topology set
183  *
184  */
185 void
186 olsr_init_tc(void)
187 {
188   OLSR_PRINTF(5, "TC: init topo\n");
189
190   avl_init(&tc_tree, avl_comp_default);
191
192   /*
193    * Get some cookies for getting stats to ease troubleshooting.
194    */
195   tc_edge_gc_timer_cookie = olsr_alloc_cookie("TC edge GC", OLSR_COOKIE_TYPE_TIMER);
196   tc_validity_timer_cookie = olsr_alloc_cookie("TC validity", OLSR_COOKIE_TYPE_TIMER);
197
198   tc_edge_mem_cookie = olsr_alloc_cookie("tc_edge_entry", OLSR_COOKIE_TYPE_MEMORY);
199   olsr_cookie_set_memory_size(tc_edge_mem_cookie, sizeof(struct tc_edge_entry) + active_lq_handler->tc_lq_size);
200
201   tc_mem_cookie = olsr_alloc_cookie("tc_entry", OLSR_COOKIE_TYPE_MEMORY);
202   olsr_cookie_set_memory_size(tc_mem_cookie, sizeof(struct tc_entry));
203
204   /*
205    * Add a TC entry for ourselves.
206    */
207   tc_myself = olsr_add_tc_entry(&olsr_cnf->main_addr);
208 }
209
210 void olsr_delete_all_tc_entries(void) {
211   struct tc_entry *tc;
212
213   OLSR_FOR_ALL_TC_ENTRIES(tc) {
214     olsr_delete_tc_entry(tc);
215   } OLSR_FOR_ALL_TC_ENTRIES_END(tc)
216 }
217
218 /**
219  * The main ip address has changed.
220  * Do the needful.
221  */
222 void
223 olsr_change_myself_tc(void)
224 {
225   if (tc_myself) {
226
227     /*
228      * Check if there was a change.
229      */
230     if (ipequal(&tc_myself->addr, &olsr_cnf->main_addr)) {
231       return;
232     }
233
234     /*
235      * Flush our own tc_entry.
236      */
237     olsr_delete_tc_entry(tc_myself);
238   }
239
240   /*
241    * The old entry for ourselves is gone, generate a new one and trigger SPF.
242    */
243   tc_myself = olsr_add_tc_entry(&olsr_cnf->main_addr);
244   changes_topology = true;
245 }
246
247 /*
248  * Increment the reference counter.
249  */
250 void
251 olsr_lock_tc_entry(struct tc_entry *tc)
252 {
253   tc->refcount++;
254 }
255
256 /*
257  * Unlock and free a tc_entry once all references are gone.
258  */
259 void
260 olsr_unlock_tc_entry(struct tc_entry *tc)
261 {
262   if (--tc->refcount) {
263     return;
264   }
265
266   /*
267    * All references are gone.
268    */
269   olsr_cookie_free(tc_mem_cookie, tc);
270 }
271
272 /**
273  * Delete a TC entry.
274  *
275  * @param entry the TC entry to delete
276  *
277  */
278 void
279 olsr_delete_tc_entry(struct tc_entry *tc)
280 {
281   struct tc_edge_entry *tc_edge;
282   struct rt_path *rtp;
283 #if 0
284   struct ipaddr_str buf;
285   OLSR_PRINTF(1, "TC: del entry %s\n", olsr_ip_to_string(&buf, &tc->addr));
286 #endif
287
288   /* delete gateway if available */
289   olsr_delete_gateway(&tc->addr);
290
291   /*
292    * Delete the rt_path for ourselves.
293    */
294   olsr_delete_routing_table(&tc->addr, olsr_cnf->maxplen, &tc->addr);
295
296   /* The edgetree and prefix tree must be empty before */
297   OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
298     olsr_delete_tc_edge_entry(tc_edge);
299   } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
300
301   OLSR_FOR_ALL_PREFIX_ENTRIES(tc, rtp) {
302     olsr_delete_rt_path(rtp);
303   } OLSR_FOR_ALL_PREFIX_ENTRIES_END(tc, rtp);
304
305   /* Stop running timers */
306   olsr_stop_timer(tc->edge_gc_timer);
307   tc->edge_gc_timer = NULL;
308   olsr_stop_timer(tc->validity_timer);
309   tc->validity_timer = NULL;
310
311   avl_delete(&tc_tree, &tc->vertex_node);
312   olsr_unlock_tc_entry(tc);
313 }
314
315 /**
316  * Look up a entry from the TC tree based on address
317  *
318  * @param adr the address to look for
319  * @return the entry found or NULL
320  */
321 struct tc_entry *
322 olsr_lookup_tc_entry(union olsr_ip_addr *adr)
323 {
324   struct avl_node *node;
325
326 #if 0
327   OLSR_PRINTF(1, "TC: lookup entry\n");
328 #endif
329
330   node = avl_find(&tc_tree, adr);
331
332   return (node ? vertex_tree2tc(node) : NULL);
333 }
334
335 /*
336  * Lookup a tc entry. Creates one if it does not exist yet.
337  */
338 struct tc_entry *
339 olsr_locate_tc_entry(union olsr_ip_addr *adr)
340 {
341   struct tc_entry *tc;
342
343   if (!(tc = olsr_lookup_tc_entry(adr))) {
344     return olsr_add_tc_entry(adr);
345   }
346   return tc;
347 }
348
349 /**
350  * Format tc_edge contents into a buffer.
351  */
352 char *
353 olsr_tc_edge_to_string(struct tc_edge_entry *tc_edge)
354 {
355   static char buf[128];
356   struct ipaddr_str addrbuf, dstbuf;
357   struct tc_entry *tc = tc_edge->tc;
358   struct lqtextbuffer lqbuffer1, lqbuffer2;
359
360   snprintf(buf, sizeof(buf), "%s > %s, cost (%6s) %s", olsr_ip_to_string(&addrbuf, &tc->addr),
361            olsr_ip_to_string(&dstbuf, &tc_edge->T_dest_addr), get_tc_edge_entry_text(tc_edge, '/', &lqbuffer1),
362            get_linkcost_text(tc_edge->cost, false, &lqbuffer2));
363
364   return buf;
365 }
366
367 /**
368  * Wrapper for the timer callback.
369  * A TC entry has not been refreshed in time.
370  * Remove it from the link-state database.
371  */
372 static void
373 olsr_expire_tc_entry(void *context)
374 {
375   struct tc_entry *tc;
376   struct ipaddr_str buf;
377
378   tc = (struct tc_entry *)context;
379
380   OLSR_PRINTF(3, "TC: expire node entry %s\n", olsr_ip_to_string(&buf, &tc->addr));
381
382   tc->validity_timer = NULL;
383
384   olsr_delete_tc_entry(tc);
385   changes_topology = true;
386 }
387
388 /**
389  * Wrapper for the timer callback.
390  * Does the garbage collection of older ansn entries after no edge addition to
391  * the TC entry has happened for OLSR_TC_EDGE_GC_TIME.
392  */
393 static void
394 olsr_expire_tc_edge_gc(void *context)
395 {
396   struct tc_entry *tc;
397   struct ipaddr_str buf;
398
399   tc = (struct tc_entry *)context;
400
401   OLSR_PRINTF(3, "TC: expire edge entry %s\n", olsr_ip_to_string(&buf, &tc->addr));
402
403   tc->edge_gc_timer = NULL;
404
405   if (olsr_delete_outdated_tc_edges(tc)) {
406     changes_topology = true;
407   }
408 }
409
410 /*
411  * If the edge does not have a minimum acceptable link quality
412  * set the etx cost to infinity such that it gets ignored during
413  * SPF calculation.
414  *
415  * @return 1 if the change of the etx value was relevant
416  */
417 bool
418 olsr_calc_tc_edge_entry_etx(struct tc_edge_entry *tc_edge)
419 {
420   olsr_linkcost old;
421
422   /*
423    * Some sanity check before recalculating the etx.
424    */
425   if (olsr_cnf->lq_level < 1) {
426     return false;
427   }
428
429   old = tc_edge->cost;
430   tc_edge->cost = olsr_calc_tc_cost(tc_edge);
431   return true;
432 }
433
434 /**
435  * Add a new tc_edge_entry to the tc_edge_tree
436  *
437  * @param (last)adr address of the entry
438  * @return a pointer to the created entry
439  */
440 struct tc_edge_entry *
441 olsr_add_tc_edge_entry(struct tc_entry *tc, union olsr_ip_addr *addr, uint16_t ansn)
442 {
443 #ifdef DEBUG
444   struct ipaddr_str buf;
445 #endif
446   struct tc_entry *tc_neighbor;
447   struct tc_edge_entry *tc_edge, *tc_edge_inv;
448
449   tc_edge = olsr_cookie_malloc(tc_edge_mem_cookie);
450   if (!tc_edge) {
451     return NULL;
452   }
453
454   /* Fill entry */
455   tc_edge->T_dest_addr = *addr;
456   tc_edge->ansn = ansn;
457   tc_edge->edge_node.key = &tc_edge->T_dest_addr;
458
459   /*
460    * Insert into the edge tree.
461    */
462   avl_insert(&tc->edge_tree, &tc_edge->edge_node, AVL_DUP_NO);
463   olsr_lock_tc_entry(tc);
464
465   /*
466    * Connect backpointer.
467    */
468   tc_edge->tc = tc;
469
470   /*
471    * Check if the neighboring router and the inverse edge is in the lsdb.
472    * Create short cuts to the inverse edge for faster SPF execution.
473    */
474   tc_neighbor = olsr_lookup_tc_entry(&tc_edge->T_dest_addr);
475   if (tc_neighbor) {
476 #ifdef DEBUG
477     OLSR_PRINTF(1, "TC:   found neighbor tc_entry %s\n", olsr_ip_to_string(&buf, &tc_neighbor->addr));
478 #endif
479
480     tc_edge_inv = olsr_lookup_tc_edge(tc_neighbor, &tc->addr);
481     if (tc_edge_inv) {
482 #ifdef DEBUG
483       OLSR_PRINTF(1, "TC:   found inverse edge for %s\n", olsr_ip_to_string(&buf, &tc_edge_inv->T_dest_addr));
484 #endif
485
486       /*
487        * Connect the edges mutually.
488        */
489       tc_edge_inv->edge_inv = tc_edge;
490       tc_edge->edge_inv = tc_edge_inv;
491
492     }
493   }
494
495   /*
496    * Update the etx.
497    */
498   olsr_calc_tc_edge_entry_etx(tc_edge);
499
500 #ifdef DEBUG
501   OLSR_PRINTF(1, "TC: add edge entry %s\n", olsr_tc_edge_to_string(tc_edge));
502 #endif
503
504   return tc_edge;
505 }
506
507 /**
508  * Delete a TC edge entry.
509  *
510  * @param tc the TC entry
511  * @param tc_edge the TC edge entry
512  */
513 void
514 olsr_delete_tc_edge_entry(struct tc_edge_entry *tc_edge)
515 {
516   struct tc_entry *tc;
517   struct tc_edge_entry *tc_edge_inv;
518
519 #ifdef DEBUG
520   OLSR_PRINTF(1, "TC: del edge entry %s\n", olsr_tc_edge_to_string(tc_edge));
521 #endif
522
523   tc = tc_edge->tc;
524   avl_delete(&tc->edge_tree, &tc_edge->edge_node);
525   olsr_unlock_tc_entry(tc);
526
527   /*
528    * Clear the backpointer of our inverse edge.
529    */
530   tc_edge_inv = tc_edge->edge_inv;
531   if (tc_edge_inv) {
532     tc_edge_inv->edge_inv = NULL;
533   }
534
535   olsr_cookie_free(tc_edge_mem_cookie, tc_edge);
536 }
537
538 /**
539  * Delete all destinations that have a lower ANSN.
540  *
541  * @param tc the entry to delete edges from
542  * @return TRUE if any destinations were deleted, FALSE if not
543  */
544 bool
545 olsr_delete_outdated_tc_edges(struct tc_entry *tc)
546 {
547   struct tc_edge_entry *tc_edge;
548   bool retval = false;
549
550 #if 0
551   OLSR_PRINTF(5, "TC: deleting outdated TC-edge entries\n");
552 #endif
553
554   OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
555     if (SEQNO_GREATER_THAN(tc->ansn, tc_edge->ansn)) {
556       olsr_delete_tc_edge_entry(tc_edge);
557       retval = true;
558     }
559   }
560   OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
561
562   return retval;
563 }
564
565 /**
566  * Delete all destinations that are inside the borders but
567  * not updated in the last tc.
568  *
569  * @param tc the entry to delete edges from
570  * @param ansn the advertised neighbor set sequence number
571  * @return 1 if any destinations were deleted 0 if not
572  */
573 static int
574 olsr_delete_revoked_tc_edges(struct tc_entry *tc, uint16_t ansn, union olsr_ip_addr *lower_border, union olsr_ip_addr *upper_border)
575 {
576   struct tc_edge_entry *tc_edge;
577   int retval = 0;
578
579 #if 0
580   OLSR_PRINTF(5, "TC: deleting MPRS\n");
581 #endif
582
583   bool passedLowerBorder = false;
584
585   OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
586     if (!passedLowerBorder) {
587       if (avl_comp_default(lower_border, &tc_edge->T_dest_addr) <= 0) {
588         passedLowerBorder = true;
589       } else {
590         continue;
591       }
592     }
593
594     if (passedLowerBorder) {
595       if (avl_comp_default(upper_border, &tc_edge->T_dest_addr) <= 0) {
596         break;
597       }
598     }
599
600     if (SEQNO_GREATER_THAN(ansn, tc_edge->ansn)) {
601       olsr_delete_tc_edge_entry(tc_edge);
602       retval = 1;
603     }
604   }
605   OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
606
607   if (retval)
608     changes_topology = true;
609   return retval;
610 }
611
612 /**
613  * Update an edge registered on an entry.
614  * Creates new edge-entries if not registered.
615  * Bases update on a received TC message
616  *
617  * @param entry the TC entry to check
618  * @pkt the TC edge entry in the packet
619  * @return 1 if entries are added 0 if not
620  */
621 static int
622 olsr_tc_update_edge(struct tc_entry *tc, uint16_t ansn, const unsigned char **curr, union olsr_ip_addr *neighbor)
623 {
624   struct tc_edge_entry *tc_edge;
625   int edge_change;
626
627   edge_change = 0;
628
629   /*
630    * Fetch the per-edge data
631    */
632   pkt_get_ipaddress(curr, neighbor);
633
634   /* First check if we know this edge */
635   tc_edge = olsr_lookup_tc_edge(tc, neighbor);
636
637   if (!tc_edge) {
638
639     /*
640      * Yet unknown - create it.
641      * Check if the address is allowed.
642      */
643     if (!olsr_validate_address(neighbor)) {
644       return 0;
645     }
646
647     tc_edge = olsr_add_tc_edge_entry(tc, neighbor, ansn);
648
649     olsr_deserialize_tc_lq_pair(curr, tc_edge);
650     edge_change = 1;
651
652   } else {
653
654     /*
655      * We know this edge - Update entry.
656      */
657     tc_edge->ansn = ansn;
658
659     /*
660      * Update link quality if configured.
661      */
662     if (olsr_cnf->lq_level > 0) {
663       olsr_deserialize_tc_lq_pair(curr, tc_edge);
664     }
665
666     /*
667      * Update the etx.
668      */
669     if (olsr_calc_tc_edge_entry_etx(tc_edge)) {
670       if (tc->msg_hops <= olsr_cnf->lq_dlimit) {
671         edge_change = 1;
672       }
673     }
674 #if DEBUG
675     if (edge_change) {
676       OLSR_PRINTF(1, "TC:   chg edge entry %s\n", olsr_tc_edge_to_string(tc_edge));
677     }
678 #endif
679
680   }
681
682   return edge_change;
683 }
684
685 /**
686  * Lookup an edge hanging off a TC entry.
687  *
688  * @param entry the entry to check
689  * @param dst_addr the destination address to check for
690  * @return a pointer to the tc_edge found - or NULL
691  */
692 struct tc_edge_entry *
693 olsr_lookup_tc_edge(struct tc_entry *tc, union olsr_ip_addr *edge_addr)
694 {
695   struct avl_node *edge_node;
696
697 #if 0
698   OLSR_PRINTF(1, "TC: lookup dst\n");
699 #endif
700
701   edge_node = avl_find(&tc->edge_tree, edge_addr);
702
703   return (edge_node ? edge_tree2tc_edge(edge_node) : NULL);
704 }
705
706 /**
707  * Print the topology table to stdout
708  */
709 void
710 olsr_print_tc_table(void)
711 {
712 #ifndef NODEBUG
713   /* The whole function makes no sense without it. */
714   struct tc_entry *tc;
715   const int ipwidth = olsr_cnf->ip_version == AF_INET ? 15 : 30;
716
717   OLSR_PRINTF(1, "\n--- %s ------------------------------------------------- TOPOLOGY\n\n" "%-*s %-*s %-14s  %s\n",
718               olsr_wallclock_string(), ipwidth, "Source IP addr", ipwidth, "Dest IP addr", "      LQ      ", "ETX");
719
720   OLSR_FOR_ALL_TC_ENTRIES(tc) {
721     struct tc_edge_entry *tc_edge;
722     OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
723       struct ipaddr_str addrbuf, dstaddrbuf;
724       struct lqtextbuffer lqbuffer1, lqbuffer2;
725
726       OLSR_PRINTF(1, "%-*s %-*s %-14s %s\n", ipwidth, olsr_ip_to_string(&addrbuf, &tc->addr), ipwidth,
727                   olsr_ip_to_string(&dstaddrbuf, &tc_edge->T_dest_addr), get_tc_edge_entry_text(tc_edge, '/', &lqbuffer1),
728                   get_linkcost_text(tc_edge->cost, false, &lqbuffer2));
729
730     } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
731   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
732 #endif
733 }
734
735 /*
736  * calculate the border IPs of a tc edge set according to the border flags
737  *
738  * @param lower border flag
739  * @param pointer to lower border ip
740  * @param upper border flag
741  * @param pointer to upper border ip
742  * @result 1 if lower/upper border ip have been set
743  */
744 static int
745 olsr_calculate_tc_border(uint8_t lower_border, union olsr_ip_addr *lower_border_ip, uint8_t upper_border,
746                          union olsr_ip_addr *upper_border_ip)
747 {
748   if (lower_border == 0 && upper_border == 0) {
749     return 0;
750   }
751   if (lower_border == 0xff) {
752     memset(lower_border_ip, 0, sizeof(lower_border_ip));
753   } else {
754     int i;
755
756     lower_border--;
757     for (i = 0; i < lower_border / 8; i++) {
758       lower_border_ip->v6.s6_addr[olsr_cnf->ipsize - i - 1] = 0;
759     }
760     lower_border_ip->v6.s6_addr[olsr_cnf->ipsize - lower_border / 8 - 1] &= (0xff << (lower_border & 7));
761     lower_border_ip->v6.s6_addr[olsr_cnf->ipsize - lower_border / 8 - 1] |= (1 << (lower_border & 7));
762   }
763
764   if (upper_border == 0xff) {
765     memset(upper_border_ip, 0xff, sizeof(upper_border_ip));
766   } else {
767     int i;
768
769     upper_border--;
770
771     for (i = 0; i < upper_border / 8; i++) {
772       upper_border_ip->v6.s6_addr[olsr_cnf->ipsize - i - 1] = 0;
773     }
774     upper_border_ip->v6.s6_addr[olsr_cnf->ipsize - upper_border / 8 - 1] &= (0xff << (upper_border & 7));
775     upper_border_ip->v6.s6_addr[olsr_cnf->ipsize - upper_border / 8 - 1] |= (1 << (upper_border & 7));
776   }
777   return 1;
778 }
779
780 /*
781  * Process an incoming TC or TC_LQ message.
782  *
783  * If the message is interesting enough, update our edges for it,
784  * trigger SPF and finally flood it to all our 2way neighbors.
785  *
786  * The order for extracting data off the message does matter,
787  * as every call to pkt_get increases the packet offset and
788  * hence the spot we are looking at.
789  */
790 bool
791 olsr_input_tc(union olsr_message * msg, struct interface * input_if __attribute__ ((unused)), union olsr_ip_addr * from_addr)
792 {
793   struct ipaddr_str buf;
794   uint16_t size, msg_seq, ansn;
795   uint8_t type, ttl, msg_hops, lower_border, upper_border;
796   olsr_reltime vtime;
797   union olsr_ip_addr originator;
798   const unsigned char *limit, *curr;
799   struct tc_entry *tc;
800   bool emptyTC;
801
802   union olsr_ip_addr lower_border_ip, upper_border_ip;
803   int borderSet = 0;
804
805   curr = (void *)msg;
806   if (!msg) {
807     return false;
808   }
809
810   /* We are only interested in TC message types. */
811   pkt_get_u8(&curr, &type);
812   if ((type != LQ_TC_MESSAGE) && (type != TC_MESSAGE)) {
813     return false;
814   }
815
816   /*
817    * If the sender interface (NB: not originator) of this message
818    * is not in the symmetric 1-hop neighborhood of this node, the
819    * message MUST be discarded.
820    */
821   if (check_neighbor_link(from_addr) != SYM_LINK) {
822     OLSR_PRINTF(2, "Received TC from NON SYM neighbor %s\n", olsr_ip_to_string(&buf, from_addr));
823     return false;
824   }
825
826   pkt_get_reltime(&curr, &vtime);
827   pkt_get_u16(&curr, &size);
828
829   pkt_get_ipaddress(&curr, &originator);
830
831   /* Copy header values */
832   pkt_get_u8(&curr, &ttl);
833   pkt_get_u8(&curr, &msg_hops);
834   pkt_get_u16(&curr, &msg_seq);
835   pkt_get_u16(&curr, &ansn);
836
837   /* Get borders */
838   pkt_get_u8(&curr, &lower_border);
839   pkt_get_u8(&curr, &upper_border);
840
841   tc = olsr_lookup_tc_entry(&originator);
842
843   if (vtime < (olsr_reltime)(olsr_cnf->min_tc_vtime*1000)) {
844           vtime = (olsr_reltime)(olsr_cnf->min_tc_vtime*1000);
845   }
846
847   if (tc && 0 != tc->edge_tree.count) {
848     if (olsr_seq_inrange_high((int)tc->msg_seq - TC_SEQNO_WINDOW, tc->msg_seq, msg_seq)
849         && olsr_seq_inrange_high((int)tc->ansn - TC_ANSN_WINDOW, tc->ansn, ansn)) {
850
851       /*
852        * Ignore already seen seq/ansn values (small window for mesh memory)
853        */
854       if ((tc->msg_seq == msg_seq) || (tc->ignored++ < 32)) {
855         return false;
856       }
857
858       OLSR_PRINTF(1, "Ignored to much LQTC's for %s, restarting\n", olsr_ip_to_string(&buf, &originator));
859
860     } else if (!olsr_seq_inrange_high(tc->msg_seq, (int)tc->msg_seq + TC_SEQNO_WINDOW * TC_SEQNO_WINDOW_MULT, msg_seq)
861                || !olsr_seq_inrange_low(tc->ansn, (int)tc->ansn + TC_ANSN_WINDOW * TC_ANSN_WINDOW_MULT, ansn)) {
862
863       /*
864        * Only accept future seq/ansn values (large window for node reconnects).
865        * Restart in all other cases. Ignore a single stray message.
866        */
867       if (!tc->err_seq_valid) {
868         tc->err_seq = msg_seq;
869         tc->err_seq_valid = true;
870       }
871       if (tc->err_seq == msg_seq) {
872         return false;
873       }
874
875       OLSR_PRINTF(2, "Detected node restart for %s\n", olsr_ip_to_string(&buf, &originator));
876     }
877   }
878
879   /*
880    * Generate a new tc_entry in the lsdb and store the sequence number.
881    */
882   if (!tc) {
883     tc = olsr_add_tc_entry(&originator);
884   }
885
886   /*
887    * Update the tc entry.
888    */
889   tc->msg_hops = msg_hops;
890   tc->msg_seq = msg_seq;
891   tc->ansn = ansn;
892   tc->ignored = 0;
893   tc->err_seq_valid = false;
894
895   OLSR_PRINTF(1, "Processing TC from %s, seq 0x%04x\n", olsr_ip_to_string(&buf, &originator), tc->msg_seq);
896
897   /*
898    * Now walk the edge advertisements contained in the packet.
899    */
900
901   limit = (unsigned char *)msg + size;
902   borderSet = 0;
903   emptyTC = curr >= limit;
904   while (curr < limit) {
905     if (olsr_tc_update_edge(tc, ansn, &curr, &upper_border_ip)) {
906       changes_topology = true;
907     }
908
909     if (!borderSet) {
910       borderSet = 1;
911       memcpy(&lower_border_ip, &upper_border_ip, sizeof(lower_border_ip));
912     }
913   }
914
915   /*
916    * Calculate real border IPs.
917    */
918   if (borderSet) {
919     borderSet = olsr_calculate_tc_border(lower_border, &lower_border_ip, upper_border, &upper_border_ip);
920   }
921
922   /*
923    * Set or change the expiration timer accordingly.
924    */
925   olsr_set_timer(&tc->validity_timer, vtime, OLSR_TC_VTIME_JITTER, OLSR_TIMER_ONESHOT, &olsr_expire_tc_entry, tc,
926                  tc_validity_timer_cookie->ci_id);
927
928   if (emptyTC && lower_border == 0xff && upper_border == 0xff) {
929     /* handle empty TC with border flags 0xff */
930     memset(&lower_border_ip, 0x00, sizeof(lower_border_ip));
931     memset(&upper_border_ip, 0xff, sizeof(upper_border_ip));
932     borderSet = 1;
933   }
934
935   if (borderSet) {
936
937     /*
938      * Delete all old tc edges within borders.
939      */
940     olsr_delete_revoked_tc_edges(tc, ansn, &lower_border_ip, &upper_border_ip);
941   } else {
942
943     /*
944      * Kick the the edge garbage collection timer. In the meantime hopefully
945      * all edges belonging to a multipart neighbor set will arrive.
946      */
947     olsr_set_timer(&tc->edge_gc_timer, OLSR_TC_EDGE_GC_TIME, OLSR_TC_EDGE_GC_JITTER, OLSR_TIMER_ONESHOT, &olsr_expire_tc_edge_gc,
948                    tc, tc_edge_gc_timer_cookie->ci_id);
949   }
950
951   if (emptyTC && borderSet) {
952     /* cleanup MIDs and HNAs if all edges have been erased by
953      * an empty TC, then alert the duplicate set and kill the
954      * tc entry */
955     olsr_cleanup_mid(&originator);
956     olsr_cleanup_hna(&originator);
957     olsr_cleanup_duplicates(&originator);
958
959     olsr_delete_tc_entry(tc);
960   }
961   /* Forward the message */
962   return true;
963 }
964
965 /*
966  * Local Variables:
967  * c-basic-offset: 2
968  * indent-tabs-mode: nil
969  * End:
970  */