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