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