Process LQ_TC messages. Made link quality features configurable. Set
[olsrd.git] / src / process_package.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: process_package.c,v 1.16 2004/11/07 20:09:11 tlopatic Exp $
23  *
24  */
25
26
27 #include "defs.h"
28 #include "process_package.h"
29 #include "hysteresis.h"
30 #include "two_hop_neighbor_table.h"
31 #include "tc_set.h"
32 #include "mpr_selector_set.h"
33 #include "mid_set.h"
34 #include "olsr.h"
35 #include "parser.h"
36 #include "duplicate_set.h"
37 #include "rebuild_packet.h"
38
39 #ifdef linux 
40 #include "linux/tunnel.h"
41 #endif
42
43
44 /**
45  *Initializing the parser functions we are using
46  */
47 void
48 olsr_init_package_process()
49 {
50 #if defined USE_LINK_QUALITY
51   if (olsr_cnf->lq_level == 0)
52     {
53 #endif
54       olsr_parser_add_function(&olsr_process_received_hello, HELLO_MESSAGE, 1);
55       olsr_parser_add_function(&olsr_process_received_tc, TC_MESSAGE, 1);
56 #if defined USE_LINK_QUALITY
57     }
58
59   else
60     {
61       olsr_parser_add_function(&olsr_input_lq_hello, LQ_HELLO_MESSAGE, 1);
62       olsr_parser_add_function(&olsr_input_lq_tc, LQ_TC_MESSAGE, 1);
63     }
64 #endif
65   olsr_parser_add_function(&olsr_process_received_mid, MID_MESSAGE, 1);
66   olsr_parser_add_function(&olsr_process_received_hna, HNA_MESSAGE, 1);
67 }
68
69 void
70 olsr_hello_tap(struct hello_message *message, struct interface *in_if,
71                union olsr_ip_addr *from_addr)
72 {
73   struct link_entry         *link;
74   struct neighbor_entry     *neighbor;
75 #if defined USE_LINK_QUALITY
76   struct hello_neighbor *walker;
77 #endif
78
79   /*
80    * Update link status
81    */
82   link = update_link_entry(&in_if->ip_addr, from_addr, message, in_if);
83
84 #if defined USE_LINK_QUALITY
85   if (olsr_cnf->lq_level > 0)
86     {
87       // just in case our neighbor has changed its HELLO interval
88
89       olsr_update_packet_loss_hello_int(link, message->htime);
90
91       // find the input interface in the list of neighbor interfaces
92
93       for (walker = message->neighbors; walker != NULL; walker = walker->next)
94         if (COMP_IP(&walker->address, &in_if->ip_addr))
95           break;
96
97       // memorize our neighbour's idea of the link quality, so that we
98       // know the link quality in both directions
99
100       if (walker != NULL)
101         link->neigh_link_quality = walker->link_quality;
102
103       else
104         link->neigh_link_quality = 0.0;
105     }
106 #endif
107   
108   neighbor = link->neighbor;
109
110   /*
111    * Hysteresis
112    */
113   if(olsr_cnf->use_hysteresis)
114     {
115       /* Update HELLO timeout */
116       //printf("MESSAGE HTIME: %f\n", message->htime);
117       olsr_update_hysteresis_hello(link, message->htime);
118     }
119
120   /* Check if we are chosen as MPR */
121   if(olsr_lookup_mpr_status(message, in_if))
122     /* source_addr is always the main addr of a node! */
123     olsr_update_mprs_set(&message->source_addr, (float)message->vtime);
124
125
126
127   /* Check willingness */
128   if(neighbor->willingness != message->willingness)
129     {
130       olsr_printf(1, "Willingness for %s changed from %d to %d - UPDATING\n", 
131                   olsr_ip_to_string(&neighbor->neighbor_main_addr),
132                   neighbor->willingness,
133                   message->willingness);
134       /*
135        *If willingness changed - recalculate
136        */
137       neighbor->willingness = message->willingness;
138       changes_neighborhood = OLSR_TRUE;
139       changes_topology = OLSR_TRUE;
140     }
141
142
143   /* Don't register neighbors of neighbors that announces WILL_NEVER */
144   if(neighbor->willingness != WILL_NEVER)
145     olsr_process_message_neighbors(neighbor, message);
146
147   /* Process changes immedeatly in case of MPR updates */
148   olsr_process_changes();
149
150   olsr_destroy_hello_message(message);
151
152   return;
153 }
154
155 /**
156  *Processes a received HELLO message. 
157  *
158  *@param m the incoming OLSR message
159  *@return 0 on sucess
160  */
161
162 void
163 olsr_process_received_hello(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *from_addr)
164 {
165   struct hello_message      message;
166
167   hello_chgestruct(&message, m);
168
169   olsr_hello_tap(&message, in_if, from_addr);
170 }
171
172 void
173 olsr_tc_tap(struct tc_message *message, struct interface *in_if,
174             union olsr_ip_addr *from_addr, union olsr_message *m)
175 {
176   struct tc_mpr_addr              *mpr;
177   struct tc_entry                 *tc_last;
178
179   if(!olsr_check_dup_table_proc(&message->originator, 
180                                 message->packet_seq_number))
181     {
182       goto forward;
183     }
184
185   olsr_printf(3, "Processing TC from %s\n",
186               olsr_ip_to_string(&message->originator));
187
188   /*
189    *      If the sender interface (NB: not originator) of this message
190    *      is not in the symmetric 1-hop neighborhood of this node, the
191    *      message MUST be discarded.
192    */
193
194   if(check_neighbor_link(from_addr) != SYM_LINK)
195     {
196       olsr_printf(2, "Received TC from NON SYM neighbor %s\n",
197                   olsr_ip_to_string(from_addr));
198       olsr_destroy_tc_message(message);
199       return;
200     }
201
202   if(olsr_cnf->debug_level > 2)
203     {
204       mpr = message->multipoint_relay_selector_address;
205       olsr_printf(3, "mpr_selector_list:[");
206
207       while(mpr!=NULL)
208         {
209           olsr_printf(3, "%s:", olsr_ip_to_string(&mpr->address));
210           mpr=mpr->next;
211         }
212
213       olsr_printf(3, "]\n");
214     }
215
216   tc_last = olsr_lookup_tc_entry(&message->originator);
217    
218   if(tc_last != NULL)
219     {
220       /* Update entry */
221
222       /* Delete destinations with lower ANSN */
223       if(olsr_tc_delete_mprs(tc_last, message))
224         changes_topology = OLSR_TRUE; 
225
226       /* Update destinations */
227       if(olsr_tc_update_mprs(tc_last, message))
228         changes_topology = OLSR_TRUE;
229
230       /* Delete possible empty TC entry */
231       if(changes_topology)
232         olsr_tc_delete_entry_if_empty(tc_last);
233     }
234
235   else
236     {
237       /*if message is empty then skip it */
238       if(message->multipoint_relay_selector_address != NULL)
239         {
240           /* New entry */
241           tc_last = olsr_add_tc_entry(&message->originator);      
242           
243           /* Update destinations */
244           olsr_tc_update_mprs(tc_last, message);
245           
246           changes_topology = OLSR_TRUE;
247         }
248       else
249         {
250           olsr_printf(3, "Dropping empty TC from %s\n",
251                       olsr_ip_to_string(&message->originator)); 
252         }
253     }
254
255   /* Process changes */
256   //olsr_process_changes();
257
258  forward:
259
260   olsr_forward_message(m, 
261                        &message->originator, 
262                        message->packet_seq_number, 
263                        in_if,
264                        from_addr);
265
266   olsr_destroy_tc_message(message);
267
268   return;
269 }
270
271 /**
272  *Process a received TopologyControl message
273  *
274  *
275  *@param m the incoming OLSR message
276  *@return 0 on success
277  */
278 void
279 olsr_process_received_tc(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *from_addr)
280
281   struct tc_message               message;
282
283   tc_chgestruct(&message, m, from_addr);
284
285   olsr_tc_tap(&message, in_if, from_addr, m);
286 }
287
288
289
290
291
292
293 /**
294  *Process a received(and parsed) MID message
295  *For every address check if there is a topology node
296  *registered with it and update its addresses.
297  *
298  *@param m the OLSR message received.
299  *@return 1 on success
300  */
301
302 void
303 olsr_process_received_mid(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *from_addr)
304 {
305   struct mid_alias *tmp_adr;
306   struct mid_message message;
307
308
309   mid_chgestruct(&message, m);
310
311   /*
312   if(COMP_IP(&message.mid_origaddr, &main_addr))
313     {
314       goto forward;  
315     }
316   */
317
318   if(!olsr_check_dup_table_proc(&message.mid_origaddr, 
319                                 message.mid_seqno))
320     {
321       goto forward;
322     }
323   
324   olsr_printf(5, "Processing MID from %s...\n", olsr_ip_to_string(&message.mid_origaddr));
325
326   tmp_adr = message.mid_addr;
327
328
329   /*
330    *      If the sender interface (NB: not originator) of this message
331    *      is not in the symmetric 1-hop neighborhood of this node, the
332    *      message MUST be discarded.
333    */
334
335   if(check_neighbor_link(from_addr) != SYM_LINK)
336     {
337       olsr_printf(2, "Received MID from NON SYM neighbor %s\n", olsr_ip_to_string(from_addr));
338       olsr_destroy_mid_message(&message);
339       return;
340     }
341
342
343
344   /* Update the timeout of the MID */
345   olsr_update_mid_table(&message.mid_origaddr, (float)message.vtime);
346
347   while(tmp_adr)
348     {
349       if(!mid_lookup_main_addr(&tmp_adr->alias_addr))
350         {
351           olsr_printf(1, "MID new: (%s, ", olsr_ip_to_string(&message.mid_origaddr));
352           olsr_printf(1, "%s)\n", olsr_ip_to_string(&tmp_adr->alias_addr));
353           insert_mid_alias(&message.mid_origaddr, &tmp_adr->alias_addr, (float)message.vtime);
354         }
355
356
357       tmp_adr = tmp_adr->next;
358     } 
359   
360   /*Update topology if neccesary*/
361   //olsr_process_changes();
362
363  forward:
364   
365   olsr_forward_message(m, 
366                        &message.mid_origaddr, 
367                        message.mid_seqno, 
368                        in_if,
369                        from_addr);
370   olsr_destroy_mid_message(&message);
371
372   return;
373 }
374
375
376
377
378
379 /**
380  *Process incoming HNA message.
381  *Forwards the message if that is to be done.
382  *
383  *@param m the incoming OLSR message
384  *the OLSR message.
385  *@return 1 on success
386  */
387
388 void
389 olsr_process_received_hna(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *from_addr)
390 {
391   struct hna_net_addr  *hna_tmp;
392   struct  hna_message message;
393
394   //printf("Processing HNA\n");
395
396   hna_chgestruct(&message, m);
397   
398
399   /* Process message */   
400   /*
401   if(COMP_IP(&message.originator, &main_addr)) 
402     {
403       goto forward;
404     }
405   */
406
407   if(!olsr_check_dup_table_proc(&message.originator, 
408                                 message.packet_seq_number))
409     {
410       goto forward;
411     }
412
413
414
415
416   hna_tmp = message.hna_net;
417
418
419
420   /*
421    *      If the sender interface (NB: not originator) of this message
422    *      is not in the symmetric 1-hop neighborhood of this node, the
423    *      message MUST be discarded.
424    */
425
426
427   if(check_neighbor_link(from_addr) != SYM_LINK)
428     {
429       olsr_printf(2, "Received HNA from NON SYM neighbor %s\n", olsr_ip_to_string(from_addr));
430       olsr_destroy_hna_message(&message);
431       return;
432     }
433
434   while(hna_tmp)
435     {
436 #ifdef linux
437       /*
438        * Set up tunnel to Internet gateway
439        */
440       if((use_tunnel) && (olsr_cnf->ip_version == AF_INET) && (hna_tmp->net.v4 == 0))
441         {
442           if(inet_tnl_added || gw_tunnel)
443             {
444               hna_tmp = hna_tmp->next;
445               continue;
446             }
447           
448           olsr_printf(1, "Internet gateway discovered! Setting up tunnel:\n");
449
450           /* Set up tunnel endpoint */
451           set_up_source_tnl(&main_addr, &message.originator, in_if->if_index); 
452         }
453       else
454 #endif
455         {
456           olsr_update_hna_entry(&message.originator, &hna_tmp->net, &hna_tmp->netmask, (float)message.vtime); 
457         }
458       
459       hna_tmp = hna_tmp->next;
460     }
461   
462   /*Update topology if neccesary*/
463   //olsr_process_changes();
464
465  forward:
466   olsr_forward_message(m, 
467                        &message.originator, 
468                        message.packet_seq_number, 
469                        in_if,
470                        from_addr);
471   olsr_destroy_hna_message(&message);
472
473   return;
474 }
475
476
477
478
479
480
481
482 /**
483  *Processes an list of neighbors from an incoming HELLO message.
484  *@param neighbor the neighbor who sendt the message.
485  *@param message the HELLO message
486  *@return nada
487  */
488 void
489 olsr_process_message_neighbors(struct neighbor_entry *neighbor,
490                                struct hello_message *message)
491 {
492   struct hello_neighbor        *message_neighbors;
493   struct neighbor_2_list_entry *two_hop_neighbor_yet;
494   struct neighbor_2_entry      *two_hop_neighbor;
495   union olsr_ip_addr           *neigh_addr;
496 #if defined USE_LINK_QUALITY
497   struct neighbor_list_entry *walker;
498   double link_quality;
499 #endif
500
501   for(message_neighbors = message->neighbors;
502       message_neighbors != NULL;
503       message_neighbors = message_neighbors->next)
504     {
505       /*
506        *check all interfaces
507        *so that we don't add ourselves to the
508        *2 hop list
509        *IMPORTANT!
510        */
511       if(if_ifwithaddr(&message_neighbors->address) != NULL)
512         continue;
513
514       /* Get the main address */
515
516       neigh_addr = mid_lookup_main_addr(&message_neighbors->address);
517
518       if (neigh_addr != NULL)
519         COPY_IP(&message_neighbors->address, neigh_addr);
520       
521       if(((message_neighbors->status == SYM_NEIGH) ||
522           (message_neighbors->status == MPR_NEIGH)))
523         {
524           //printf("\tProcessing %s\n", olsr_ip_to_string(&message_neighbors->address));
525           //printf("\tMain addr: %s\n", olsr_ip_to_string(neigh_addr));
526           
527           two_hop_neighbor_yet =
528             olsr_lookup_my_neighbors(neighbor,
529                                      &message_neighbors->address);
530
531           if (two_hop_neighbor_yet != NULL)
532             {
533               /* Updating the holding time for this neighbor */
534               olsr_get_timestamp((olsr_u32_t)message->vtime * 1000,
535                                  &two_hop_neighbor_yet->neighbor_2_timer);
536
537               two_hop_neighbor = two_hop_neighbor_yet->neighbor_2;
538             }
539           else
540             {
541               two_hop_neighbor =
542                 olsr_lookup_two_hop_neighbor_table(&message_neighbors->address);
543               if (two_hop_neighbor == NULL)
544                 {
545                   //printf("Adding 2 hop neighbor %s\n\n", olsr_ip_to_string(&message_neighbors->address)); 
546
547                   changes_neighborhood = OLSR_TRUE;
548                   changes_topology = OLSR_TRUE;
549
550                   two_hop_neighbor =
551                     olsr_malloc(sizeof(struct neighbor_2_entry),
552                                 "Process HELLO");
553                   
554                   two_hop_neighbor->neighbor_2_nblist.next =
555                     &two_hop_neighbor->neighbor_2_nblist;
556
557                   two_hop_neighbor->neighbor_2_nblist.prev =
558                     &two_hop_neighbor->neighbor_2_nblist;
559
560                   two_hop_neighbor->neighbor_2_pointer = 0;
561                   
562                   COPY_IP(&two_hop_neighbor->neighbor_2_addr,
563                           &message_neighbors->address);
564
565                   olsr_insert_two_hop_neighbor_table(two_hop_neighbor);
566
567                   olsr_linking_this_2_entries(neighbor, two_hop_neighbor,
568                                               (float)message->vtime);
569                 }
570               else
571                 {
572                   /*
573                     linking to this two_hop_neighbor entry
574                   */    
575                   changes_neighborhood = OLSR_TRUE;
576                   changes_topology = OLSR_TRUE;
577                   
578                   olsr_linking_this_2_entries(neighbor, two_hop_neighbor,
579                                               (float)message->vtime); 
580                 }
581             }
582 #if defined USE_LINK_QUALITY
583           if (olsr_cnf->lq_level > 0)
584             {
585               link_quality =
586                 olsr_neighbor_best_link_quality(&neighbor->neighbor_main_addr);
587
588               // loop through the one-hop neighbors that see this
589               // two hop neighbour
590
591               for (walker = two_hop_neighbor->neighbor_2_nblist.next;
592                    walker != &two_hop_neighbor->neighbor_2_nblist;
593                    walker = walker->next)
594                 {
595                   // have we found the one-hop neighbor that sent the
596                   // HELLO message that we're current processing?
597
598                   if (walker->neighbor == neighbor)
599                     {
600                       // total link quality = link quality between us
601                       // and our one-hop neighbor x link quality between
602                       // our one-hop neighbor and the two-hop neighbor
603
604                       walker->full_link_quality =
605                         link_quality *
606                         message_neighbors->link_quality *
607                         message_neighbors->neigh_link_quality;
608                     }
609                 }
610             }
611 #endif
612         }
613     }
614 }
615
616
617
618
619
620
621
622
623 /**
624  *Links a one-hop neighbor with a 2-hop neighbor.
625  *
626  *@param neighbor the 1-hop neighbor
627  *@param two_hop_neighbor the 2-hop neighbor
628  *@return nada
629  */
630 void
631 olsr_linking_this_2_entries(struct neighbor_entry *neighbor,struct neighbor_2_entry *two_hop_neighbor, float vtime)
632 {
633   struct neighbor_list_entry    *list_of_1_neighbors;
634   struct neighbor_2_list_entry  *list_of_2_neighbors;
635
636   list_of_1_neighbors = olsr_malloc(sizeof(struct neighbor_list_entry), "Link entries 1");
637
638   list_of_2_neighbors = olsr_malloc(sizeof(struct neighbor_2_list_entry), "Link entries 2");
639
640   list_of_1_neighbors->neighbor = neighbor;
641
642 #if defined USE_LINK_QUALITY
643   list_of_1_neighbors->full_link_quality = 0.0;
644 #endif
645
646   /* Queue */
647   two_hop_neighbor->neighbor_2_nblist.next->prev = list_of_1_neighbors;
648   list_of_1_neighbors->next = two_hop_neighbor->neighbor_2_nblist.next;
649   two_hop_neighbor->neighbor_2_nblist.next = list_of_1_neighbors;
650   list_of_1_neighbors->prev = &two_hop_neighbor->neighbor_2_nblist;
651
652
653   list_of_2_neighbors->neighbor_2 = two_hop_neighbor;
654   
655   olsr_get_timestamp((olsr_u32_t) vtime*1000, &list_of_2_neighbors->neighbor_2_timer);
656
657   /* Queue */
658   neighbor->neighbor_2_list.next->prev = list_of_2_neighbors;
659   list_of_2_neighbors->next = neighbor->neighbor_2_list.next;
660   neighbor->neighbor_2_list.next = list_of_2_neighbors;
661   list_of_2_neighbors->prev = &neighbor->neighbor_2_list;
662   
663   /*increment the pointer counter*/
664   two_hop_neighbor->neighbor_2_pointer++;
665 }
666
667
668
669
670
671
672 /**
673  *Check if a hello message states this node as a MPR.
674  *
675  *@param message the message to check
676  *@param n_link the buffer to put the link status in
677  *@param n_status the buffer to put the status in
678  *
679  *@return 1 if we are selected as MPR 0 if not
680  */
681 int
682 olsr_lookup_mpr_status(struct hello_message *message, struct interface *in_if)
683 {
684   
685   struct hello_neighbor  *neighbors;
686
687   neighbors=message->neighbors;
688   
689   while(neighbors!=NULL)
690     {  
691       //printf("(linkstatus)Checking %s ",olsr_ip_to_string(&neighbors->address));
692       //printf("against %s\n",olsr_ip_to_string(&main_addr));
693
694
695     if(olsr_cnf->ip_version == AF_INET)
696       { 
697         /* IPv4 */  
698         if(COMP_IP(&neighbors->address, &in_if->ip_addr))
699           {
700             //printf("ok");
701             if((neighbors->link == SYM_LINK) && (neighbors->status == MPR_NEIGH))
702               return 1;
703             
704             return 0;
705           }
706       }
707     else
708       { 
709         /* IPv6 */  
710         if(COMP_IP(&neighbors->address, &in_if->int6_addr.sin6_addr))
711           {
712             //printf("ok");
713             if((neighbors->link == SYM_LINK) && (neighbors->status == MPR_NEIGH))
714               return 1;
715             
716             return 0;
717           }
718       }
719  
720       neighbors = neighbors->next; 
721     }
722
723   /* Not found */
724   return 0;
725 }