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