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