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