7504fcc8f2e961d4d9910624a9f5bb2a4c5bef4e
[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 "olsr_timer.h"
52 #include "olsr_socket.h"
53 #include "olsr_spf.h"
54 #include "net_olsr.h"
55 #include "ipcalc.h"
56 #include "lq_plugin.h"
57 #include "common/string.h"
58 #include "olsr_logging.h"
59
60 #include <assert.h>
61
62 static void olsr_expire_link_entry(void *context);
63 static void olsr_expire_link_loss_timer(void *context);
64 static void olsr_expire_link_sym_timer(void *context);
65
66 /* head node for all link sets */
67 struct list_entity link_entry_head;
68
69 static struct olsr_timer_info *link_dead_timer_info = NULL;
70 static struct olsr_timer_info *link_loss_timer_info = NULL;
71 static struct olsr_timer_info *link_sym_timer_info = NULL;
72
73 bool link_changes;                     /* is set if changes occur in MPRS set */
74
75 void
76 signal_link_changes(bool val)
77 {                               /* XXX ugly */
78   link_changes = val;
79 }
80
81 /* Prototypes. */
82 static int check_link_status(const struct lq_hello_message *message, const struct interface *in_if);
83 static struct link_entry *add_link_entry(const union olsr_ip_addr *,
84                                          const union olsr_ip_addr *,
85                                          union olsr_ip_addr *, uint32_t, uint32_t, struct interface *);
86
87 void
88 olsr_init_link_set(void)
89 {
90   OLSR_INFO(LOG_LINKS, "Initialize linkset...\n");
91
92   /* Init list head */
93   list_init_head(&link_entry_head);
94
95   link_dead_timer_info = olsr_timer_add("Link dead", &olsr_expire_link_entry, false);
96   link_loss_timer_info = olsr_timer_add("Link loss", &olsr_expire_link_loss_timer, true);
97   link_sym_timer_info = olsr_timer_add("Link SYM", &olsr_expire_link_sym_timer, false);
98
99 }
100
101
102 /**
103  * Get the status of a link. The status is based upon different
104  * timeouts in the link entry.
105  *
106  * @param remote address of the remote interface
107  * @return the link status of the link
108  */
109 int
110 lookup_link_status(const struct link_entry *entry)
111 {
112   if (entry == NULL || list_is_empty(&link_entry_head)) {
113     return UNSPEC_LINK;
114   }
115
116   if (entry->link_sym_timer) {
117     return SYM_LINK;
118   }
119
120   if (!olsr_timer_isTimedOut(entry->ASYM_time)) {
121     return ASYM_LINK;
122   }
123
124   return LOST_LINK;
125 }
126
127 /**
128  * Find best link to a neighbor
129  */
130 struct link_entry *
131 get_best_link_to_neighbor_ip(const union olsr_ip_addr *remote)
132 {
133   struct nbr_entry *nbr;
134
135   nbr = olsr_lookup_nbr_entry(remote, true);
136   return get_best_link_to_neighbor(nbr);
137 }
138
139 /**
140  * Find best link to a neighbor
141  */
142 struct link_entry *
143 get_best_link_to_neighbor(struct nbr_entry *nbr)
144 {
145   struct link_entry *walker, *good_link, *iterator;
146   olsr_linkcost curr_lcost = LINK_COST_BROKEN;
147
148   /* we haven't selected any links, yet */
149   good_link = NULL;
150
151   /* loop through all links that we have */
152   OLSR_FOR_ALL_LINK_ENTRIES(walker, iterator) {
153     /* if this is not a link to the neighour in question, skip */
154     if (walker->neighbor != nbr || lookup_link_status(walker) != SYM_LINK)
155       continue;
156
157     /*
158      * is this link better than anything we had before ?
159      */
160     if (walker->linkcost < curr_lcost) {
161       /* memorize the link quality */
162       curr_lcost = walker->linkcost;
163       good_link = walker;
164     }
165   }
166
167   /*
168    * if we haven't found any symmetric links, try to return an asymmetric link.
169    */
170   return good_link;
171 }
172
173 static void
174 set_loss_link_multiplier(struct link_entry *entry)
175 {
176   struct interface *inter;
177   struct olsr_if_config *cfg_inter;
178   struct olsr_lq_mult *mult;
179   uint32_t val = 0;
180
181   /* find the interface for the link */
182   inter = if_ifwithaddr(&entry->local_iface_addr);
183
184   /* find the interface configuration for the interface */
185   for (cfg_inter = olsr_cnf->if_configs; cfg_inter; cfg_inter = cfg_inter->next) {
186     if (cfg_inter->interf == inter) {
187       break;
188     }
189   }
190
191   /* loop through the multiplier entries */
192   for (mult = cfg_inter->cnf->lq_mult; mult != NULL; mult = mult->next) {
193     /*
194      * use the default multiplier only if there isn't any entry that
195      * has a matching IP address.
196      */
197     if ((val == 0 && olsr_ipcmp(&mult->addr, &all_zero) == 0) || olsr_ipcmp(&mult->addr, &entry->neighbor_iface_addr) == 0) {
198       val = mult->value;
199     }
200   }
201
202   /* if we have not found an entry, then use the default multiplier */
203   if (val == 0) {
204     val = LINK_LOSS_MULTIPLIER;
205   }
206
207   /* store the multiplier */
208   entry->loss_link_multiplier = val;
209 }
210
211 /*
212  * Delete, unlink and free a link entry.
213  */
214 static void
215 olsr_delete_link_entry(struct link_entry *link)
216 {
217   /*
218    * Delete the rt_path for the link-end.
219    */
220   olsr_delete_routing_table(&link->neighbor_iface_addr, 8 * olsr_cnf->ipsize,
221                             &link->neighbor->nbr_addr, OLSR_RT_ORIGIN_LINK);
222
223   /* update neighbor statistics */
224   link->neighbor->linkcount--;
225   if (link->is_mprs) {
226     link->neighbor->mprs_count --;
227   }
228
229   /* Delete neighbor entry if no links left */
230   if (link->neighbor->linkcount == 0) {
231     olsr_delete_nbr_entry(link->neighbor);
232   }
233
234   /* Kill running timers */
235   olsr_timer_stop(link->link_timer);
236   link->link_timer = NULL;
237
238   olsr_timer_stop(link->link_sym_timer);
239   link->link_sym_timer = NULL;
240
241   olsr_timer_stop(link->link_loss_timer);
242   link->link_loss_timer = NULL;
243
244   list_remove(&link->link_list);
245
246   /* Unlink Interfaces */
247   unlock_interface(link->inter);
248   link->inter = NULL;
249
250   free(link->if_name);
251   olsr_free_link_entry(link);
252
253   changes_neighborhood = true;
254 }
255
256 /**
257  * Delete all link entries matching a given interface id
258  */
259 void
260 olsr_delete_link_entry_by_if(const struct interface *ifp)
261 {
262   struct link_entry *link, *iterator;
263 #if !defined REMOVE_LOG_DEBUG
264   struct ipaddr_str buf;
265 #endif
266
267   OLSR_FOR_ALL_LINK_ENTRIES(link, iterator) {
268     if (ifp == link->inter) {
269       OLSR_DEBUG(LOG_LINKS, "Removing link %s of interface %s\n",
270           olsr_ip_to_string(&buf, &link->neighbor_iface_addr), ifp->int_name);
271       olsr_delete_link_entry(link);
272     }
273   }
274 }
275
276 /**
277  * Callback for the link loss timer.
278  */
279 static void
280 olsr_expire_link_loss_timer(void *context)
281 {
282   struct link_entry *link;
283
284   link = (struct link_entry *)context;
285
286   /* count the lost packet */
287   olsr_lq_hello_handler(link, true);
288
289   /* next timeout in 1.0 x htime */
290   olsr_timer_change(link->link_loss_timer, link->loss_helloint, OLSR_LINK_LOSS_JITTER);
291 }
292
293 /**
294  * Callback for the link SYM timer.
295  */
296 static void
297 olsr_expire_link_sym_timer(void *context)
298 {
299   struct link_entry *link;
300
301   link = (struct link_entry *)context;
302   link->link_sym_timer = NULL;  /* be pedandic */
303
304   if (link->status != SYM_LINK) {
305     return;
306   }
307
308   link->status = lookup_link_status(link);
309   olsr_update_nbr_status(link->neighbor);
310   changes_neighborhood = true;
311 }
312
313 /**
314  * Callback for the link_hello timer.
315  */
316 void
317 olsr_expire_link_hello_timer(void *context)
318 {
319   struct link_entry *link;
320
321   link = (struct link_entry *)context;
322
323   /* update neighbor status */
324   olsr_update_nbr_status(link->neighbor);
325 }
326
327 /**
328  * Callback for the link timer.
329  */
330 static void
331 olsr_expire_link_entry(void *context)
332 {
333   struct link_entry *link;
334
335   link = (struct link_entry *)context;
336   link->link_timer = NULL;      /* be pedandic */
337
338   olsr_delete_link_entry(link);
339 }
340
341 /**
342  * Set the link expiration timer.
343  */
344 static void
345 olsr_set_link_timer(struct link_entry *link, unsigned int rel_timer)
346 {
347   olsr_timer_set(&link->link_timer, rel_timer, OLSR_LINK_JITTER,
348                  link, link_dead_timer_info);
349 }
350
351 /**
352  * Nothing mysterious here.
353  * Adding a new link entry to the link set.
354  *
355  * @param local the local IP address
356  * @param remote the remote IP address
357  * @param remote_main the remote nodes main address
358  * @param vtime the validity time of the entry
359  * @param htime the HELLO interval of the remote node
360  * @param local_if the local interface
361  * @return the new (or already existing) link_entry
362  */
363 static struct link_entry *
364 add_link_entry(const union olsr_ip_addr *local,
365                const union olsr_ip_addr *remote,
366                union olsr_ip_addr *remote_main, uint32_t vtime, uint32_t htime, struct interface *local_if)
367 {
368   struct link_entry *link;
369   struct nbr_entry *neighbor;
370 #if !defined  REMOVE_LOG_DEBUG
371   struct ipaddr_str localbuf, rembuf;
372 #endif
373
374   link = lookup_link_entry(remote, remote_main, local_if);
375   if (link) {
376     return link;
377   }
378
379   /*
380    * if there exists no link tuple with
381    * L_neighbor_iface_addr == Source Address
382    */
383
384   OLSR_DEBUG(LOG_LINKS, "Adding %s=>%s to link set\n", olsr_ip_to_string(&localbuf, local), olsr_ip_to_string(&rembuf, remote));
385
386   /* a new tuple is created with... */
387   link = olsr_malloc_link_entry();
388
389   /* copy if_name, if it is defined */
390   if (local_if->int_name) {
391     link->if_name = strdup(local_if->int_name);
392   } else {
393     link->if_name = NULL;
394   }
395   /* shortcut to interface. */
396   link->inter = local_if;
397   lock_interface(local_if);
398
399   /*
400    * L_local_iface_addr = Address of the interface
401    * which received the HELLO message
402    */
403   link->local_iface_addr = *local;
404
405   /* L_neighbor_iface_addr = Source Address */
406   link->neighbor_iface_addr = *remote;
407
408   /* L_time = current time + validity time */
409   olsr_set_link_timer(link, vtime);
410
411   link->status = ASYM_LINK;
412
413   link->loss_helloint = htime;
414
415   olsr_timer_set(&link->link_loss_timer, htime + htime / 2,
416                  OLSR_LINK_LOSS_JITTER, link, link_loss_timer_info);
417
418   set_loss_link_multiplier(link);
419
420   link->linkcost = LINK_COST_BROKEN;
421
422   link->is_mprs = false;
423
424   /* Add to queue */
425   list_add_before(&link_entry_head, &link->link_list);
426
427
428   /*
429    * Create the neighbor entry
430    */
431
432   /* Neighbor MUST exist! */
433   neighbor = olsr_lookup_nbr_entry(remote_main, true);
434   if (!neighbor) {
435     OLSR_DEBUG(LOG_LINKS, "ADDING NEW NEIGHBOR ENTRY %s FROM LINK SET\n", olsr_ip_to_string(&rembuf, remote_main));
436     neighbor = olsr_add_nbr_entry(remote_main);
437   }
438
439   assert(neighbor->tc_edge);
440
441   neighbor->linkcount++;
442   link->neighbor = neighbor;
443
444   /*
445    * Add the rt_path for the link-end. This is an optimization
446    * that lets us install > 1 hop routes prior to receiving
447    * the MID entry for the 1 hop neighbor.
448    */
449   olsr_insert_routing_table(remote, 8 * olsr_cnf->ipsize, remote_main, OLSR_RT_ORIGIN_LINK);
450
451   changes_neighborhood = true;
452   return link;
453 }
454
455
456 /**
457  * Lookup the status of a link.
458  *
459  * @param int_addr address of the remote interface
460  * @return 1 of the link is symmertic 0 if not
461  */
462 int
463 check_neighbor_link(const union olsr_ip_addr *int_addr)
464 {
465   struct link_entry *link, *iterator;
466
467   OLSR_FOR_ALL_LINK_ENTRIES(link, iterator) {
468     if (olsr_ipcmp(int_addr, &link->neighbor_iface_addr) == 0) {
469       return lookup_link_status(link);
470     }
471   }
472
473   return UNSPEC_LINK;
474 }
475
476 /**
477  * Lookup a link entry
478  *
479  * @param remote the remote interface address
480  * @param remote_main the remote nodes main address
481  * @param local the local interface address
482  * @return the link entry if found, NULL if not
483  */
484 struct link_entry *
485 lookup_link_entry(const union olsr_ip_addr *remote, const union olsr_ip_addr *remote_main, const struct interface *local)
486 {
487   struct link_entry *link, *iterator;
488
489   OLSR_FOR_ALL_LINK_ENTRIES(link, iterator) {
490     if (olsr_ipcmp(remote, &link->neighbor_iface_addr) == 0 && (link->if_name ? !strcmp(link->if_name, local->int_name)
491                                                                 : olsr_ipcmp(&local->ip_addr, &link->local_iface_addr) == 0)) {
492       /* check the remote-main address only if there is one given */
493       if (NULL != remote_main && olsr_ipcmp(remote_main, &link->neighbor->nbr_addr) != 0) {
494         /* Neighbor has changed it's router_id, update */
495 #if !defined REMOVE_LOG_DEBUG
496         struct ipaddr_str oldbuf, newbuf;
497 #endif
498         OLSR_DEBUG(LOG_LINKS, "Neighbor changed main_ip, updating %s -> %s\n",
499                    olsr_ip_to_string(&oldbuf, &link->neighbor->nbr_addr), olsr_ip_to_string(&newbuf, remote_main));
500         link->neighbor->nbr_addr = *remote_main;
501       }
502       return link;
503     }
504   }
505
506   return NULL;
507 }
508
509 /**
510  * Update a link entry. This is the "main entrypoint" in
511  * the link-sensing. This function is called from the HELLO
512  * parser function. It makes sure a entry is updated or created.
513  *
514  * @param local the local IP address
515  * @param remote the remote IP address
516  * @param message the HELLO message
517  * @param in_if the interface on which this HELLO was received
518  * @return the link_entry struct describing this link entry
519  */
520 struct link_entry *
521 update_link_entry(const union olsr_ip_addr *local,
522                   const union olsr_ip_addr *remote, struct lq_hello_message *message, struct interface *in_if)
523 {
524   struct link_entry *entry;
525
526   /* Add if not registered */
527   entry = add_link_entry(local, remote, &message->comm->originator, message->comm->vtime, message->htime, in_if);
528
529   /* Update ASYM_time */
530   entry->vtime = message->comm->vtime;
531   entry->ASYM_time = olsr_timer_getAbsolute(message->comm->vtime);
532
533   entry->status = check_link_status(message, in_if);
534
535   switch (entry->status) {
536   case (LOST_LINK):
537     olsr_timer_stop(entry->link_sym_timer);
538     entry->link_sym_timer = NULL;
539     break;
540   case (SYM_LINK):
541   case (ASYM_LINK):
542
543     /* L_SYM_time = current time + validity time */
544     olsr_timer_set(&entry->link_sym_timer, message->comm->vtime,
545                    OLSR_LINK_SYM_JITTER, entry, link_sym_timer_info);
546
547     /* L_time = L_SYM_time + NEIGHB_HOLD_TIME */
548     olsr_set_link_timer(entry, message->comm->vtime + NEIGHB_HOLD_TIME);
549     break;
550   default:;
551   }
552
553   /* L_time = max(L_time, L_ASYM_time) */
554   if (entry->link_timer && (entry->link_timer->timer_clock < entry->ASYM_time)) {
555     olsr_set_link_timer(entry, olsr_timer_getRelative(entry->ASYM_time));
556   }
557
558   /* Update neighbor */
559   olsr_update_nbr_status(entry->neighbor);
560
561   return entry;
562 }
563
564
565 /**
566  * Function that updates all registered pointers to
567  * one neighbor entry with another pointer
568  * Used by MID updates.
569  *
570  * @old the pointer to replace
571  * @new the pointer to use instead of "old"
572  * @return the number of entries updated
573  */
574 int
575 replace_neighbor_link_set(const struct nbr_entry *old, struct nbr_entry *new)
576 {
577   struct link_entry *link, *iterator;
578   int retval = 0;
579
580   if (list_is_empty(&link_entry_head)) {
581     return retval;
582   }
583
584   OLSR_FOR_ALL_LINK_ENTRIES(link, iterator) {
585     if (link->neighbor == old) {
586       link->neighbor = new;
587       retval++;
588     }
589   }
590
591   return retval;
592 }
593
594
595 /**
596  *Checks the link status to a neighbor by
597  *looking in a received HELLO message.
598  *
599  *@param message the HELLO message to check
600  *
601  *@return the link status
602  */
603 static int
604 check_link_status(const struct lq_hello_message *message, const struct interface *in_if)
605 {
606   int ret = UNSPEC_LINK;
607   struct lq_hello_neighbor *neighbors;
608
609   neighbors = message->neigh;
610   while (neighbors) {
611
612     /*
613      * Note: If a neigh has 2 cards we can reach, the neigh
614      * will send a Hello with the same IP mentined twice
615      */
616     if (olsr_ipcmp(&neighbors->addr, &in_if->ip_addr) == 0
617         && neighbors->link_type != UNSPEC_LINK) {
618       ret = neighbors->link_type;
619       if (SYM_LINK == ret) {
620         break;
621       }
622     }
623     neighbors = neighbors->next;
624   }
625
626   return ret;
627 }
628
629 void
630 olsr_print_link_set(void)
631 {
632 #if !defined REMOVE_LOG_INFO
633   /* The whole function makes no sense without it. */
634   struct link_entry *walker, *iterator;
635   char totaltxt[256] = { 0 };
636   const char *txt;
637   int addrsize;
638   struct timeval_buf timebuf;
639   size_t i, j, length, max, totaltxt_len;
640   addrsize = olsr_cnf->ip_version == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
641
642   /* generate LQ headline */
643   totaltxt[0] = 0;
644   totaltxt_len = 0;
645   for (i=1; i<olsr_get_linklabel_count(); i++) {
646     txt = olsr_get_linklabel(i);
647     max = olsr_get_linklabel_maxlength(i);
648
649     length = strlen(txt);
650
651     /* add seperator */
652     if (i != 1) {
653       totaltxt[totaltxt_len++] = '/';
654     }
655
656     /* reserve space for label */
657     if (max > length) {
658       for (j=0; j<max; j++) {
659         totaltxt[totaltxt_len + j] = '-';
660       }
661     }
662
663     /* copy label */
664     strncpy(&totaltxt[totaltxt_len + max/2 - length/2], txt, length);
665     totaltxt_len += max;
666   }
667   totaltxt[totaltxt_len] = 0;
668
669   OLSR_INFO(LOG_LINKS, "\n--- %s ---------------------------------------------------- LINKS\n\n",
670       olsr_timer_getWallclockString(&timebuf));
671   OLSR_INFO_NH(LOG_LINKS, "%-*s  %-6s %s %s\n", addrsize, "IP address", "hyst", totaltxt , olsr_get_linklabel(0));
672
673   OLSR_FOR_ALL_LINK_ENTRIES(walker, iterator) {
674     struct ipaddr_str buf;
675     char lqbuffer[LQTEXT_MAXLENGTH];
676
677     /* generate LQ headline */
678     totaltxt[0] = 0;
679     totaltxt_len = 0;
680     for (i=1; i<olsr_get_linklabel_count(); i++) {
681       txt = olsr_get_linkdata_text(walker, i, lqbuffer, sizeof(lqbuffer));
682       max = olsr_get_linklabel_maxlength(i);
683
684       length = strlen(txt);
685
686       /* add seperator */
687       if (i != 1) {
688         totaltxt[totaltxt_len++] = '/';
689       }
690
691       /* reserve space for label */
692       if (max > length) {
693         for (j=0; j<max; j++) {
694           totaltxt[totaltxt_len + j] = ' ';
695         }
696       }
697
698       /* copy label */
699       strncpy(&totaltxt[totaltxt_len + max/2 - length/2], txt, length);
700       totaltxt_len += max;
701     }
702     totaltxt[totaltxt_len] = 0;
703     OLSR_INFO_NH(LOG_LINKS, "%-*s %s %s\n",
704                  addrsize, olsr_ip_to_string(&buf, &walker->neighbor_iface_addr),
705                  totaltxt, olsr_get_linkcost_text(walker->linkcost, false, lqbuffer, sizeof(lqbuffer)));
706   }
707 #endif
708 }
709
710 /*
711  * called for every LQ HELLO message.
712  * update the timeout with the htime value from the message
713  */
714 void
715 olsr_update_packet_loss_hello_int(struct link_entry *entry, uint32_t loss_hello_int)
716 {
717   entry->loss_helloint = loss_hello_int;
718 }
719
720 void
721 olsr_update_packet_loss(struct link_entry *entry)
722 {
723   olsr_lq_hello_handler(entry, false);
724
725   /* timeout for the first lost packet is 1.5 x htime */
726   olsr_timer_set(&entry->link_loss_timer, entry->loss_helloint + entry->loss_helloint / 2,
727                  OLSR_LINK_LOSS_JITTER, entry, link_loss_timer_info);
728 }
729
730 void
731 generate_hello(void *p) {
732   struct interface *ifp = p;
733   uint8_t msg_buffer[MAXMESSAGESIZE - OLSR_HEADERSIZE] __attribute__ ((aligned));
734   struct olsr_message msg;
735   uint8_t *curr = msg_buffer;
736   uint8_t *length_field, *last;
737   struct link_entry *link, *iterator;
738   uint8_t writeLinkType, writeNeighType;
739   OLSR_INFO(LOG_PACKET_CREATION, "Building Hello for %s\n-------------------\n", ifp->int_name);
740
741   msg.type = olsr_get_Hello_MessageId();
742   msg.vtime = ifp->hello_validity;
743   msg.size = 0; /* fill in later */
744   msg.originator = olsr_cnf->router_id;
745   msg.ttl = 1;
746   msg.hopcnt = 0;
747   msg.seqno = get_msg_seqno();
748
749   length_field = olsr_put_msg_hdr(&curr, &msg);
750
751   pkt_put_u16(&curr, 0);
752   pkt_put_reltime(&curr, ifp->hello_interval);
753   pkt_put_u8(&curr, olsr_cnf->willingness);
754
755   last = msg_buffer + sizeof(msg_buffer) - olsr_cnf->ipsize;
756
757   /* first calculate local link status */
758   OLSR_FOR_ALL_LINK_ENTRIES(link, iterator) {
759     if (olsr_ipcmp(&link->local_iface_addr, &ifp->ip_addr) != 0) {
760       link->iflocal_link_status = UNSPEC_LINK;
761     }
762     else {
763       link->iflocal_link_status = lookup_link_status(link);
764     }
765
766     if (link->neighbor->is_mpr) {
767       link->iflocal_neigh_status = MPR_NEIGH;
768     }
769     else if (link->neighbor->is_sym) {
770       link->iflocal_neigh_status = SYM_NEIGH;
771     }
772     else {
773       link->iflocal_neigh_status = NOT_NEIGH;
774     }
775   }
776
777   for (writeNeighType = 0; writeNeighType < COUNT_NEIGH_TYPES; writeNeighType++) {
778     for (writeLinkType = 0; writeLinkType < COUNT_LINK_TYPES; writeLinkType++) {
779       bool first = true;
780       uint8_t *linkstart = NULL;
781
782       OLSR_FOR_ALL_LINK_ENTRIES(link, iterator) {
783         if (link->iflocal_link_status != writeLinkType
784             || link->iflocal_neigh_status != writeNeighType) {
785           continue;
786         }
787
788         if (first) {
789           pkt_put_u8(&curr, CREATE_LINK_CODE(writeNeighType, writeLinkType));
790           pkt_put_u8(&curr, 0);
791           first = false;
792
793           /* put in dummy length */
794           linkstart = curr;
795           pkt_put_u16(&curr, 0);
796         }
797
798         pkt_put_ipaddress(&curr, &link->neighbor_iface_addr);
799         olsr_serialize_hello_lq_pair(&curr, link);
800       }
801
802       /* fix length field of hello block */
803       if (linkstart != NULL) {
804         pkt_put_u16(&linkstart, (uint16_t)(curr + 2 - linkstart));
805       }
806     }
807   }
808
809   /* fix length field of message */
810   pkt_put_u16(&length_field, curr - msg_buffer);
811
812   /* send hello immediately */
813   if (net_outbuffer_bytes_left(ifp) < curr - msg_buffer) {
814     net_output(ifp);
815   }
816   net_outbuffer_push(ifp, msg_buffer, curr - msg_buffer);
817   net_output(ifp);
818 }
819 /*
820  * Local Variables:
821  * c-basic-offset: 2
822  * indent-tabs-mode: nil
823  * End:
824  */