1 /*
2  * The olsr.org Optimized Link-State Routing daemon (olsrd)
3  *
4  * (c) by the OLSR project
5  *
6  * See our Git repository to find out who worked on this file
7  * and thus is a copyright holder on it.
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * * Redistributions of source code must retain the above copyright
16  *   notice, this list of conditions and the following disclaimer.
17  * * Redistributions in binary form must reproduce the above copyright
18  *   notice, this list of conditions and the following disclaimer in
19  *   the documentation and/or other materials provided with the
20  *   distribution.
21  * * Neither the name of olsr.org, olsrd nor the names of its
22  *   contributors may be used to endorse or promote products derived
23  *   from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Visit http://www.olsr.org for more information.
39  *
40  * If you find this software useful feel free to make a donation
41  * to the project. For more information see the website or contact
42  * the copyright holders.
43  *
44  */
45 
46 /*
47  * Link sensing database for the OLSR routing daemon
48  */
49 #include <assert.h>
50 
51 #include "defs.h"
52 #include "link_set.h"
53 #include "hysteresis.h"
54 #include "mid_set.h"
55 #include "mpr.h"
56 #include "neighbor_table.h"
57 #include "olsr.h"
58 #include "log.h"
59 #include "scheduler.h"
60 #include "olsr_spf.h"
61 #include "net_olsr.h"
62 #include "ipcalc.h"
63 #include "lq_plugin.h"
64 
65 /* head node for all link sets */
66 struct list_node link_entry_head;
67 
68 bool link_changes = false; /* is set if changes occur in MPRS set */
69 
70 void
signal_link_changes(bool val)71 signal_link_changes(bool val)
72 {                               /* XXX ugly */
73   link_changes = val;
74 }
75 
76 /* Prototypes. */
77 static int check_link_status(const struct hello_message *message, const struct interface_olsr *in_if);
78 static struct link_entry *add_link_entry(const union olsr_ip_addr *, const union olsr_ip_addr *, const union olsr_ip_addr *,
79                                          olsr_reltime, olsr_reltime, const struct interface_olsr *);
80 static int get_neighbor_status(const union olsr_ip_addr *);
81 static void olsr_expire_link_sym_timer(void *context);
82 
83 void
olsr_init_link_set(void)84 olsr_init_link_set(void)
85 {
86 
87   /* Init list head */
88   list_head_init(&link_entry_head);
89 }
90 
91 /**
92  * This function resets all links to lost, so that
93  * a final "lost all links" hello can be generated to
94  * tell your neighbors that you are gone now.
95  */
olsr_reset_all_links(void)96 void olsr_reset_all_links(void) {
97   struct link_entry *link;
98 
99   OLSR_FOR_ALL_LINK_ENTRIES(link) {
100     link->ASYM_time = now_times-1;
101 
102     olsr_stop_timer(link->link_sym_timer);
103     link->link_sym_timer = NULL;
104 
105     link->neighbor->is_mpr = false;
106     link->neighbor->status = NOT_SYM;
107   } OLSR_FOR_ALL_LINK_ENTRIES_END(link)
108 
109 
110   OLSR_FOR_ALL_LINK_ENTRIES(link) {
111     olsr_expire_link_sym_timer(link);
112     olsr_clear_hello_lq(link);
113   } OLSR_FOR_ALL_LINK_ENTRIES_END(link)
114 }
115 
116 /**
117  * Get the status of a link. The status is based upon different
118  * timeouts in the link entry.
119  *
120  * @param entry link entry
121  * @return the link status of the link
122  */
123 int
lookup_link_status(const struct link_entry * entry)124 lookup_link_status(const struct link_entry *entry)
125 {
126 
127   if (entry == NULL || list_is_empty(&link_entry_head)) {
128     return UNSPEC_LINK;
129   }
130 
131   /*
132    * Hysteresis
133    */
134   if (olsr_cnf->use_hysteresis) {
135 
136     /*
137      * if L_LOST_LINK_time is not expired, the link is advertised
138      * with a link type of LOST_LINK.
139      */
140 
141     if (!TIMED_OUT(entry->L_LOST_LINK_time)) {
142       return LOST_LINK;
143     }
144 
145     /*
146      * otherwise, if L_LOST_LINK_time is expired and L_link_pending
147      * is set to "true", the link SHOULD NOT be advertised at all;
148      */
149     if (entry->L_link_pending == 1) {
150 #ifndef NODEBUG
151       struct ipaddr_str buf;
152       OLSR_PRINTF(3, "HYST[%s]: Setting to HIDE\n", olsr_ip_to_string(&buf, &entry->neighbor_iface_addr));
153 #endif /* NODEBUG */
154       return HIDE_LINK;
155     }
156 
157     /*
158      * otherwise, if L_LOST_LINK_time is expired and L_link_pending
159      * is set to "false", the link is advertised as described
160      * previously in section 6.
161      */
162   }
163 
164   if (entry->link_sym_timer) {
165     return SYM_LINK;
166   }
167 
168   if (!TIMED_OUT(entry->ASYM_time)) {
169     return ASYM_LINK;
170   }
171 
172   return LOST_LINK;
173 }
174 
175 /**
176  * Find the "best" link status to a neighbor
177  *
178  * @param address the address to check for
179  * @return SYM_LINK if a symmetric link exists 0 if not
180  */
181 static int
get_neighbor_status(const union olsr_ip_addr * address)182 get_neighbor_status(const union olsr_ip_addr *address)
183 {
184   const union olsr_ip_addr *main_addr;
185   struct interface_olsr *ifs;
186 
187   /* Find main address */
188   if (!(main_addr = mid_lookup_main_addr(address)))
189     main_addr = address;
190 
191   /* Loop trough local interfaces to check all possebilities */
192   for (ifs = ifnet; ifs != NULL; ifs = ifs->int_next) {
193     struct mid_address *aliases;
194     struct link_entry *lnk = lookup_link_entry(main_addr, NULL, ifs);
195 
196     if (lnk != NULL) {
197       if (lookup_link_status(lnk) == SYM_LINK)
198         return SYM_LINK;
199     }
200 
201     /* Get aliases */
202     for (aliases = mid_lookup_aliases(main_addr); aliases != NULL; aliases = aliases->next_alias) {
203 
204       lnk = lookup_link_entry(&aliases->alias, NULL, ifs);
205       if (lnk && (lookup_link_status(lnk) == SYM_LINK)) {
206         return SYM_LINK;
207       }
208     }
209   }
210 
211   return 0;
212 }
213 
214 /**
215  * Find best link to a neighbor
216  */
217 struct link_entry *
get_best_link_to_neighbor(const union olsr_ip_addr * remote)218 get_best_link_to_neighbor(const union olsr_ip_addr *remote)
219 {
220   const union olsr_ip_addr *main_addr;
221   struct link_entry *walker, *good_link, *backup_link;
222   struct interface_olsr *tmp_if;
223   int curr_metric = MAX_IF_METRIC;
224   olsr_linkcost curr_lcost = LINK_COST_BROKEN;
225   olsr_linkcost tmp_lc;
226 
227   /* main address lookup */
228   main_addr = mid_lookup_main_addr(remote);
229 
230   /* "remote" *already is* the main address */
231   if (!main_addr) {
232     main_addr = remote;
233   }
234 
235   /* we haven't selected any links, yet */
236   good_link = NULL;
237   backup_link = NULL;
238 
239   /* loop through all links that we have */
240   OLSR_FOR_ALL_LINK_ENTRIES(walker) {
241 
242     /* if this is not a link to the neighour in question, skip */
243     if (!ipequal(&walker->neighbor->neighbor_main_addr, main_addr))
244       continue;
245 
246     if (olsr_cnf->lq_level == 0) {
247 
248       /*
249        * handle the non-LQ, RFC-compliant case
250        */
251 
252       /*
253        * find the interface for the link.
254        * we select the link with the best local interface metric.
255        */
256       tmp_if = walker->if_name ? if_ifwithname(walker->if_name) : if_ifwithaddr(&walker->local_iface_addr);
257 
258       if (!tmp_if) {
259         continue;
260       }
261 
262       /*
263        * is this interface better than anything we had before ?
264        * use the requested remote interface address as a tie-breaker
265        */
266       if ((tmp_if->int_metric < curr_metric) || ((tmp_if->int_metric == curr_metric) && ipequal(&walker->local_iface_addr, remote))) {
267 
268         /* memorize the interface's metric */
269         curr_metric = tmp_if->int_metric;
270 
271         /* prefer symmetric links over asymmetric links */
272         if (lookup_link_status(walker) == SYM_LINK) {
273           good_link = walker;
274         } else {
275           backup_link = walker;
276         }
277       }
278     } else {
279 
280       /*
281        * handle the LQ, non-RFC compliant case.
282        */
283 
284       /* get the link cost */
285       tmp_lc = walker->linkcost;
286 
287       /*
288        * is this link better than anything we had before ?
289        * use the requested remote interface address as a tie-breaker.
290        */
291       if ((tmp_lc < curr_lcost) || ((tmp_lc == curr_lcost) && ipequal(&walker->local_iface_addr, remote))) {
292 
293         /* memorize the link quality */
294         curr_lcost = tmp_lc;
295 
296         /* prefer symmetric links over asymmetric links */
297         if (lookup_link_status(walker) == SYM_LINK) {
298           good_link = walker;
299         } else {
300           backup_link = walker;
301         }
302       }
303     }
304   }
305   OLSR_FOR_ALL_LINK_ENTRIES_END(walker);
306 
307   /*
308    * if we haven't found any symmetric links, try to return an asymmetric link.
309    */
310   return good_link ? good_link : backup_link;
311 }
312 
313 static void
set_loss_link_multiplier(struct link_entry * entry)314 set_loss_link_multiplier(struct link_entry *entry)
315 {
316   struct interface_olsr *inter = NULL;
317   struct olsr_if *cfg_inter = NULL;
318   struct olsr_lq_mult *mult;
319   uint32_t val = 0;
320   union olsr_ip_addr null_addr;
321   struct ipaddr_str buf;
322 
323   /* find the interface for the link */
324   assert(entry->if_name);
325   inter = if_ifwithname(entry->if_name);
326 
327   if (inter) {
328     /* find the interface configuration for the interface */
329     for (cfg_inter = olsr_cnf->interfaces; cfg_inter; cfg_inter = cfg_inter->next) {
330       if (cfg_inter->interf == inter) {
331         break;
332       }
333     }
334   }
335 
336   if (cfg_inter) {
337     /* create a null address for comparison */
338     memset(&null_addr, 0, sizeof(union olsr_ip_addr));
339 
340     /* loop through the multiplier entries */
341     for (mult = cfg_inter->cnf->lq_mult; mult != NULL; mult = mult->next) {
342 
343       /*
344        * use the default multiplier only if there isn't any entry that
345        * has a matching IP address.
346        */
347       if ((ipequal(&mult->addr, &null_addr) && val == 0) || ipequal(&mult->addr, &entry->neighbor_iface_addr)) {
348         val = mult->value;
349       }
350     }
351   }
352 
353   /* if we have not found an entry, then use the default multiplier */
354   if (val == 0) {
355     val = LINK_LOSS_MULTIPLIER;
356   }
357 
358   /* store the multiplier */
359   entry->loss_link_multiplier = val;
360 
361   OLSR_PRINTF(1, "Set linkloss multiplier for %s on %s to %d\n",
362       olsr_ip_to_string(&buf, &entry->neighbor_iface_addr), entry->if_name, val);
363 }
364 
365 /*
366  * Delete, unlink and free a link entry.
367  */
368 static void
olsr_delete_link_entry(struct link_entry * link)369 olsr_delete_link_entry(struct link_entry *link)
370 {
371   struct tc_edge_entry *tc_edge;
372 
373   /* delete tc edges we made for SPF */
374   tc_edge = olsr_lookup_tc_edge(tc_myself, &link->neighbor_iface_addr);
375   if (tc_edge != NULL) {
376     olsr_delete_tc_edge_entry(tc_edge);
377   }
378 
379 
380   /* Delete neighbor entry */
381   if (link->neighbor->linkcount == 1) {
382     olsr_delete_neighbor_table(&link->neighbor->neighbor_main_addr);
383   } else {
384     link->neighbor->linkcount--;
385   }
386 
387   /* Kill running timers */
388   olsr_stop_timer(link->link_timer);
389   link->link_timer = NULL;
390   olsr_stop_timer(link->link_sym_timer);
391   link->link_sym_timer = NULL;
392   olsr_stop_timer(link->link_hello_timer);
393   link->link_hello_timer = NULL;
394   olsr_stop_timer(link->link_loss_timer);
395   link->link_loss_timer = NULL;
396   list_remove(&link->link_list);
397 
398   free(link->if_name);
399   free(link);
400 
401   changes_neighborhood = true;
402 }
403 
404 /**
405  * Delete all link entries matching a given interface address.
406  */
407 void
olsr_delete_link_entry_by_ip(const union olsr_ip_addr * int_addr)408 olsr_delete_link_entry_by_ip(const union olsr_ip_addr *int_addr)
409 {
410   struct link_entry *link;
411 
412   if (list_is_empty(&link_entry_head)) {
413     return;
414   }
415 
416   OLSR_FOR_ALL_LINK_ENTRIES(link) {
417     if (ipequal(int_addr, &link->local_iface_addr)) {
418       olsr_delete_link_entry(link);
419     }
420   }
421   OLSR_FOR_ALL_LINK_ENTRIES_END(link);
422 }
423 
424 
425 /**
426  * Callback for the link loss timer.
427  */
428 static void
olsr_expire_link_loss_timer(void * context)429 olsr_expire_link_loss_timer(void *context)
430 {
431   struct link_entry *link;
432 
433   link = (struct link_entry *)context;
434 
435   /* count the lost packet */
436   olsr_update_packet_loss_worker(link, true);
437 
438   /* next timeout in 1.0 x htime */
439   olsr_change_timer(link->link_loss_timer, link->loss_helloint, OLSR_LINK_LOSS_JITTER, OLSR_TIMER_PERIODIC);
440 }
441 
442 
443 /**
444  * Callback for the link SYM timer.
445  */
446 static void
olsr_expire_link_sym_timer(void * context)447 olsr_expire_link_sym_timer(void *context)
448 {
449   struct link_entry *link;
450 
451   link = (struct link_entry *)context;
452   link->link_sym_timer = NULL;  /* be pedandic */
453 
454   if (link->prev_status != SYM_LINK) {
455     return;
456   }
457 
458   link->prev_status = lookup_link_status(link);
459   update_neighbor_status(link->neighbor, get_neighbor_status(&link->neighbor_iface_addr));
460   changes_neighborhood = true;
461 }
462 
463 /**
464  * Callback for the link_hello timer.
465  */
466 void
olsr_expire_link_hello_timer(void * context)467 olsr_expire_link_hello_timer(void *context)
468 {
469   struct ipaddr_str buf;
470   struct link_entry *link;
471 
472   link = (struct link_entry *)context;
473 
474   link->L_link_quality = olsr_hyst_calc_instability(link->L_link_quality);
475 
476   OLSR_PRINTF(1, "HYST[%s] HELLO timeout %f\n", olsr_ip_to_string(&buf, &link->neighbor_iface_addr), (double)link->L_link_quality);
477 
478   /* Update hello_timeout - NO SLACK THIS TIME */
479   olsr_change_timer(link->link_hello_timer, link->last_htime, OLSR_LINK_JITTER, OLSR_TIMER_PERIODIC);
480 
481   /* Update hysteresis values */
482   olsr_process_hysteresis(link);
483 
484   /* update neighbor status */
485   update_neighbor_status(link->neighbor, get_neighbor_status(&link->neighbor_iface_addr));
486 
487   /* Update seqno - not mentioned in the RFC... kind of a hack.. */
488   link->olsr_seqno++;
489 }
490 
491 /**
492  * Callback for the link timer.
493  */
494 static void
olsr_expire_link_entry(void * context)495 olsr_expire_link_entry(void *context)
496 {
497   struct link_entry *link;
498 
499   link = (struct link_entry *)context;
500   link->link_timer = NULL;      /* be pedandic */
501 
502   olsr_delete_link_entry(link);
503 }
504 
505 /**
506  * Set the link expiration timer.
507  */
508 void
olsr_set_link_timer(struct link_entry * link,unsigned int rel_timer)509 olsr_set_link_timer(struct link_entry *link, unsigned int rel_timer)
510 {
511   struct ipaddr_str buf;
512 
513   OLSR_PRINTF(3, "reset link timer: %s = %u\n",
514     olsr_ip_to_string(&buf, &link->neighbor_iface_addr),
515     (unsigned int)(now_times + rel_timer/1000));
516   olsr_set_timer(&link->link_timer, rel_timer, OLSR_LINK_JITTER, OLSR_TIMER_ONESHOT, &olsr_expire_link_entry, link, 0);
517 }
518 
519 /**
520  * Nothing mysterious here.
521  * Adding a new link entry to the link set.
522  *
523  * @param local the local IP address
524  * @param remote the remote IP address
525  * @param remote_main the remote nodes main address
526  * @param vtime the validity time of the entry
527  * @param htime the HELLO interval of the remote node
528  * @param local_if the local interface
529  * @return the new link_entry
530  */
531 static struct link_entry *
add_link_entry(const union olsr_ip_addr * local,const union olsr_ip_addr * remote,const union olsr_ip_addr * remote_main,olsr_reltime vtime,olsr_reltime htime,const struct interface_olsr * local_if)532 add_link_entry(const union olsr_ip_addr *local, const union olsr_ip_addr *remote, const union olsr_ip_addr *remote_main,
533                olsr_reltime vtime, olsr_reltime htime, const struct interface_olsr *local_if)
534 {
535   struct link_entry *new_link;
536   struct neighbor_entry *neighbor;
537   struct link_entry *tmp_link_set;
538 
539   tmp_link_set = lookup_link_entry(remote, remote_main, local_if);
540   if (tmp_link_set) {
541     return tmp_link_set;
542   }
543 
544   /*
545    * if there exists no link tuple with
546    * L_neighbor_iface_addr == Source Address
547    */
548 
549 #ifdef DEBUG
550   {
551     struct ipaddr_str localbuf, rembuf;
552     OLSR_PRINTF(1, "Adding %s=>%s to link set\n", olsr_ip_to_string(&localbuf, local), olsr_ip_to_string(&rembuf, remote));
553   }
554 #endif /* DEBUG */
555 
556   /* a new tuple is created with... */
557   new_link = olsr_malloc_link_entry("new link entry");
558 
559   /* copy if_name, if it is defined */
560   if (local_if->int_name) {
561     size_t name_size = strlen(local_if->int_name) + 1;
562     new_link->if_name = olsr_malloc(name_size, "target of if_name in new link entry");
563     strscpy(new_link->if_name, local_if->int_name, name_size);
564   } else
565     new_link->if_name = NULL;
566 
567   /* shortcut to interface. XXX refcount */
568   new_link->inter = local_if;
569 
570   /*
571    * L_local_iface_addr = Address of the interface
572    * which received the HELLO message
573    */
574   new_link->local_iface_addr = *local;
575 
576   /* L_neighbor_iface_addr = Source Address */
577   new_link->neighbor_iface_addr = *remote;
578 
579   /* L_time = current time + validity time */
580   olsr_set_link_timer(new_link, vtime);
581 
582   new_link->prev_status = ASYM_LINK;
583 
584   /* HYSTERESIS */
585   if (olsr_cnf->use_hysteresis) {
586     new_link->L_link_pending = 1;
587     new_link->L_LOST_LINK_time = GET_TIMESTAMP(vtime);
588     olsr_update_hysteresis_hello(new_link, htime);
589     new_link->last_htime = htime;
590     new_link->olsr_seqno = 0;
591     new_link->olsr_seqno_valid = false;
592   }
593 
594   new_link->L_link_quality = 0.0;
595 
596   if (olsr_cnf->lq_level > 0) {
597     new_link->loss_helloint = htime;
598 
599     olsr_set_timer(&new_link->link_loss_timer, htime + htime / 2, OLSR_LINK_LOSS_JITTER, OLSR_TIMER_PERIODIC,
600                    &olsr_expire_link_loss_timer, new_link, 0);
601 
602     set_loss_link_multiplier(new_link);
603   }
604 
605   new_link->linkcost = LINK_COST_BROKEN;
606 
607   /* Add to queue */
608   list_add_before(&link_entry_head, &new_link->link_list);
609 
610   /*
611    * Create the neighbor entry
612    */
613 
614   /* Neighbor MUST exist! */
615   neighbor = olsr_lookup_neighbor_table(remote_main);
616   if (!neighbor) {
617 #ifdef DEBUG
618     struct ipaddr_str buf;
619     OLSR_PRINTF(3, "ADDING NEW NEIGHBOR ENTRY %s FROM LINK SET\n", olsr_ip_to_string(&buf, remote_main));
620 #endif /* DEBUG */
621     neighbor = olsr_insert_neighbor_table(remote_main);
622   }
623 
624   neighbor->linkcount++;
625   new_link->neighbor = neighbor;
626 
627   return new_link;
628 }
629 
630 /**
631  * Lookup the status of a link.
632  *
633  * @param int_addr address of the remote interface
634  * @return 1 of the link is symmertic 0 if not
635  */
636 int
check_neighbor_link(const union olsr_ip_addr * int_addr)637 check_neighbor_link(const union olsr_ip_addr *int_addr)
638 {
639   struct link_entry *link;
640 
641   OLSR_FOR_ALL_LINK_ENTRIES(link) {
642     if (ipequal(int_addr, &link->neighbor_iface_addr)) {
643       return lookup_link_status(link);
644     }
645   }
646   OLSR_FOR_ALL_LINK_ENTRIES_END(link);
647 
648   return UNSPEC_LINK;
649 }
650 
651 /**
652  * Lookup a link entry
653  *
654  * @param remote the remote interface address
655  * @param remote_main the remote nodes main address
656  * @param local the local interface address
657  * @return the link entry if found, NULL if not
658  */
659 struct link_entry *
lookup_link_entry(const union olsr_ip_addr * remote,const union olsr_ip_addr * remote_main,const struct interface_olsr * local)660 lookup_link_entry(const union olsr_ip_addr *remote, const union olsr_ip_addr *remote_main, const struct interface_olsr *local)
661 {
662   struct link_entry *link;
663 
664   OLSR_FOR_ALL_LINK_ENTRIES(link) {
665     if (ipequal(remote, &link->neighbor_iface_addr)
666         && (link->if_name ? !strcmp(link->if_name, local->int_name) : ipequal(&local->ip_addr, &link->local_iface_addr))) {
667       /* check the remote-main address only if there is one given */
668       if (NULL != remote_main && !ipequal(remote_main, &link->neighbor->neighbor_main_addr)) {
669         /* Neighbor has changed it's main_addr, update */
670         struct ipaddr_str oldbuf, newbuf;
671 
672         OLSR_PRINTF(1, "Neighbor changed main_ip, updating %s -> %s\n",
673                     olsr_ip_to_string(&oldbuf, &link->neighbor->neighbor_main_addr), olsr_ip_to_string(&newbuf, remote_main));
674         olsr_update_neighbor_main_addr(link->neighbor, remote_main);
675       }
676       return link;
677     }
678   }
679   OLSR_FOR_ALL_LINK_ENTRIES_END(link);
680 
681   return NULL;
682 }
683 
684 /**
685  * Update a link entry. This is the "main entrypoint" in
686  * the link-sensing. This function is called from the HELLO
687  * parser function. It makes sure a entry is updated or created.
688  *
689  * @param local the local IP address
690  * @param remote the remote IP address
691  * @param message the HELLO message
692  * @param in_if the interface on which this HELLO was received
693  * @return the link_entry struct describing this link entry
694  */
695 struct link_entry *
update_link_entry(const union olsr_ip_addr * local,const union olsr_ip_addr * remote,const struct hello_message * message,const struct interface_olsr * in_if)696 update_link_entry(const union olsr_ip_addr *local, const union olsr_ip_addr *remote, const struct hello_message *message,
697                   const struct interface_olsr *in_if)
698 {
699   struct link_entry *entry;
700 
701   /* Add if not registered */
702   entry = add_link_entry(local, remote, &message->source_addr, message->vtime, message->htime, in_if);
703 
704   /* Update ASYM_time */
705   entry->vtime = message->vtime;
706   entry->ASYM_time = GET_TIMESTAMP(message->vtime);
707 
708   entry->prev_status = check_link_status(message, in_if);
709 
710   switch (entry->prev_status) {
711   case (LOST_LINK):
712     olsr_stop_timer(entry->link_sym_timer);
713     entry->link_sym_timer = NULL;
714     break;
715   case (SYM_LINK):
716   case (ASYM_LINK):
717 
718     /* L_SYM_time = current time + validity time */
719     olsr_set_timer(&entry->link_sym_timer, message->vtime, OLSR_LINK_SYM_JITTER, OLSR_TIMER_ONESHOT, &olsr_expire_link_sym_timer,
720                    entry, 0);
721 
722     /* L_time = L_SYM_time + NEIGHB_HOLD_TIME */
723     olsr_set_link_timer(entry, message->vtime + NEIGHB_HOLD_TIME * MSEC_PER_SEC);
724     break;
725   default:
726     break;
727   }
728 
729   /* L_time = max(L_time, L_ASYM_time) */
730   if (entry->link_timer == NULL || (entry->link_timer->timer_clock < entry->ASYM_time)) {
731     olsr_set_link_timer(entry, TIME_DUE(entry->ASYM_time));
732   }
733 
734   /* Update hysteresis values */
735   if (olsr_cnf->use_hysteresis)
736     olsr_process_hysteresis(entry);
737 
738   /* Update neighbor */
739   update_neighbor_status(entry->neighbor, get_neighbor_status(remote));
740 
741   return entry;
742 }
743 
744 /**
745  * Function that updates all registered pointers to
746  * one neighbor entry with another pointer
747  * Used by MID updates.
748  *
749  * @param old the pointer to replace
750  * @param new the pointer to use instead of "old"
751  * @return the number of entries updated
752  */
753 int
replace_neighbor_link_set(const struct neighbor_entry * old,struct neighbor_entry * new)754 replace_neighbor_link_set(const struct neighbor_entry *old, struct neighbor_entry *new)
755 {
756   struct link_entry *link;
757   int retval = 0;
758 
759   if (list_is_empty(&link_entry_head)) {
760     return retval;
761   }
762 
763   OLSR_FOR_ALL_LINK_ENTRIES(link) {
764 
765     if (link->neighbor == old) {
766       link->neighbor = new;
767       retval++;
768     }
769   }
770   OLSR_FOR_ALL_LINK_ENTRIES_END(link);
771 
772   return retval;
773 }
774 
775 /**
776  *Checks the link status to a neighbor by
777  *looking in a received HELLO message.
778  *
779  *@param message the HELLO message to check
780  *@param in_if the incoming interface
781  *
782  *@return the link status
783  */
784 static int
check_link_status(const struct hello_message * message,const struct interface_olsr * in_if)785 check_link_status(const struct hello_message *message, const struct interface_olsr *in_if)
786 {
787   int ret = UNSPEC_LINK;
788   struct hello_neighbor *neighbors;
789 
790   neighbors = message->neighbors;
791   while (neighbors) {
792 
793     /*
794      * Note: If a neigh has 2 cards we can reach, the neigh
795      * will send a Hello with the same IP mentined twice
796      */
797     if (ipequal(&neighbors->address, &in_if->ip_addr) &&
798         neighbors->link != UNSPEC_LINK) {
799       ret = neighbors->link;
800       if (SYM_LINK == ret) {
801         break;
802       }
803     }
804     neighbors = neighbors->next;
805   }
806 
807   return ret;
808 }
809 
810 #ifndef NODEBUG
811 void
olsr_print_link_set(void)812 olsr_print_link_set(void)
813 {
814   /* The whole function makes no sense without it. */
815   struct link_entry *walker;
816   const int addrsize = olsr_cnf->ip_version == AF_INET ? (INET_ADDRSTRLEN - 1) : (INET6_ADDRSTRLEN - 1);
817 
818   OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- LINKS\n\n", olsr_wallclock_string());
819   OLSR_PRINTF(1, "%-*s  %-6s %-14s %s\n", addrsize, "IP address", "hyst", "      LQ      ", "ETX");
820 
821   OLSR_FOR_ALL_LINK_ENTRIES(walker) {
822 
823     struct ipaddr_str buf;
824     struct lqtextbuffer lqbuffer1, lqbuffer2;
825     OLSR_PRINTF(1, "%-*s  %5.3f  %-14s %s\n", addrsize, olsr_ip_to_string(&buf, &walker->neighbor_iface_addr),
826         (double)walker->L_link_quality,
827         get_link_entry_text(walker, '/', &lqbuffer1),
828         get_linkcost_text(walker->linkcost,false, &lqbuffer2));
829   } OLSR_FOR_ALL_LINK_ENTRIES_END(walker);
830 }
831 #endif /* NODEBUG */
832 
833 /*
834  * called for every LQ HELLO message.
835  * update the timeout with the htime value from the message
836  */
837 void
olsr_update_packet_loss_hello_int(struct link_entry * entry,olsr_reltime loss_hello_int)838 olsr_update_packet_loss_hello_int(struct link_entry *entry, olsr_reltime loss_hello_int)
839 {
840   entry->loss_helloint = loss_hello_int;
841 }
842 
843 void
olsr_received_hello_handler(struct link_entry * entry)844 olsr_received_hello_handler(struct link_entry *entry)
845 {
846   olsr_update_packet_loss_worker(entry, false);
847 
848   /* timeout for the first lost packet is 1.5 x htime */
849   olsr_set_timer(&entry->link_loss_timer, entry->loss_helloint + entry->loss_helloint / 2, OLSR_LINK_LOSS_JITTER,
850                  OLSR_TIMER_PERIODIC, &olsr_expire_link_loss_timer, entry, 0);
851 }
852 
853 /*
854  * Local Variables:
855  * c-basic-offset: 2
856  * indent-tabs-mode: nil
857  * End:
858  */
859