Fix timer multiplier (unnecessary, constant is already in ms)
[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->status != SYM_LINK) {
374     return;
375   }
376
377   link->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->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
523   link->link_tc_edge = olsr_lookup_tc_edge(tc_myself, remote_main);
524   if (link->link_tc_edge == NULL) {
525     link->link_tc_edge = olsr_add_tc_edge_entry(tc_myself, remote_main, 0);
526   }
527
528   /*
529    * Add the rt_path for the link-end. This is an optimization
530    * that lets us install > 1 hop routes prior to receiving
531    * the MID entry for the 1 hop neighbor.
532    */
533   olsr_insert_routing_table(remote, 8 * olsr_cnf->ipsize, remote_main, OLSR_RT_ORIGIN_LINK);
534
535   changes_neighborhood = true;
536   return link;
537 }
538
539
540 /**
541  * Lookup the status of a link.
542  *
543  * @param int_addr address of the remote interface
544  * @return 1 of the link is symmertic 0 if not
545  */
546 int
547 check_neighbor_link(const union olsr_ip_addr *int_addr)
548 {
549   struct link_entry *link;
550
551   OLSR_FOR_ALL_LINK_ENTRIES(link) {
552     if (olsr_ipcmp(int_addr, &link->neighbor_iface_addr) == 0) {
553       return lookup_link_status(link);
554     }
555   }
556   OLSR_FOR_ALL_LINK_ENTRIES_END(link);
557
558   return UNSPEC_LINK;
559 }
560
561 /**
562  * Lookup a link entry
563  *
564  * @param remote the remote interface address
565  * @param remote_main the remote nodes main address
566  * @param local the local interface address
567  * @return the link entry if found, NULL if not
568  */
569 struct link_entry *
570 lookup_link_entry(const union olsr_ip_addr *remote, const union olsr_ip_addr *remote_main, const struct interface *local)
571 {
572   struct link_entry *link;
573
574   OLSR_FOR_ALL_LINK_ENTRIES(link) {
575     if (olsr_ipcmp(remote, &link->neighbor_iface_addr) == 0 && (link->if_name ? !strcmp(link->if_name, local->int_name)
576                                                                 : olsr_ipcmp(&local->ip_addr, &link->local_iface_addr) == 0)) {
577       /* check the remote-main address only if there is one given */
578       if (NULL != remote_main && olsr_ipcmp(remote_main, &link->neighbor->nbr_addr) != 0) {
579         /* Neighbor has changed it's main_addr, update */
580 #if !defined REMOVE_LOG_DEBUG
581         struct ipaddr_str oldbuf, newbuf;
582 #endif
583         OLSR_DEBUG(LOG_LINKS, "Neighbor changed main_ip, updating %s -> %s\n",
584                    olsr_ip_to_string(&oldbuf, &link->neighbor->nbr_addr), olsr_ip_to_string(&newbuf, remote_main));
585         link->neighbor->nbr_addr = *remote_main;
586       }
587       return link;
588     }
589   }
590   OLSR_FOR_ALL_LINK_ENTRIES_END(link);
591
592   return NULL;
593 }
594
595 /**
596  * Update a link entry. This is the "main entrypoint" in
597  * the link-sensing. This function is called from the HELLO
598  * parser function. It makes sure a entry is updated or created.
599  *
600  * @param local the local IP address
601  * @param remote the remote IP address
602  * @param message the HELLO message
603  * @param in_if the interface on which this HELLO was received
604  * @return the link_entry struct describing this link entry
605  */
606 struct link_entry *
607 update_link_entry(const union olsr_ip_addr *local,
608                   const union olsr_ip_addr *remote, struct lq_hello_message *message, struct interface *in_if)
609 {
610   struct link_entry *entry;
611
612   /* Add if not registered */
613   entry = add_link_entry(local, remote, &message->comm->originator, message->comm->vtime, message->htime, in_if);
614
615   /* Update ASYM_time */
616   entry->vtime = message->comm->vtime;
617   entry->ASYM_time = GET_TIMESTAMP(message->comm->vtime);
618
619   entry->status = check_link_status(message, in_if);
620
621   switch (entry->status) {
622   case (LOST_LINK):
623     olsr_stop_timer(entry->link_sym_timer);
624     entry->link_sym_timer = NULL;
625     break;
626   case (SYM_LINK):
627   case (ASYM_LINK):
628
629     /* L_SYM_time = current time + validity time */
630     olsr_set_timer(&entry->link_sym_timer, message->comm->vtime,
631                    OLSR_LINK_SYM_JITTER, OLSR_TIMER_ONESHOT, &olsr_expire_link_sym_timer, entry, link_sym_timer_cookie);
632
633     /* L_time = L_SYM_time + NEIGHB_HOLD_TIME */
634     olsr_set_link_timer(entry, message->comm->vtime + NEIGHB_HOLD_TIME);
635     break;
636   default:;
637   }
638
639   /* L_time = max(L_time, L_ASYM_time) */
640   if (entry->link_timer && (entry->link_timer->timer_clock < entry->ASYM_time)) {
641     olsr_set_link_timer(entry, TIME_DUE(entry->ASYM_time));
642   }
643
644   /* Update neighbor */
645   olsr_update_nbr_status(entry->neighbor, get_neighbor_status(remote));
646
647   return entry;
648 }
649
650
651 /**
652  * Function that updates all registered pointers to
653  * one neighbor entry with another pointer
654  * Used by MID updates.
655  *
656  * @old the pointer to replace
657  * @new the pointer to use instead of "old"
658  * @return the number of entries updated
659  */
660 int
661 replace_neighbor_link_set(const struct nbr_entry *old, struct nbr_entry *new)
662 {
663   struct link_entry *link;
664   int retval = 0;
665
666   if (list_is_empty(&link_entry_head)) {
667     return retval;
668   }
669
670   OLSR_FOR_ALL_LINK_ENTRIES(link) {
671
672     if (link->neighbor == old) {
673       link->neighbor = new;
674       retval++;
675     }
676   }
677   OLSR_FOR_ALL_LINK_ENTRIES_END(link);
678
679   return retval;
680 }
681
682
683 /**
684  *Checks the link status to a neighbor by
685  *looking in a received HELLO message.
686  *
687  *@param message the HELLO message to check
688  *
689  *@return the link status
690  */
691 static int
692 check_link_status(const struct lq_hello_message *message, const struct interface *in_if)
693 {
694   int ret = UNSPEC_LINK;
695   struct lq_hello_neighbor *neighbors;
696
697   neighbors = message->neigh;
698   while (neighbors) {
699
700     /*
701      * Note: If a neigh has 2 cards we can reach, the neigh
702      * will send a Hello with the same IP mentined twice
703      */
704     if (olsr_ipcmp(&neighbors->addr, &in_if->ip_addr) == 0
705         && neighbors->link_type != UNSPEC_LINK) {
706       ret = neighbors->link_type;
707       if (SYM_LINK == ret) {
708         break;
709       }
710     }
711     neighbors = neighbors->next;
712   }
713
714   return ret;
715 }
716
717 void
718 olsr_print_link_set(void)
719 {
720 #if !defined REMOVE_LOG_INFO
721   /* The whole function makes no sense without it. */
722   struct link_entry *walker;
723   char totaltxt[256];
724   const char *txt;
725   int addrsize;
726   size_t i, j, length, max, totaltxt_len;
727   addrsize = olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
728
729   /* generate LQ headline */
730   totaltxt[0] = 0;
731   totaltxt_len = 0;
732   for (i=1; i<olsr_get_linklabel_count(); i++) {
733     txt = olsr_get_linklabel(i);
734     max = olsr_get_linklabel_maxlength(i);
735
736     length = strlen(txt);
737
738     /* add seperator */
739     if (i != 1) {
740       totaltxt[totaltxt_len++] = '/';
741     }
742
743     /* reserve space for label */
744     if (max > length) {
745       for (j=0; j<max; j++) {
746         totaltxt[totaltxt_len + j] = '-';
747       }
748     }
749
750     /* copy label */
751     strncpy(&totaltxt[totaltxt_len + max/2 - length/2], txt, length);
752     totaltxt_len += max;
753   }
754   totaltxt[totaltxt_len] = 0;
755
756   OLSR_INFO(LOG_LINKS, "\n--- %s ---------------------------------------------------- LINKS\n\n", olsr_wallclock_string());
757   OLSR_INFO_NH(LOG_LINKS, "%-*s  %-6s %s %s\n", addrsize, "IP address", "hyst", totaltxt , olsr_get_linklabel(0));
758
759   OLSR_FOR_ALL_LINK_ENTRIES(walker) {
760     struct ipaddr_str buf;
761     char lqbuffer[LQTEXT_MAXLENGTH];
762
763     /* generate LQ headline */
764     totaltxt[0] = 0;
765     totaltxt_len = 0;
766     for (i=1; i<olsr_get_linklabel_count(); i++) {
767       txt = olsr_get_linkdata_text(walker, i, lqbuffer, sizeof(lqbuffer));
768       max = olsr_get_linklabel_maxlength(i);
769
770       length = strlen(txt);
771
772       /* add seperator */
773       if (i != 1) {
774         totaltxt[totaltxt_len++] = '/';
775       }
776
777       /* reserve space for label */
778       if (max > length) {
779         for (j=0; j<max; j++) {
780           totaltxt[totaltxt_len + j] = ' ';
781         }
782       }
783
784       /* copy label */
785       strncpy(&totaltxt[totaltxt_len + max/2 - length/2], txt, length);
786       totaltxt_len += max;
787     }
788     totaltxt[totaltxt_len] = 0;
789     OLSR_INFO_NH(LOG_LINKS, "%-*s %s %s\n",
790                  addrsize, olsr_ip_to_string(&buf, &walker->neighbor_iface_addr),
791                  totaltxt, olsr_get_linkcost_text(walker->linkcost, false, lqbuffer, sizeof(lqbuffer)));
792   } OLSR_FOR_ALL_LINK_ENTRIES_END(walker);
793 #endif
794 }
795
796 /*
797  * called for every LQ HELLO message.
798  * update the timeout with the htime value from the message
799  */
800 void
801 olsr_update_packet_loss_hello_int(struct link_entry *entry, uint32_t loss_hello_int)
802 {
803   entry->loss_helloint = loss_hello_int;
804 }
805
806 void
807 olsr_update_packet_loss(struct link_entry *entry)
808 {
809   olsr_update_packet_loss_worker(entry, false);
810
811   /* timeout for the first lost packet is 1.5 x htime */
812   olsr_set_timer(&entry->link_loss_timer, entry->loss_helloint + entry->loss_helloint / 2,
813                  OLSR_LINK_LOSS_JITTER, OLSR_TIMER_PERIODIC, &olsr_expire_link_loss_timer, entry, link_loss_timer_cookie);
814 }
815
816 void
817 generate_hello(void *p) {
818   struct interface *ifp = p;
819   uint8_t msg_buffer[MAXMESSAGESIZE - OLSR_HEADERSIZE] __attribute__ ((aligned));
820   struct olsr_message msg;
821   uint8_t *curr = msg_buffer;
822   uint8_t *length_field, *last;
823   struct link_entry *link;
824   uint8_t writeLinkType, writeNeighType;
825   OLSR_INFO(LOG_PACKET_CREATION, "Building Hello for %s\n-------------------\n", ifp->int_name);
826
827   msg.type = olsr_get_Hello_MessageId();
828   msg.vtime = ifp->hello_validity;
829   msg.size = 0; /* fill in later */
830   msg.originator = olsr_cnf->router_id;
831   msg.ttl = 1;
832   msg.hopcnt = 0;
833   msg.seqno = get_msg_seqno();
834
835   length_field = olsr_put_msg_hdr(&curr, &msg);
836
837   pkt_put_u16(&curr, 0);
838   pkt_put_reltime(&curr, ifp->hello_interval);
839   pkt_put_u8(&curr, olsr_cnf->willingness);
840
841   last = msg_buffer + sizeof(msg_buffer) - olsr_cnf->ipsize;
842
843   /* first calculate local link status */
844   OLSR_FOR_ALL_LINK_ENTRIES(link) {
845     if (olsr_ipcmp(&link->local_iface_addr, &ifp->ip_addr) != 0) {
846       link->iflocal_link_status = UNSPEC_LINK;
847     }
848     else {
849       link->iflocal_link_status = lookup_link_status(link);
850     }
851
852     if (link->neighbor->is_mpr) {
853       link->iflocal_neigh_status = MPR_NEIGH;
854     }
855     else if (link->neighbor->is_sym) {
856       link->iflocal_neigh_status = SYM_NEIGH;
857     }
858     else {
859       link->iflocal_neigh_status = NOT_NEIGH;
860     }
861   } OLSR_FOR_ALL_LINK_ENTRIES_END(link)
862
863   for (writeNeighType = 0; writeNeighType < COUNT_NEIGH_TYPES; writeNeighType++) {
864     for (writeLinkType = 0; writeLinkType < COUNT_LINK_TYPES; writeLinkType++) {
865       bool first = true;
866       uint8_t *linkstart = NULL;
867
868       OLSR_FOR_ALL_LINK_ENTRIES(link) {
869         if (link->iflocal_link_status != writeLinkType
870             || link->iflocal_neigh_status != writeNeighType) {
871           continue;
872         }
873
874         if (first) {
875           pkt_put_u8(&curr, CREATE_LINK_CODE(writeNeighType, writeLinkType));
876           pkt_put_u8(&curr, 0);
877           first = false;
878
879           /* put in dummy length */
880           linkstart = curr;
881           pkt_put_u16(&curr, 0);
882         }
883
884         pkt_put_ipaddress(&curr, &link->neighbor_iface_addr);
885         olsr_serialize_hello_lq_pair(&curr, link);
886       } OLSR_FOR_ALL_LINK_ENTRIES_END(link)
887
888       /* fix length field of hello block */
889       if (linkstart != NULL) {
890         pkt_put_u16(&linkstart, (uint16_t)(curr + 2 - linkstart));
891       }
892     }
893   }
894
895   /* fix length field of message */
896   pkt_put_u16(&length_field, curr - msg_buffer);
897
898   /* send hello immediately */
899   if (net_outbuffer_bytes_left(ifp) < curr - msg_buffer) {
900     net_output(ifp);
901   }
902   net_outbuffer_push(ifp, msg_buffer, curr - msg_buffer);
903   net_output(ifp);
904 }
905 /*
906  * Local Variables:
907  * c-basic-offset: 2
908  * indent-tabs-mode: nil
909  * End:
910  */