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