FIX: floatingpoint-text to uint32 conversion
[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 *, uint32_t, uint32_t, 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 #if !defined REMOVE_LOG_DEBUG
332   struct ipaddr_str buf;
333 #endif
334
335   OLSR_FOR_ALL_LINK_ENTRIES(link) {
336     if (ifp == link->inter) {
337       OLSR_DEBUG(LOG_LINKS, "Removing link %s of interface %s\n",
338           olsr_ip_to_string(&buf, &link->neighbor_iface_addr), ifp->int_name);
339       olsr_delete_link_entry(link);
340     }
341   }
342   OLSR_FOR_ALL_LINK_ENTRIES_END(link);
343 }
344
345 /**
346  * Callback for the link loss timer.
347  */
348 static void
349 olsr_expire_link_loss_timer(void *context)
350 {
351   struct link_entry *link;
352
353   link = (struct link_entry *)context;
354
355   /* count the lost packet */
356   olsr_update_packet_loss_worker(link, true);
357
358   /* next timeout in 1.0 x htime */
359   olsr_change_timer(link->link_loss_timer, link->loss_helloint, OLSR_LINK_LOSS_JITTER, OLSR_TIMER_PERIODIC);
360 }
361
362 /**
363  * Callback for the link SYM timer.
364  */
365 static void
366 olsr_expire_link_sym_timer(void *context)
367 {
368   struct link_entry *link;
369
370   link = (struct link_entry *)context;
371   link->link_sym_timer = NULL;  /* be pedandic */
372
373   if (link->prev_status != SYM_LINK) {
374     return;
375   }
376
377   link->prev_status = lookup_link_status(link);
378   olsr_update_nbr_status(link->neighbor, get_neighbor_status(&link->neighbor_iface_addr));
379   changes_neighborhood = true;
380 }
381
382 /**
383  * Callback for the link_hello timer.
384  */
385 void
386 olsr_expire_link_hello_timer(void *context)
387 {
388   struct link_entry *link;
389
390   link = (struct link_entry *)context;
391
392   /* update neighbor status */
393   olsr_update_nbr_status(link->neighbor, get_neighbor_status(&link->neighbor_iface_addr));
394 }
395
396 /**
397  * Callback for the link timer.
398  */
399 static void
400 olsr_expire_link_entry(void *context)
401 {
402   struct link_entry *link;
403
404   link = (struct link_entry *)context;
405   link->link_timer = NULL;      /* be pedandic */
406
407   olsr_delete_link_entry(link);
408 }
409
410 /**
411  * Set the link expiration timer.
412  */
413 static void
414 olsr_set_link_timer(struct link_entry *link, unsigned int rel_timer)
415 {
416   olsr_set_timer(&link->link_timer, rel_timer, OLSR_LINK_JITTER,
417                  OLSR_TIMER_ONESHOT, &olsr_expire_link_entry, link, link_dead_timer_cookie);
418 }
419
420 /**
421  * Nothing mysterious here.
422  * Adding a new link entry to the link set.
423  *
424  * @param local the local IP address
425  * @param remote the remote IP address
426  * @param remote_main the remote nodes main address
427  * @param vtime the validity time of the entry
428  * @param htime the HELLO interval of the remote node
429  * @param local_if the local interface
430  * @return the new (or already existing) link_entry
431  */
432 static struct link_entry *
433 add_link_entry(const union olsr_ip_addr *local,
434                const union olsr_ip_addr *remote,
435                union olsr_ip_addr *remote_main, uint32_t vtime, uint32_t htime, struct interface *local_if)
436 {
437   struct link_entry *link;
438   struct nbr_entry *neighbor;
439 #if !defined  REMOVE_LOG_DEBUG
440   struct ipaddr_str localbuf, rembuf;
441 #endif
442
443   link = lookup_link_entry(remote, remote_main, local_if);
444   if (link) {
445     /*
446      * Link exists. Update tc_edge LQ and exit.
447      */
448     olsr_copylq_link_entry_2_tc_edge_entry(link->link_tc_edge, link);
449     changes_neighborhood = olsr_calc_tc_edge_entry_etx(link->link_tc_edge);
450     return link;
451   }
452
453   /*
454    * if there exists no link tuple with
455    * L_neighbor_iface_addr == Source Address
456    */
457
458   OLSR_DEBUG(LOG_LINKS, "Adding %s=>%s to link set\n", olsr_ip_to_string(&localbuf, local), olsr_ip_to_string(&rembuf, remote));
459
460   /* a new tuple is created with... */
461   link = olsr_malloc_link_entry();
462
463   /* copy if_name, if it is defined */
464   if (local_if->int_name) {
465     size_t name_size = strlen(local_if->int_name) + 1;
466     link->if_name = olsr_malloc(name_size, "target of if_name in new link entry");
467     strscpy(link->if_name, local_if->int_name, name_size);
468   } else
469     link->if_name = NULL;
470
471   /* shortcut to interface. */
472   link->inter = local_if;
473   lock_interface(local_if);
474
475   /*
476    * L_local_iface_addr = Address of the interface
477    * which received the HELLO message
478    */
479   link->local_iface_addr = *local;
480
481   /* L_neighbor_iface_addr = Source Address */
482   link->neighbor_iface_addr = *remote;
483
484   /* L_time = current time + validity time */
485   olsr_set_link_timer(link, vtime);
486
487   link->prev_status = ASYM_LINK;
488
489   link->loss_helloint = htime;
490
491   olsr_set_timer(&link->link_loss_timer, htime + htime / 2,
492                  OLSR_LINK_LOSS_JITTER, OLSR_TIMER_PERIODIC, &olsr_expire_link_loss_timer, link, link_loss_timer_cookie);
493
494   set_loss_link_multiplier(link);
495
496   link->linkcost = LINK_COST_BROKEN;
497
498   link->is_mprs = false;
499
500   /* Add to queue */
501   list_add_before(&link_entry_head, &link->link_list);
502
503
504   /*
505    * Create the neighbor entry
506    */
507
508   /* Neighbor MUST exist! */
509   neighbor = olsr_lookup_nbr_entry(remote_main, true);
510   if (!neighbor) {
511     OLSR_DEBUG(LOG_LINKS, "ADDING NEW NEIGHBOR ENTRY %s FROM LINK SET\n", olsr_ip_to_string(&rembuf, remote_main));
512     neighbor = olsr_add_nbr_entry(remote_main);
513   }
514
515   neighbor->linkcount++;
516   link->neighbor = neighbor;
517
518   /*
519    * Now create a tc-edge for that link.
520    */
521   olsr_change_myself_tc();
522   if (link->link_tc_edge == NULL) {
523     link->link_tc_edge = olsr_add_tc_edge_entry(tc_myself, remote_main, 0);
524   }
525
526   /*
527    * Mark the edge local such that it does not get deleted
528    * during cleanup functions.
529    */
530   link->link_tc_edge->is_local = 1;
531
532   /*
533    * Add the rt_path for the link-end. This is an optimization
534    * that lets us install > 1 hop routes prior to receiving
535    * the MID entry for the 1 hop neighbor.
536    */
537   olsr_insert_routing_table(remote, 8 * olsr_cnf->ipsize, remote_main, OLSR_RT_ORIGIN_LINK);
538
539   changes_neighborhood = true;
540   return link;
541 }
542
543
544 /**
545  * Lookup the status of a link.
546  *
547  * @param int_addr address of the remote interface
548  * @return 1 of the link is symmertic 0 if not
549  */
550 int
551 check_neighbor_link(const union olsr_ip_addr *int_addr)
552 {
553   struct link_entry *link;
554
555   OLSR_FOR_ALL_LINK_ENTRIES(link) {
556     if (olsr_ipcmp(int_addr, &link->neighbor_iface_addr) == 0) {
557       return lookup_link_status(link);
558     }
559   }
560   OLSR_FOR_ALL_LINK_ENTRIES_END(link);
561
562   return UNSPEC_LINK;
563 }
564
565 /**
566  * Lookup a link entry
567  *
568  * @param remote the remote interface address
569  * @param remote_main the remote nodes main address
570  * @param local the local interface address
571  * @return the link entry if found, NULL if not
572  */
573 struct link_entry *
574 lookup_link_entry(const union olsr_ip_addr *remote, const union olsr_ip_addr *remote_main, const struct interface *local)
575 {
576   struct link_entry *link;
577
578   OLSR_FOR_ALL_LINK_ENTRIES(link) {
579     if (olsr_ipcmp(remote, &link->neighbor_iface_addr) == 0 && (link->if_name ? !strcmp(link->if_name, local->int_name)
580                                                                 : olsr_ipcmp(&local->ip_addr, &link->local_iface_addr) == 0)) {
581       /* check the remote-main address only if there is one given */
582       if (NULL != remote_main && olsr_ipcmp(remote_main, &link->neighbor->nbr_addr) != 0) {
583         /* Neighbor has changed it's main_addr, update */
584 #if !defined REMOVE_LOG_DEBUG
585         struct ipaddr_str oldbuf, newbuf;
586 #endif
587         OLSR_DEBUG(LOG_LINKS, "Neighbor changed main_ip, updating %s -> %s\n",
588                    olsr_ip_to_string(&oldbuf, &link->neighbor->nbr_addr), olsr_ip_to_string(&newbuf, remote_main));
589         link->neighbor->nbr_addr = *remote_main;
590       }
591       return link;
592     }
593   }
594   OLSR_FOR_ALL_LINK_ENTRIES_END(link);
595
596   return NULL;
597 }
598
599 /**
600  * Update a link entry. This is the "main entrypoint" in
601  * the link-sensing. This function is called from the HELLO
602  * parser function. It makes sure a entry is updated or created.
603  *
604  * @param local the local IP address
605  * @param remote the remote IP address
606  * @param message the HELLO message
607  * @param in_if the interface on which this HELLO was received
608  * @return the link_entry struct describing this link entry
609  */
610 struct link_entry *
611 update_link_entry(const union olsr_ip_addr *local,
612                   const union olsr_ip_addr *remote, struct lq_hello_message *message, struct interface *in_if)
613 {
614   struct link_entry *entry;
615
616   /* Add if not registered */
617   entry = add_link_entry(local, remote, &message->comm.orig, message->comm.vtime, message->htime, in_if);
618
619   /* Update ASYM_time */
620   entry->vtime = message->comm.vtime;
621   entry->ASYM_time = GET_TIMESTAMP(message->comm.vtime);
622
623   entry->prev_status = check_link_status(message, in_if);
624
625   switch (entry->prev_status) {
626   case (LOST_LINK):
627     olsr_stop_timer(entry->link_sym_timer);
628     entry->link_sym_timer = NULL;
629     break;
630   case (SYM_LINK):
631   case (ASYM_LINK):
632
633     /* L_SYM_time = current time + validity time */
634     olsr_set_timer(&entry->link_sym_timer, message->comm.vtime,
635                    OLSR_LINK_SYM_JITTER, OLSR_TIMER_ONESHOT, &olsr_expire_link_sym_timer, entry, link_sym_timer_cookie);
636
637     /* L_time = L_SYM_time + NEIGHB_HOLD_TIME */
638     olsr_set_link_timer(entry, message->comm.vtime + NEIGHB_HOLD_TIME * MSEC_PER_SEC);
639     break;
640   default:;
641   }
642
643   /* L_time = max(L_time, L_ASYM_time) */
644   if (entry->link_timer && (entry->link_timer->timer_clock < entry->ASYM_time)) {
645     olsr_set_link_timer(entry, TIME_DUE(entry->ASYM_time));
646   }
647
648   /* Update neighbor */
649   olsr_update_nbr_status(entry->neighbor, get_neighbor_status(remote));
650
651   return entry;
652 }
653
654
655 /**
656  * Function that updates all registered pointers to
657  * one neighbor entry with another pointer
658  * Used by MID updates.
659  *
660  * @old the pointer to replace
661  * @new the pointer to use instead of "old"
662  * @return the number of entries updated
663  */
664 int
665 replace_neighbor_link_set(const struct nbr_entry *old, struct nbr_entry *new)
666 {
667   struct link_entry *link;
668   int retval = 0;
669
670   if (list_is_empty(&link_entry_head)) {
671     return retval;
672   }
673
674   OLSR_FOR_ALL_LINK_ENTRIES(link) {
675
676     if (link->neighbor == old) {
677       link->neighbor = new;
678       retval++;
679     }
680   }
681   OLSR_FOR_ALL_LINK_ENTRIES_END(link);
682
683   return retval;
684 }
685
686
687 /**
688  *Checks the link status to a neighbor by
689  *looking in a received HELLO message.
690  *
691  *@param message the HELLO message to check
692  *
693  *@return the link status
694  */
695 static int
696 check_link_status(const struct lq_hello_message *message, const struct interface *in_if)
697 {
698   int ret = UNSPEC_LINK;
699   struct lq_hello_neighbor *neighbors;
700
701   neighbors = message->neigh;
702   while (neighbors) {
703
704     /*
705      * Note: If a neigh has 2 cards we can reach, the neigh
706      * will send a Hello with the same IP mentined twice
707      */
708     if (olsr_ipcmp(&neighbors->addr, &in_if->ip_addr) == 0
709         && neighbors->link_type != UNSPEC_LINK) {
710       ret = neighbors->link_type;
711       if (SYM_LINK == ret) {
712         break;
713       }
714     }
715     neighbors = neighbors->next;
716   }
717
718   return ret;
719 }
720
721 void
722 olsr_print_link_set(void)
723 {
724 #if !defined REMOVE_LOG_INFO
725   /* The whole function makes no sense without it. */
726   struct link_entry *walker;
727   const int addrsize = olsr_cnf->ip_version == AF_INET ? 15 : 39;
728
729   OLSR_INFO(LOG_LINKS, "\n--- %s ---------------------------------------------------- LINKS\n\n", olsr_wallclock_string());
730   OLSR_INFO_NH(LOG_LINKS, "%-*s  %-6s %-14s %s\n", addrsize, "IP address", "hyst", "      LQ      ", "ETX");
731
732   OLSR_FOR_ALL_LINK_ENTRIES(walker) {
733     struct ipaddr_str buf;
734     struct lqtextbuffer lqbuffer1, lqbuffer2;
735
736     OLSR_INFO_NH(LOG_LINKS, "%-*s %-14s %s\n",
737                  addrsize, olsr_ip_to_string(&buf, &walker->neighbor_iface_addr),
738                  get_link_entry_text(walker, '/', &lqbuffer1), get_linkcost_text(walker->linkcost, false, &lqbuffer2));
739   } OLSR_FOR_ALL_LINK_ENTRIES_END(walker);
740 #endif
741 }
742
743 /*
744  * called for every LQ HELLO message.
745  * update the timeout with the htime value from the message
746  */
747 void
748 olsr_update_packet_loss_hello_int(struct link_entry *entry, uint32_t loss_hello_int)
749 {
750   entry->loss_helloint = loss_hello_int;
751 }
752
753 void
754 olsr_update_packet_loss(struct link_entry *entry)
755 {
756   olsr_update_packet_loss_worker(entry, false);
757
758   /* timeout for the first lost packet is 1.5 x htime */
759   olsr_set_timer(&entry->link_loss_timer, entry->loss_helloint + entry->loss_helloint / 2,
760                  OLSR_LINK_LOSS_JITTER, OLSR_TIMER_PERIODIC, &olsr_expire_link_loss_timer, entry, link_loss_timer_cookie);
761 }
762
763 /*
764  * Local Variables:
765  * c-basic-offset: 2
766  * indent-tabs-mode: nil
767  * End:
768  */