Experimental link quality metric based on a link's packet loss. Define
[olsrd.git] / src / link_set.c
1 /*
2  * OLSR ad-hoc routing table management protocol
3  * Copyright (C) 2003 Andreas T√łnnesen (andreto@ifi.uio.no)
4  *
5  * This file is part of the olsr.org OLSR daemon.
6  *
7  * olsr.org is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * olsr.org is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with olsr.org; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  * 
21  * 
22  * $Id: link_set.c,v 1.10 2004/10/20 17:11:33 tlopatic Exp $
23  *
24  */
25
26
27 /*
28  * Link sensing database for the OLSR routing daemon
29  */
30
31 #include "link_set.h"
32 #include "hysteresis.h"
33 #include "mid_set.h"
34 #include "mpr.h"
35 #include "olsr.h"
36 #include "scheduler.h"
37
38 #include "link_layer.h"
39
40
41
42 /* Begin:
43  * Prototypes for internal functions 
44  */
45
46 static int
47 check_link_status(struct hello_message *);
48
49 static void
50 olsr_time_out_hysteresis(void);
51
52 #if defined USE_LINK_QUALITY
53 static void olsr_time_out_packet_loss(void);
54 #endif
55
56 static struct link_entry *
57 add_new_entry(union olsr_ip_addr *, union olsr_ip_addr *, union olsr_ip_addr *, double, double);
58
59 static void
60 olsr_time_out_link_set(void);
61
62 static int
63 get_neighbor_status(union olsr_ip_addr *);
64
65
66 /* End:
67  * Prototypes for internal functions 
68  */
69
70
71
72 void
73 olsr_init_link_set()
74 {
75
76   /* Timers */
77   olsr_init_timer((olsr_u32_t) (NEIGHB_HOLD_TIME*1000), &hold_time_neighbor);
78
79   olsr_register_timeout_function(&olsr_time_out_link_set);
80   if(olsr_cnf->use_hysteresis)
81     {
82       olsr_register_timeout_function(&olsr_time_out_hysteresis);
83     }
84
85 #if defined USE_LINK_QUALITY
86   if (1)
87     {
88       olsr_register_timeout_function(&olsr_time_out_packet_loss);
89     }
90 #endif
91
92   link_set = NULL;
93 }
94
95
96
97 /**
98  * Get the status of a link. The status is based upon different
99  * timeouts in the link entry.
100  *
101  *@param remote address of the remote interface
102  *
103  *@return the link status of the link
104  */
105 int
106 lookup_link_status(struct link_entry *entry)
107 {
108
109   if(entry == NULL || link_set == NULL)
110     {
111       return UNSPEC_LINK;
112     }
113
114   /*
115    * Hysteresis
116    */
117   if(olsr_cnf->use_hysteresis)
118     {
119       /*
120         if L_LOST_LINK_time is not expired, the link is advertised
121         with a link type of LOST_LINK.
122       */
123       if(!TIMED_OUT(&entry->L_LOST_LINK_time))
124         return LOST_LINK;
125       /*
126         otherwise, if L_LOST_LINK_time is expired and L_link_pending
127         is set to "true", the link SHOULD NOT be advertised at all;
128       */
129       if(entry->L_link_pending == 1)
130         {
131 #ifdef DEBUG
132           olsr_printf(3, "HYST[%s]: Setting to HIDE\n", olsr_ip_to_string(&entry->neighbor_iface_addr));
133 #endif
134           return HIDE_LINK;
135         }
136       /*
137         otherwise, if L_LOST_LINK_time is expired and L_link_pending
138         is set to "false", the link is advertised as described
139         previously in section 6.
140       */
141     }
142
143   if(!TIMED_OUT(&entry->SYM_time))
144     return SYM_LINK;
145
146   if(!TIMED_OUT(&entry->ASYM_time))
147     return ASYM_LINK;
148
149   return LOST_LINK;
150
151
152 }
153
154
155
156
157
158
159 /**
160  *Find the "best" link status to a
161  *neighbor
162  *
163  *@param address the address to check for
164  *
165  *@return SYM_LINK if a symmetric link exists 0 if not
166  */
167 static int
168 get_neighbor_status(union olsr_ip_addr *address)
169 {
170   union olsr_ip_addr *main_addr;
171   struct addresses   *aliases;
172   struct link_entry  *link;
173   struct interface   *ifs;
174
175   //printf("GET_NEIGHBOR_STATUS\n");
176
177   /* Find main address */
178   if(!(main_addr = mid_lookup_main_addr(address)))
179     main_addr = address;
180
181   //printf("\tmain: %s\n", olsr_ip_to_string(main_addr));
182
183   /* Loop trough local interfaces to check all possebilities */
184   for(ifs = ifnet; ifs != NULL; ifs = ifs->int_next)
185     {
186       //printf("\tChecking %s->", olsr_ip_to_string(&ifs->ip_addr));
187       //printf("%s : ", olsr_ip_to_string(main_addr)); 
188       if((link = lookup_link_entry(main_addr, &ifs->ip_addr)) != NULL)
189         {
190           //printf("%d\n", lookup_link_status(link));
191           if(lookup_link_status(link) == SYM_LINK)
192             return SYM_LINK;
193         }
194       /* Get aliases */
195       for(aliases = mid_lookup_aliases(main_addr);
196           aliases != NULL;
197           aliases = aliases->next)
198         {
199           //printf("\tChecking %s->", olsr_ip_to_string(&ifs->ip_addr));
200           //printf("%s : ", olsr_ip_to_string(&aliases->address)); 
201           if((link = lookup_link_entry(&aliases->address, &ifs->ip_addr)) != NULL)
202             {
203               //printf("%d\n", lookup_link_status(link));
204
205               if(lookup_link_status(link) == SYM_LINK)
206                 return SYM_LINK;
207             }
208         }
209     }
210   
211   return 0;
212 }
213
214
215
216
217 /**
218  *Get the remote interface address to use as nexthop
219  *to reach the remote host.
220  *
221  *@param address the address of the remote host
222  *@return the nexthop address to use. Returns the pointer
223  *passed as arg 1 if nothing is found(if no MID is registered).
224  */
225 union olsr_ip_addr *
226 get_neighbor_nexthop(union olsr_ip_addr *address)
227 {
228   union olsr_ip_addr *main_addr;
229   struct addresses   *aliases;
230   struct link_entry  *link;
231   struct interface   *ifs;
232
233   //printf("GET_NEIGHBOR_NEXTHOP\n");
234
235   /* Find main address */
236   if(!(main_addr = mid_lookup_main_addr(address)))
237     main_addr = address;
238
239   //printf("\tmain: %s\n", olsr_ip_to_string(main_addr));
240
241   /* Loop trough local interfaces to check all possebilities */
242   for(ifs = ifnet; ifs != NULL; ifs = ifs->int_next)
243     {
244       //printf("\tChecking %s->", olsr_ip_to_string(&ifs->ip_addr));
245       //printf("%s : ", olsr_ip_to_string(main_addr)); 
246       if((link = lookup_link_entry(main_addr, &ifs->ip_addr)) != NULL)
247         {
248           //printf("%d\n", lookup_link_status(link));
249           if(lookup_link_status(link) == SYM_LINK)
250             return main_addr;
251         }
252       /* Get aliases */
253       for(aliases = mid_lookup_aliases(main_addr);
254           aliases != NULL;
255           aliases = aliases->next)
256         {
257           //printf("\tChecking %s->", olsr_ip_to_string(&ifs->ip_addr));
258           //printf("%s : ", olsr_ip_to_string(&aliases->address)); 
259           if((link = lookup_link_entry(&aliases->address, &ifs->ip_addr)) != NULL)
260             {
261               //printf("%d\n", lookup_link_status(link));
262
263               if(lookup_link_status(link) == SYM_LINK)
264                 return &aliases->address;
265             }
266         }
267     }
268   
269   /* This shoud only happen if not MID addresses for the
270    * multi-homed remote host are registered yet
271    */
272   return address;
273 }
274
275
276
277
278 /**
279  *Get the interface to use when setting up
280  *a route to a neighbor. The interface with
281  *the lowest metric is used.
282  *
283  *As this function is only called by the route calculation
284  *functions it is considered that the caller is responsible
285  *for making sure the neighbor is symmetric.
286  *Due to experiences of route calculaition queryig for interfaces
287  *when no links with a valid SYM time is avalibe, the function
288  *will return a possible interface with an expired SYM time
289  *if no SYM links were discovered.
290  *
291  *@param address of the neighbor - does not have to
292  *be the main address
293  *
294  *@return a interface struct representing the interface to use
295  */
296 struct interface *
297 get_interface_link_set(union olsr_ip_addr *remote)
298 {
299   struct link_entry *tmp_link_set;
300   union olsr_ip_addr *remote_addr;
301   struct interface *if_to_use, *tmp_if, *backup_if;
302
303   if_to_use = NULL;
304   backup_if = NULL;
305
306   if(remote == NULL || link_set == NULL)
307     {
308       olsr_printf(1, "Get interface: not sane request or empty link set!\n");
309       return NULL;
310     }
311
312   /* Check for main address of address */
313   if((remote_addr = mid_lookup_main_addr(remote)) == NULL)
314     remote_addr = remote;
315
316   tmp_link_set = link_set;
317   
318   while(tmp_link_set)
319     {
320       //printf("Checking %s vs ", olsr_ip_to_string(&tmp_link_set->neighbor_iface_addr));
321       //printf("%s\n", olsr_ip_to_string(addr));
322       
323       if(COMP_IP(remote_addr, &tmp_link_set->neighbor->neighbor_main_addr) ||
324          COMP_IP(remote_addr, &tmp_link_set->neighbor_iface_addr))
325         {
326
327           tmp_if = if_ifwithaddr(&tmp_link_set->local_iface_addr);
328
329           /* Must be symmetric link! */
330           if(!TIMED_OUT(&tmp_link_set->SYM_time))
331             {
332               if((if_to_use == NULL) || (if_to_use->int_metric > tmp_if->int_metric))
333                 if_to_use = tmp_if;
334             }
335           /* Backup solution in case the links have timed out */
336           else
337             {
338               if((if_to_use == NULL) && ((backup_if == NULL) || (backup_if->int_metric > tmp_if->int_metric)))
339                 {
340                   backup_if = tmp_if;
341                 }
342             }
343         }
344       
345       tmp_link_set = tmp_link_set->next;
346     }
347   
348   /* Not found */
349   if(if_to_use == NULL)
350     return backup_if;
351   
352   return if_to_use;
353 }
354
355
356
357 /**
358  *Nothing mysterious here.
359  *Adding a new link entry to the link set.
360  *
361  *@param local the local IP address
362  *@param remote the remote IP address
363  *@param remote_main teh remote nodes main address
364  *@param vtime the validity time of the entry
365  *@param htime the HELLO interval of the remote node
366  */
367
368 static struct link_entry *
369 add_new_entry(union olsr_ip_addr *local, union olsr_ip_addr *remote, union olsr_ip_addr *remote_main, double vtime, double htime)
370 {
371   struct link_entry *tmp_link_set, *new_link;
372   struct neighbor_entry *neighbor;
373 #ifndef WIN32
374   struct interface *local_if;
375 #endif
376
377   tmp_link_set = link_set;
378
379   while(tmp_link_set)
380     {
381       if(COMP_IP(remote, &tmp_link_set->neighbor_iface_addr))
382         return tmp_link_set;
383       tmp_link_set = tmp_link_set->next;
384     }
385
386   /*
387    * if there exists no link tuple with
388    * L_neighbor_iface_addr == Source Address
389    */
390
391 #ifdef DEBUG
392   olsr_printf(3, "Adding %s to link set\n", olsr_ip_to_string(remote));
393 #endif
394
395   /* a new tuple is created with... */
396
397   new_link = olsr_malloc(sizeof(struct link_entry), "new link entry");
398
399   /*
400    * L_local_iface_addr = Address of the interface
401    * which received the HELLO message
402    */
403   //printf("\tLocal IF: %s\n", olsr_ip_to_string(local));
404   COPY_IP(&new_link->local_iface_addr, local);
405   /* L_neighbor_iface_addr = Source Address */
406   COPY_IP(&new_link->neighbor_iface_addr, remote);
407
408   /* L_SYM_time            = current time - 1 (expired) */
409   new_link->SYM_time = now;
410   /* Subtract 1 */
411   new_link->SYM_time.tv_sec -= 1;
412
413   /* L_time = current time + validity time */
414   olsr_get_timestamp((olsr_u32_t) vtime*1000, &new_link->time);
415
416
417   /* HYSTERESIS */
418   if(olsr_cnf->use_hysteresis)
419     {
420       new_link->L_link_pending = 1;
421       olsr_get_timestamp((olsr_u32_t) vtime*1000, &new_link->L_LOST_LINK_time);
422       olsr_get_timestamp((olsr_u32_t) htime*1500, &new_link->hello_timeout);
423       new_link->last_htime = htime;
424       new_link->olsr_seqno = 0;
425       new_link->L_link_quality = 0;
426     }
427
428 #if defined USE_LINK_QUALITY
429   if (1)
430     {
431       new_link->loss_hello_int = htime;
432
433       olsr_get_timestamp((olsr_u32_t)(htime * 1500.0),
434                          &new_link->loss_timeout);
435
436       new_link->loss_seqno = 0;
437       new_link->loss_seqno_valid = 0;
438       new_link->loss_missed_hellos = 0;
439
440       new_link->lost_packets = 0;
441       new_link->total_packets = 0;
442
443       new_link->loss_window_size = 25;
444       new_link->loss_index = 0;
445
446       memset(new_link->loss_bitmap, 0, sizeof (new_link->loss_bitmap));
447     }
448 #endif
449
450   /* Add to queue */
451   new_link->next = link_set;
452   link_set = new_link;
453
454
455   /*
456    * Create the neighbor entry
457    */
458
459   /* Neighbor MUST exist! */
460   if(NULL == (neighbor = olsr_lookup_neighbor_table(remote_main)))
461     {
462       neighbor = olsr_insert_neighbor_table(remote_main);
463       /* Copy the main address */
464       COPY_IP(&neighbor->neighbor_main_addr, remote_main);
465 #ifdef DEBUG
466       olsr_printf(3, "ADDING NEW NEIGHBOR ENTRY %s FROM LINK SET\n", olsr_ip_to_string(remote_main));
467 #endif
468     }
469
470   neighbor->linkcount++;
471
472
473   new_link->neighbor = neighbor;
474
475   if(!COMP_IP(remote, remote_main))
476     {
477       /* Add MID alias if not already registered */
478       /* This is kind of sketchy... and not specified
479        * in the RFC. We can only guess a vtime.
480        * We'll go for one that is hopefully long
481        * enough in most cases. 20 seconds
482        */
483       olsr_printf(1, "Adding MID alias main %s ", olsr_ip_to_string(remote_main));
484       olsr_printf(1, "-> %s based on HELLO\n\n", olsr_ip_to_string(remote));
485       insert_mid_alias(remote_main, remote, 20.0);
486     }
487
488   /* Add to link-layer spy list */
489 #ifndef WIN32
490   if(llinfo)
491     {
492       local_if = if_ifwithaddr(local);
493       
494       olsr_printf(1, "Adding %s to spylist of interface %s\n", olsr_ip_to_string(remote), local_if->int_name);
495
496       if((local_if != NULL) && (add_spy_node(remote, local_if->int_name)))
497         new_link->spy_activated = 1;
498     }
499 #endif
500
501   return link_set;
502 }
503
504
505 /**
506  *Lookup the status of a link.
507  *
508  *@param int_addr address of the remote interface
509  *
510  *@return 1 of the link is symmertic 0 if not
511  */
512
513 int
514 check_neighbor_link(union olsr_ip_addr *int_addr)
515 {
516   struct link_entry *tmp_link_set;
517
518   tmp_link_set = link_set;
519
520   while(tmp_link_set)
521     {
522       if(COMP_IP(int_addr, &tmp_link_set->neighbor_iface_addr))
523         return lookup_link_status(tmp_link_set);
524       tmp_link_set = tmp_link_set->next;
525     }
526   return UNSPEC_LINK;
527 }
528
529
530 /**
531  *Lookup a link entry
532  *
533  *@param remote the remote interface address
534  *@param local the local interface address
535  *
536  *@return the link entry if found, NULL if not
537  */
538 struct link_entry *
539 lookup_link_entry(union olsr_ip_addr *remote, union olsr_ip_addr *local)
540 {
541   struct link_entry *tmp_link_set;
542
543   tmp_link_set = link_set;
544
545   while(tmp_link_set)
546     {
547       if(COMP_IP(remote, &tmp_link_set->neighbor_iface_addr) &&
548          COMP_IP(local, &tmp_link_set->local_iface_addr))
549         return tmp_link_set;
550       tmp_link_set = tmp_link_set->next;
551     }
552   return NULL;
553
554 }
555
556
557
558
559
560
561
562 /**
563  *Update a link entry. This is the "main entrypoint" in
564  *the link-sensing. This function is calles from the HELLO
565  *parser function.
566  *It makes sure a entry is updated or created.
567  *
568  *@param local the local IP address
569  *@param remote the remote IP address
570  *@param message the HELLO message
571  *@param in_if the interface on which this HELLO was received
572  *
573  *@return the link_entry struct describing this link entry
574  */
575 struct link_entry *
576 update_link_entry(union olsr_ip_addr *local, union olsr_ip_addr *remote, struct hello_message *message, struct interface *in_if)
577 {
578   int status;
579   struct link_entry *entry;
580 #ifndef WIN32
581   struct interface *local_if;
582 #endif
583
584   /* Time out entries */
585   //timeout_link_set();
586
587   /* Add if not registered */
588   entry = add_new_entry(local, remote, &message->source_addr, message->vtime, message->htime);
589
590   /* Update link layer info */
591   /* Add to link-layer spy list */
592 #ifndef WIN32
593   if(llinfo && !entry->spy_activated)
594     {
595       local_if = if_ifwithaddr(local);
596       
597       olsr_printf(1, "Adding %s to spylist of interface %s\n", olsr_ip_to_string(remote), local_if->int_name);
598
599       if((local_if != NULL) && (add_spy_node(remote, local_if->int_name)))
600         entry->spy_activated = 1;
601     }
602 #endif
603
604   /* Update ASYM_time */
605   //printf("Vtime is %f\n", message->vtime);
606   /* L_ASYM_time = current time + validity time */
607   olsr_get_timestamp((olsr_u32_t) (message->vtime*1000), &entry->ASYM_time);
608
609
610   status = check_link_status(message);
611
612   //printf("Status %d\n", status);
613
614   switch(status)
615     {
616     case(LOST_LINK):
617       /* L_SYM_time = current time - 1 (i.e., expired) */
618       entry->SYM_time = now;
619       entry->SYM_time.tv_sec -= 1;
620
621       break;
622     case(SYM_LINK):
623     case(ASYM_LINK):
624       /* L_SYM_time = current time + validity time */
625       //printf("updating SYM time for %s\n", olsr_ip_to_string(remote));
626       olsr_get_timestamp((olsr_u32_t) (message->vtime*1000), &entry->SYM_time);
627         //timeradd(&now, &tmp_timer, &entry->SYM_time);
628
629       /* L_time = L_SYM_time + NEIGHB_HOLD_TIME */
630       timeradd(&entry->SYM_time, &hold_time_neighbor, &entry->time);
631
632       break;
633     default:;
634     }
635
636   /* L_time = max(L_time, L_ASYM_time) */
637   if(timercmp(&entry->time, &entry->ASYM_time, <))
638     entry->time = entry->ASYM_time;
639
640
641   /*
642   printf("Updating link LOCAL: %s ", olsr_ip_to_string(local));
643   printf("REMOTE: %s\n", olsr_ip_to_string(remote));
644   printf("VTIME: %f ", message->vtime);
645   printf("STATUS: %d\n", status);
646   */
647
648   /* Update hysteresis values */
649   if(olsr_cnf->use_hysteresis)
650     olsr_process_hysteresis(entry);
651
652   /* update neighbor status */
653   /* Return link status */
654   //status = lookup_link_status(entry);
655   /* UPDATED ! */
656   status = get_neighbor_status(remote);
657
658   /* Update neighbor */
659   update_neighbor_status(entry->neighbor, status);
660   //update_neighbor_status(entry->neighbor);
661
662   return entry;  
663 }
664
665
666 /**
667  * Fuction that updates all registered pointers to
668  * one neighbor entry with another pointer
669  * Used by MID updates.
670  *
671  *@old the pointer to replace
672  *@new the pointer to use instead of "old"
673  *
674  *@return the number of entries updated
675  */
676 int
677 replace_neighbor_link_set(struct neighbor_entry *old,
678                           struct neighbor_entry *new)
679 {
680   struct link_entry *tmp_link_set, *last_link_entry;
681   int retval;
682
683   retval = 0;
684
685   if(link_set == NULL)
686     return retval;
687       
688   tmp_link_set = link_set;
689   last_link_entry = NULL;
690
691   while(tmp_link_set)
692     {
693
694       if(tmp_link_set->neighbor == old)
695         {
696           tmp_link_set->neighbor = new;
697           retval++;
698         }
699       tmp_link_set = tmp_link_set->next;
700     }
701
702   return retval;
703
704 }
705
706
707 /**
708  *Checks the link status to a neighbor by
709  *looking in a received HELLO message.
710  *
711  *@param message the HELLO message to check
712  *
713  *@return the link status
714  */
715 static int
716 check_link_status(struct hello_message *message)
717 {
718
719   struct hello_neighbor  *neighbors;
720   struct interface *ifd;
721
722   neighbors = message->neighbors;
723   
724   while(neighbors!=NULL)
725     {  
726       //printf("(linkstatus)Checking %s ",olsr_ip_to_string(&neighbors->address));
727       //printf("against %s\n",olsr_ip_to_string(&main_addr));
728
729       /* Check all interfaces */          
730       for (ifd = ifnet; ifd ; ifd = ifd->int_next) 
731         {
732           if(COMP_IP(&neighbors->address, &ifd->ip_addr))
733             {
734               //printf("ok");
735               return neighbors->link;
736             }
737         }
738
739       neighbors = neighbors->next; 
740     }
741
742
743   return UNSPEC_LINK;
744 }
745
746
747 /**
748  *Time out the link set. In other words, the link
749  *set is traversed and all non-valid entries are
750  *deleted.
751  *
752  */
753 static void
754 olsr_time_out_link_set()
755 {
756
757   struct link_entry *tmp_link_set, *last_link_entry;
758
759   if(link_set == NULL)
760     return;
761       
762   tmp_link_set = link_set;
763   last_link_entry = NULL;
764
765   while(tmp_link_set)
766     {
767
768       if(TIMED_OUT(&tmp_link_set->time))
769         {
770           if(last_link_entry != NULL)
771             {
772               last_link_entry->next = tmp_link_set->next;
773
774               /* Delete neighbor entry */
775               if(tmp_link_set->neighbor->linkcount == 1)
776                 olsr_delete_neighbor_table(&tmp_link_set->neighbor->neighbor_main_addr);
777               else
778                 tmp_link_set->neighbor->linkcount--;
779
780               //olsr_delete_neighbor_if_no_link(&tmp_link_set->neighbor->neighbor_main_addr);
781               changes_neighborhood = UP;
782
783               free(tmp_link_set);
784               tmp_link_set = last_link_entry;
785             }
786           else
787             {
788               link_set = tmp_link_set->next; /* CHANGED */
789
790               /* Delete neighbor entry */
791               if(tmp_link_set->neighbor->linkcount == 1)
792                 olsr_delete_neighbor_table(&tmp_link_set->neighbor->neighbor_main_addr);
793               else
794                 tmp_link_set->neighbor->linkcount--;
795               //olsr_delete_neighbor_if_no_link(&tmp_link_set->neighbor->neighbor_main_addr);
796
797               changes_neighborhood = UP;
798
799               free(tmp_link_set);
800               tmp_link_set = link_set;
801               continue;
802             }       
803         }
804       
805       last_link_entry = tmp_link_set;
806       tmp_link_set = tmp_link_set->next;
807     }
808
809   return;
810 }
811
812
813
814
815 /**
816  *Updates links that we have not received
817  *HELLO from in expected time according to 
818  *hysteresis.
819  *
820  *@return nada
821  */
822 static void
823 olsr_time_out_hysteresis()
824 {
825
826   struct link_entry *tmp_link_set;
827   int status;
828
829   if(link_set == NULL)
830     return;
831
832   tmp_link_set = link_set;
833
834   while(tmp_link_set)
835     {
836       if(TIMED_OUT(&tmp_link_set->hello_timeout))
837         {
838           tmp_link_set->L_link_quality = olsr_hyst_calc_instability(tmp_link_set->L_link_quality);
839           olsr_printf(1, "HYST[%s] HELLO timeout %0.3f\n", olsr_ip_to_string(&tmp_link_set->neighbor_iface_addr), tmp_link_set->L_link_quality);
840           /* Update hello_timeout - NO SLACK THIS TIME */
841           olsr_get_timestamp((olsr_u32_t) tmp_link_set->last_htime*1000, &tmp_link_set->hello_timeout);
842
843           /* Recalculate status */
844           /* Update hysteresis values */
845           olsr_process_hysteresis(tmp_link_set);
846           
847           /* update neighbor status */
848           //status = lookup_link_status(tmp_link_set);
849           /* UPDATED ! */
850           status = get_neighbor_status(&tmp_link_set->neighbor_iface_addr);
851
852
853           /* Update neighbor */
854           update_neighbor_status(tmp_link_set->neighbor, status);
855           //update_neighbor_status(tmp_link_set->neighbor);
856
857           /* Update seqno - not mentioned in the RFC... kind of a hack.. */
858           tmp_link_set->olsr_seqno++;
859         }
860       tmp_link_set = tmp_link_set->next;
861     }
862
863   return;
864 }
865
866 #if defined USE_LINK_QUALITY
867 void olsr_print_link_set(void)
868 {
869   struct link_entry *walker;
870   float link_quality;
871
872   olsr_printf(1, "CURRENT LINK SET ------------------------------\n");
873
874   for (walker = link_set; walker != NULL; walker = walker->next)
875     {
876       if (walker->total_packets > 0)
877         link_quality = 1.0 - (float)walker->lost_packets /
878           (float)walker->total_packets;
879
880       else
881         link_quality = 0.0;
882
883       olsr_printf(1, "%15s %5.3f %5.3f %d/%d\n",
884                   olsr_ip_to_string(&walker->neighbor_iface_addr),
885                   walker->L_link_quality, link_quality,
886                   walker->lost_packets, walker->total_packets);
887     }
888
889   olsr_printf(1, "CURRENT LINK SET (END) ------------------------\n");
890 }
891
892 static void update_packet_loss_worker(struct link_entry *entry, int lost)
893 {
894   unsigned char mask = 1 << (entry->loss_index & 7);
895   int index = entry->loss_index >> 3;
896
897   if (lost == 0)
898     {
899       if ((entry->loss_bitmap[index] & mask) != 0)
900         {
901           entry->loss_bitmap[index] &= ~mask;
902           entry->lost_packets--;
903         }
904     }
905
906   else
907     {
908       if ((entry->loss_bitmap[index] & mask) == 0)
909         {
910           entry->loss_bitmap[index] |= mask;
911           entry->lost_packets++;
912         }
913     }
914
915   entry->loss_index++;
916
917   if (entry->loss_index >= entry->loss_window_size)
918     entry->loss_index = 0;
919
920   if (entry->total_packets < entry->loss_window_size)
921     entry->total_packets++;
922 }
923
924 void olsr_update_packet_loss_hello_int(struct link_entry *entry,
925                                        double loss_hello_int)
926 {
927   entry->loss_hello_int = loss_hello_int;
928 }
929
930 void olsr_update_packet_loss(union olsr_ip_addr *rem, union olsr_ip_addr *loc,
931                              olsr_u16_t seqno)
932 {
933   struct link_entry *entry;
934
935   entry = lookup_link_entry(rem, loc);
936
937   if (entry == NULL)
938     return;
939     
940   if (entry->loss_seqno_valid != 0 && 
941       (unsigned short)(seqno - entry->loss_seqno) < 100)
942     {
943       while (entry->loss_seqno != seqno)
944         {
945           if (entry->loss_missed_hellos == 0)
946             update_packet_loss_worker(entry, 1);
947
948           else
949             entry->loss_missed_hellos--;
950
951           entry->loss_seqno++;
952         }
953     }
954
955   update_packet_loss_worker(entry, 0);
956
957   entry->loss_missed_hellos = 0;
958   entry->loss_seqno = seqno + 1;
959   entry->loss_seqno_valid = 1;
960
961   olsr_get_timestamp((olsr_u32_t)(entry->loss_hello_int * 1500.0),
962                      &entry->loss_timeout);
963 }
964
965 static void olsr_time_out_packet_loss()
966 {
967   struct link_entry *walker;
968
969   for (walker = link_set; walker != NULL; walker = walker->next)
970     {
971       if (!TIMED_OUT(&walker->loss_timeout))
972         continue;
973       
974       update_packet_loss_worker(walker, 1);
975
976       walker->loss_missed_hellos++;
977
978       olsr_get_timestamp((olsr_u32_t)(walker->loss_hello_int * 1000.0),
979                          &walker->loss_timeout);
980     }
981 }
982 #endif