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