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