c5ddcabd0a08b9f3c547a4dbb729217c5af29d9b
[olsrd.git] / src / link_set.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Andreas T√łnnesen(andreto@olsr.org)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright 
11  *   notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright 
13  *   notice, this list of conditions and the following disclaimer in 
14  *   the documentation and/or other materials provided with the 
15  *   distribution.
16  * * Neither the name of olsr.org, olsrd nor the names of its 
17  *   contributors may be used to endorse or promote products derived 
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Visit http://www.olsr.org for more information.
34  *
35  * If you find this software useful feel free to make a donation
36  * to the project. For more information see the website or contact
37  * the copyright holders.
38  *
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 "hysteresis.h"
49 #include "mid_set.h"
50 #include "mpr.h"
51 #include "neighbor_table.h"
52 #include "olsr.h"
53 #include "scheduler.h"
54 #include "lq_route.h"
55 #include "net_olsr.h"
56 #include "ipcalc.h"
57 #include "lq_plugin.h"
58
59 /* head node for all link sets */
60 struct list_node link_entry_head;
61
62 olsr_bool link_changes; /* is set if changes occur in MPRS set */ 
63
64 void
65 signal_link_changes(olsr_bool val) /* XXX ugly */
66 {
67   link_changes = val;
68 }
69
70 static int
71 check_link_status(const struct hello_message *message, const struct interface *in_if);
72
73 static struct link_entry *
74 add_link_entry(const union olsr_ip_addr *, const union olsr_ip_addr *, const union olsr_ip_addr *, double, double, const struct interface *);
75
76 static int
77 get_neighbor_status(const union olsr_ip_addr *);
78
79 void
80 olsr_init_link_set(void)
81 {
82
83   /* Init list head */
84   list_head_init(&link_entry_head);
85 }
86
87
88 /**
89  * Get the status of a link. The status is based upon different
90  * timeouts in the link entry.
91  *
92  *@param remote address of the remote interface
93  *
94  *@return the link status of the link
95  */
96 int
97 lookup_link_status(const struct link_entry *entry)
98 {
99
100   if(entry == NULL || list_is_empty(&link_entry_head)) {
101     return UNSPEC_LINK;
102   }
103
104   /*
105    * Hysteresis
106    */
107   if(olsr_cnf->use_hysteresis)
108     {
109       /*
110         if L_LOST_LINK_time is not expired, the link is advertised
111         with a link type of LOST_LINK.
112       */
113
114       if(!TIMED_OUT(entry->L_LOST_LINK_time))
115         return LOST_LINK;
116       /*
117         otherwise, if L_LOST_LINK_time is expired and L_link_pending
118         is set to "true", the link SHOULD NOT be advertised at all;
119       */
120       if(entry->L_link_pending == 1)
121         {
122 #ifndef NODEBUG
123           struct ipaddr_str buf;
124           OLSR_PRINTF(3, "HYST[%s]: Setting to HIDE\n", olsr_ip_to_string(&buf, &entry->neighbor_iface_addr));
125 #endif
126           return HIDE_LINK;
127         }
128       /*
129         otherwise, if L_LOST_LINK_time is expired and L_link_pending
130         is set to "false", the link is advertised as described
131         previously in section 6.
132       */
133     }
134
135   if (entry->link_sym_timer) {
136     return SYM_LINK;
137   }
138
139   if(!TIMED_OUT(entry->ASYM_time))
140     return ASYM_LINK;
141
142   return LOST_LINK;
143
144
145 }
146
147
148 /**
149  *Find the "best" link status to a
150  *neighbor
151  *
152  *@param address the address to check for
153  *
154  *@return SYM_LINK if a symmetric link exists 0 if not
155  */
156 static int
157 get_neighbor_status(const union olsr_ip_addr *address)
158 {
159   const union olsr_ip_addr *main_addr;
160   struct interface   *ifs;
161
162   //printf("GET_NEIGHBOR_STATUS\n");
163
164   /* Find main address */
165   if(!(main_addr = mid_lookup_main_addr(address)))
166     main_addr = address;
167
168   //printf("\tmain: %s\n", olsr_ip_to_string(main_addr));
169
170   /* Loop trough local interfaces to check all possebilities */
171   for(ifs = ifnet; ifs != NULL; ifs = ifs->int_next)
172     {
173       struct mid_address   *aliases;
174       struct link_entry  *lnk = lookup_link_entry(main_addr, NULL, ifs);
175
176       //printf("\tChecking %s->", olsr_ip_to_string(&ifs->ip_addr));
177       //printf("%s : ", olsr_ip_to_string(main_addr)); 
178       if(lnk != NULL)
179         {
180           //printf("%d\n", lookup_link_status(link));
181           if(lookup_link_status(lnk) == SYM_LINK)
182             return SYM_LINK;
183         }
184       /* Get aliases */
185       for(aliases = mid_lookup_aliases(main_addr);
186           aliases != NULL;
187           aliases = aliases->next_alias)
188         {
189           //printf("\tChecking %s->", olsr_ip_to_string(&ifs->ip_addr));
190           //printf("%s : ", olsr_ip_to_string(&aliases->address)); 
191             lnk = lookup_link_entry(&aliases->alias, NULL, ifs);
192             if(lnk != NULL)
193             {
194               //printf("%d\n", lookup_link_status(link));
195
196               if(lookup_link_status(lnk) == SYM_LINK)
197                 return SYM_LINK;
198             }
199         }
200     }
201   
202   return 0;
203 }
204
205 /**
206  * Find best link to a neighbor
207  */
208
209 struct link_entry *
210 get_best_link_to_neighbor(const union olsr_ip_addr *remote)
211 {
212   const union olsr_ip_addr *main_addr;
213   struct link_entry *walker, *good_link, *backup_link;
214   int curr_metric = MAX_IF_METRIC;
215   olsr_linkcost curr_lcost = LINK_COST_BROKEN;
216   
217   // main address lookup
218
219   main_addr = mid_lookup_main_addr(remote);
220
221   // "remote" *already is* the main address
222
223   if (main_addr == NULL)
224     main_addr = remote;
225
226   // we haven't selected any links, yet
227
228   good_link = NULL;
229   backup_link = NULL;
230
231   // loop through all links that we have
232
233   OLSR_FOR_ALL_LINK_ENTRIES(walker) {
234
235     /* if this is not a link to the neighour in question, skip */
236     if (!ipequal(&walker->neighbor->neighbor_main_addr, main_addr))
237       continue;
238
239     // handle the non-LQ, RFC-compliant case
240
241     if (olsr_cnf->lq_level == 0)
242     {
243       struct interface *tmp_if;
244
245       // find the interface for the link - we select the link with the
246       // best local interface metric
247       tmp_if = walker->if_name ? if_ifwithname(walker->if_name) :
248               if_ifwithaddr(&walker->local_iface_addr);
249
250       if(!tmp_if)
251         continue;
252
253       // is this interface better than anything we had before?
254
255       if ((tmp_if->int_metric < curr_metric) ||
256           // use the requested remote interface address as a tie-breaker
257           ((tmp_if->int_metric == curr_metric) && 
258            ipequal(&walker->local_iface_addr, remote)))
259       {
260         // memorize the interface's metric
261
262         curr_metric = tmp_if->int_metric;
263
264         // prefer symmetric links over asymmetric links
265
266         if (lookup_link_status(walker) == SYM_LINK)
267           good_link = walker;
268
269         else
270           backup_link = walker;
271       }
272     }
273
274     // handle the LQ, non-RFC compliant case
275
276     else
277     {
278       olsr_linkcost tmp_lc;
279
280       // get the link cost
281
282       tmp_lc = walker->linkcost; 
283
284       // is this link better than anything we had before?
285               
286       if((tmp_lc < curr_lcost) ||
287          // use the requested remote interface address as a tie-breaker
288          ((tmp_lc == curr_lcost) && ipequal(&walker->local_iface_addr, remote)))
289       {
290         // memorize the link quality
291
292         curr_lcost = tmp_lc;
293
294         // prefer symmetric links over asymmetric links
295
296         if(lookup_link_status(walker) == SYM_LINK)
297           good_link = walker;
298
299         else
300           backup_link = walker;
301       }
302     }
303   } OLSR_FOR_ALL_LINK_ENTRIES_END(walker);
304
305   // if we haven't found any symmetric links, try to return an
306   // asymmetric link
307
308   return good_link ? good_link : backup_link;
309 }
310
311 static void set_loss_link_multiplier(struct link_entry *entry)
312 {
313   struct interface *inter;
314   struct olsr_if *cfg_inter;
315   struct olsr_lq_mult *mult;
316   float val = -1.0;
317   union olsr_ip_addr null_addr;
318
319   // find the interface for the link
320
321   inter = if_ifwithaddr(&entry->local_iface_addr);
322
323   // find the interface configuration for the interface
324
325   for (cfg_inter = olsr_cnf->interfaces; cfg_inter != NULL;
326        cfg_inter = cfg_inter->next)
327     if (cfg_inter->interf == inter)
328       break;
329
330   // create a null address for comparison
331
332   memset(&null_addr, 0, sizeof (union olsr_ip_addr));
333
334   // loop through the multiplier entries
335
336   for (mult = cfg_inter->cnf->lq_mult; mult != NULL; mult = mult->next)
337   {
338     // use the default multiplier only if there isn't any entry that
339     // has a matching IP address
340
341     if ((ipequal(&mult->addr, &null_addr) && val < 0.0) ||
342         ipequal(&mult->addr, &entry->neighbor_iface_addr))
343       val = mult->val;
344   }
345
346   // if we have not found an entry, then use the default multiplier
347
348   if (val < 0)
349     val = 1.0;
350
351   // store the multiplier
352
353   entry->loss_link_multiplier = (olsr_u32_t)(val * 65536);
354 }
355
356 /*
357  * Delete, unlink and free a link entry.
358  */
359 static void
360 olsr_delete_link_entry(struct link_entry *link)
361 {
362
363   /* Delete neighbor entry */
364   if (link->neighbor->linkcount == 1) {
365     olsr_delete_neighbor_table(&link->neighbor->neighbor_main_addr);
366   } else {
367     link->neighbor->linkcount--;
368   }
369
370   /* Kill running timers */
371   olsr_stop_timer(link->link_timer);
372   link->link_timer = NULL;
373   olsr_stop_timer(link->link_sym_timer);
374   link->link_sym_timer = NULL;
375   olsr_stop_timer(link->link_hello_timer);
376   link->link_hello_timer = NULL;
377   olsr_stop_timer(link->link_loss_timer);
378   link->link_loss_timer = NULL;
379
380   list_remove(&link->link_list);
381
382   free(link->if_name);
383   free(link);
384
385   changes_neighborhood = OLSR_TRUE;
386 }
387
388 void
389 olsr_delete_link_entry_by_ip(const union olsr_ip_addr *int_addr)
390 {
391   struct link_entry *link;
392
393   if (list_is_empty(&link_entry_head)) {
394     return;
395   }
396
397   OLSR_FOR_ALL_LINK_ENTRIES(link) {
398     if (ipequal(int_addr, &link->local_iface_addr)) {
399       olsr_delete_link_entry(link);
400     }
401   } OLSR_FOR_ALL_LINK_ENTRIES_END(link);
402 }
403
404 /**
405  * Callback for the link loss timer.
406  */
407 static void
408 olsr_expire_link_loss_timer(void *context)
409 {
410   struct link_entry *link;
411   
412   link = (struct link_entry *)context;
413
414   /* count the lost packet */
415   olsr_update_packet_loss_worker(link, OLSR_TRUE);
416
417   /* next timeout in 1.0 x htime */
418   olsr_change_timer(link->link_loss_timer, link->loss_hello_int * MSEC_PER_SEC,
419                     OLSR_LINK_LOSS_JITTER, OLSR_TIMER_PERIODIC);
420 }
421
422 /**
423  * Callback for the link SYM timer.
424  */
425 static void
426 olsr_expire_link_sym_timer(void *context)
427 {
428   struct link_entry *link;
429
430   link = (struct link_entry *)context;
431   link->link_sym_timer = NULL; /* be pedandic */
432
433   if (link->prev_status != SYM_LINK) {
434     return;
435   } 
436
437   link->prev_status = lookup_link_status(link);
438   update_neighbor_status(link->neighbor,
439                          get_neighbor_status(&link->neighbor_iface_addr));
440   changes_neighborhood = OLSR_TRUE;
441 }
442
443 /**
444  * Callback for the link_hello timer.
445  */
446 void
447 olsr_expire_link_hello_timer(void *context)
448 {
449 #ifndef NODEBUG
450   struct ipaddr_str buf;
451 #endif
452   struct link_entry *link;
453
454   link = (struct link_entry *)context;
455
456   link->L_link_quality = olsr_hyst_calc_instability(link->L_link_quality);
457
458   OLSR_PRINTF(1, "HYST[%s] HELLO timeout %f\n",
459               olsr_ip_to_string(&buf, &link->neighbor_iface_addr),
460               link->L_link_quality);
461
462   /* Update hello_timeout - NO SLACK THIS TIME */
463   olsr_change_timer(link->link_hello_timer, link->last_htime * MSEC_PER_SEC,
464                     OLSR_LINK_JITTER, OLSR_TIMER_PERIODIC);
465
466   /* Update hysteresis values */
467   olsr_process_hysteresis(link);
468           
469   /* update neighbor status */
470   update_neighbor_status(link->neighbor,
471                          get_neighbor_status(&link->neighbor_iface_addr));
472
473   /* Update seqno - not mentioned in the RFC... kind of a hack.. */
474   link->olsr_seqno++;
475 }
476
477 /**
478  * Callback for the link timer.
479  */
480 static void
481 olsr_expire_link_entry(void *context)
482 {
483   struct link_entry *link;
484
485   link = (struct link_entry *)context;
486   link->link_timer = NULL; /* be pedandic */
487
488   olsr_delete_link_entry(link);
489 }
490
491 /**
492  * Set the link expiration timer.
493  */
494 void
495 olsr_set_link_timer(struct link_entry *link, unsigned int rel_timer)
496 {
497   olsr_set_timer(&link->link_timer, rel_timer, OLSR_LINK_JITTER,
498                  OLSR_TIMER_ONESHOT, &olsr_expire_link_entry, link, 0);
499 }
500
501 /**
502  *Nothing mysterious here.
503  *Adding a new link entry to the link set.
504  *
505  *@param local the local IP address
506  *@param remote the remote IP address
507  *@param remote_main the remote nodes main address
508  *@param vtime the validity time of the entry
509  *@param htime the HELLO interval of the remote node
510  *@param local_if the local interface
511  */
512
513 static struct link_entry *
514 add_link_entry(const union olsr_ip_addr *local,
515                const union olsr_ip_addr *remote,
516                const union olsr_ip_addr *remote_main,
517                double vtime,
518                double htime,
519                const struct interface *local_if)
520 {
521   struct link_entry *new_link;
522   struct neighbor_entry *neighbor;
523   struct link_entry *tmp_link_set = lookup_link_entry(remote, remote_main, local_if);
524   if (tmp_link_set) {
525     return tmp_link_set;
526   }
527
528   /*
529    * if there exists no link tuple with
530    * L_neighbor_iface_addr == Source Address
531    */
532
533 #ifdef DEBUG
534   {
535 #ifndef NODEBUG
536     struct ipaddr_str localbuf, rembuf;
537 #endif
538     OLSR_PRINTF(1, "Adding %s=>%s to link set\n", olsr_ip_to_string(&localbuf, local), olsr_ip_to_string(&rembuf, remote));
539   }
540 #endif
541
542   /* a new tuple is created with... */
543
544   new_link = olsr_malloc_link_entry("new link entry");
545   
546   /* copy if_name, if it is defined */
547   if (local_if->int_name)
548     {
549       new_link->if_name = olsr_malloc(strlen(local_if->int_name)+1, "target of if_name in new link entry");
550       strcpy(new_link->if_name, local_if->int_name);
551     } else 
552       new_link->if_name = NULL;
553
554   /* shortcut to interface. XXX refcount */
555   new_link->inter = local_if;
556
557   /*
558    * L_local_iface_addr = Address of the interface
559    * which received the HELLO message
560    */
561   //printf("\tLocal IF: %s\n", olsr_ip_to_string(local));
562   new_link->local_iface_addr = *local;
563   /* L_neighbor_iface_addr = Source Address */
564   new_link->neighbor_iface_addr = *remote;
565
566   /* L_time = current time + validity time */
567   olsr_set_link_timer(new_link, vtime * MSEC_PER_SEC);
568
569   new_link->prev_status = ASYM_LINK;
570
571   /* HYSTERESIS */
572   if(olsr_cnf->use_hysteresis)
573     {
574       new_link->L_link_pending = 1;
575       new_link->L_LOST_LINK_time = GET_TIMESTAMP(vtime*1000);
576       olsr_update_hysteresis_hello(new_link, htime);
577       new_link->last_htime = htime;
578       new_link->olsr_seqno = 0;
579       new_link->olsr_seqno_valid = OLSR_FALSE;
580     }
581
582   new_link->L_link_quality = 0.0;
583
584   if (olsr_cnf->lq_level > 0)
585     {
586       new_link->loss_hello_int = htime;
587
588       olsr_set_timer(&new_link->link_loss_timer, htime * 1500,
589                      OLSR_LINK_LOSS_JITTER, OLSR_TIMER_PERIODIC,
590                      &olsr_expire_link_loss_timer, new_link, 0);
591
592       set_loss_link_multiplier(new_link);
593     }
594
595   new_link->linkcost = LINK_COST_BROKEN;
596
597   /* Add to queue */
598   list_add_before(&link_entry_head, &new_link->link_list);
599
600   /*
601    * Create the neighbor entry
602    */
603
604   /* Neighbor MUST exist! */
605   neighbor = olsr_lookup_neighbor_table(remote_main);
606   if(neighbor == NULL)
607     {
608 #ifdef DEBUG
609 #ifndef NODEBUG
610       struct ipaddr_str buf;
611 #endif
612       OLSR_PRINTF(3, "ADDING NEW NEIGHBOR ENTRY %s FROM LINK SET\n", olsr_ip_to_string(&buf, remote_main));
613 #endif
614       neighbor = olsr_insert_neighbor_table(remote_main);
615     }
616
617   neighbor->linkcount++;
618   new_link->neighbor = neighbor;
619
620   return new_link;
621 }
622
623
624 /**
625  * Lookup the status of a link.
626  *
627  * @param int_addr address of the remote interface
628  * @return 1 of the link is symmertic 0 if not
629  */
630 int
631 check_neighbor_link(const union olsr_ip_addr *int_addr)
632 {
633   struct link_entry *link;
634
635   OLSR_FOR_ALL_LINK_ENTRIES(link) {
636     if (ipequal(int_addr, &link->neighbor_iface_addr))
637       return lookup_link_status(link);
638   } OLSR_FOR_ALL_LINK_ENTRIES_END(link);
639
640   return UNSPEC_LINK;
641 }
642
643
644 /**
645  *Lookup a link entry
646  *
647  *@param remote the remote interface address
648  *@param remote_main the remote nodes main address
649  *@param local the local interface address
650  *
651  *@return the link entry if found, NULL if not
652  */
653 struct link_entry *
654 lookup_link_entry(const union olsr_ip_addr *remote,
655                   const union olsr_ip_addr *remote_main,
656                   const struct interface *local)
657 {
658   struct link_entry *link;
659
660   OLSR_FOR_ALL_LINK_ENTRIES(link) {
661     if(ipequal(remote, &link->neighbor_iface_addr) &&
662        (link->if_name ? !strcmp(link->if_name, local->int_name)
663         : ipequal(&local->ip_addr, &link->local_iface_addr)) &&
664
665        /* check the remote-main address only if there is one given */
666        (!remote_main || ipequal(remote_main, &link->neighbor->neighbor_main_addr))) {
667       return link;
668     }
669   } OLSR_FOR_ALL_LINK_ENTRIES_END(link);
670
671   return NULL;
672 }
673
674
675
676
677
678
679
680 /**
681  *Update a link entry. This is the "main entrypoint" in
682  *the link-sensing. This function is called from the HELLO
683  *parser function.
684  *It makes sure a entry is updated or created.
685  *
686  *@param local the local IP address
687  *@param remote the remote IP address
688  *@param message the HELLO message
689  *@param in_if the interface on which this HELLO was received
690  *
691  *@return the link_entry struct describing this link entry
692  */
693 struct link_entry *
694 update_link_entry(const union olsr_ip_addr *local, 
695                   const union olsr_ip_addr *remote, 
696                   const struct hello_message *message, 
697                   const struct interface *in_if)
698 {
699   struct link_entry *entry;
700
701   /* Add if not registered */
702   entry = add_link_entry(local, remote, &message->source_addr, message->vtime, message->htime, in_if);
703
704   /* Update ASYM_time */
705   //printf("Vtime is %f\n", message->vtime);
706   /* L_ASYM_time = current time + validity time */
707   entry->vtime = message->vtime;
708   entry->ASYM_time = GET_TIMESTAMP(message->vtime*1000);
709   
710   entry->prev_status = check_link_status(message, in_if);
711   
712   //printf("Status %d\n", status);
713   
714   switch(entry->prev_status)
715     {
716     case(LOST_LINK):
717       olsr_stop_timer(entry->link_sym_timer);
718       entry->link_sym_timer = NULL;
719       break;
720     case(SYM_LINK):
721     case(ASYM_LINK):
722       /* L_SYM_time = current time + validity time */
723       olsr_set_timer(&entry->link_sym_timer, message->vtime * MSEC_PER_SEC,
724                      OLSR_LINK_SYM_JITTER, OLSR_TIMER_ONESHOT,
725                      &olsr_expire_link_sym_timer, entry, 0);
726
727       /* L_time = L_SYM_time + NEIGHB_HOLD_TIME */
728       olsr_set_link_timer(entry, (message->vtime + NEIGHB_HOLD_TIME) *
729                           MSEC_PER_SEC);
730       break;
731     default:;
732     }
733
734   /* L_time = max(L_time, L_ASYM_time) */
735   if(entry->link_timer && (entry->link_timer->timer_clock < entry->ASYM_time)) {
736     olsr_set_link_timer(entry, TIME_DUE(entry->ASYM_time));
737   }
738
739
740   /*
741   printf("Updating link LOCAL: %s ", olsr_ip_to_string(local));
742   printf("REMOTE: %s\n", olsr_ip_to_string(remote));
743   printf("VTIME: %f ", message->vtime);
744   printf("STATUS: %d\n", status);
745   */
746
747   /* Update hysteresis values */
748   if(olsr_cnf->use_hysteresis)
749     olsr_process_hysteresis(entry);
750
751   /* Update neighbor */
752   update_neighbor_status(entry->neighbor, get_neighbor_status(remote));
753
754   return entry;  
755 }
756
757
758 /**
759  * Fuction that updates all registered pointers to
760  * one neighbor entry with another pointer
761  * Used by MID updates.
762  *
763  *@old the pointer to replace
764  *@new the pointer to use instead of "old"
765  *
766  *@return the number of entries updated
767  */
768 int
769 replace_neighbor_link_set(const struct neighbor_entry *old,
770                           struct neighbor_entry *new)
771 {
772   struct link_entry *link;
773   int retval = 0;
774
775   if (list_is_empty(&link_entry_head)) {
776     return retval;
777   }
778       
779   OLSR_FOR_ALL_LINK_ENTRIES(link) {
780
781     if (link->neighbor == old) {
782       link->neighbor = new;
783       retval++;
784     }
785   } OLSR_FOR_ALL_LINK_ENTRIES_END(link);
786
787   return retval;
788 }
789
790
791 /**
792  *Checks the link status to a neighbor by
793  *looking in a received HELLO message.
794  *
795  *@param message the HELLO message to check
796  *
797  *@return the link status
798  */
799 static int
800 check_link_status(const struct hello_message *message, const struct interface *in_if)
801 {
802   int ret = UNSPEC_LINK;
803   struct hello_neighbor  *neighbors;
804
805   neighbors = message->neighbors;
806   
807   while(neighbors!=NULL)
808     {
809       /*
810        * Note: If a neigh has 2 cards we can reach, the neigh
811        * will send a Hello with the same IP mentined twice
812        */
813       if(ipequal(&neighbors->address, &in_if->ip_addr))
814         {
815           //printf("ok");
816           ret = neighbors->link;
817           if (SYM_LINK == ret) break;
818         }
819
820       neighbors = neighbors->next; 
821     }
822
823
824   return ret;
825 }
826
827 void olsr_print_link_set(void)
828 {
829 #ifndef NODEBUG
830   /* The whole function makes no sense without it. */
831   struct link_entry *walker;
832   const int addrsize = olsr_cnf->ip_version == AF_INET ? 15 : 39;
833
834   OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- LINKS\n\n",
835               olsr_wallclock_string());
836   OLSR_PRINTF(1, "%-*s  %-6s %-14s %s\n", addrsize,
837               "IP address", "hyst", "      LQ      ", "ETX");
838
839   OLSR_FOR_ALL_LINK_ENTRIES(walker) {
840
841     struct ipaddr_str buf;
842     struct lqtextbuffer lqbuffer1, lqbuffer2;
843     OLSR_PRINTF(1, "%-*s  %5.3f  %-14s %s\n",
844                 addrsize, olsr_ip_to_string(&buf, &walker->neighbor_iface_addr),
845                 walker->L_link_quality,
846                 get_link_entry_text(walker, &lqbuffer1),
847                 get_linkcost_text(walker->linkcost, OLSR_FALSE, &lqbuffer2));
848   } OLSR_FOR_ALL_LINK_ENTRIES_END(walker);
849 #endif
850 }
851
852 void olsr_update_packet_loss_hello_int(struct link_entry *entry,
853                                        double loss_hello_int)
854 {
855   // called for every LQ HELLO message - update the timeout
856   // with the htime value from the message
857
858   entry->loss_hello_int = loss_hello_int;
859 }
860
861 void olsr_update_packet_loss(struct link_entry *entry)
862 {
863   olsr_update_packet_loss_worker(entry, OLSR_FALSE);
864
865   // timeout for the first lost packet is 1.5 x htime
866
867   olsr_set_timer(&entry->link_loss_timer, entry->loss_hello_int * 1500,
868                  OLSR_LINK_LOSS_JITTER, OLSR_TIMER_PERIODIC,
869                  &olsr_expire_link_loss_timer, entry, 0);
870 }
871
872 /*
873  * Local Variables:
874  * c-basic-offset: 2
875  * End:
876  */