03350c8c2e774ab00a0982049c9b0cd1f1e523b0
[olsrd.git] / src / olsr.c
1 /*
2  * OLSR ad-hoc routing table management protocol
3  * Copyright (C) 2004 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: olsr.c,v 1.24 2004/11/20 17:10:03 tlopatic Exp $
23  *
24  */
25
26 /**
27  * All these functions are global
28  */
29
30 #include "defs.h"
31 #include "olsr.h"
32 #include "link_set.h"
33 #include "two_hop_neighbor_table.h"
34 #include "tc_set.h"
35 #include "duplicate_set.h"
36 #include "mpr_selector_set.h"
37 #include "mid_set.h"
38 #include "mpr.h"
39 #if defined USE_LINK_QUALITY
40 #include "lq_mpr.h"
41 #include "lq_route.h"
42 #endif
43 #include "scheduler.h"
44 #include "generate_msg.h"
45 #include "apm.h"
46 #include "misc.h"
47
48 #include <stdarg.h>
49 #include <signal.h>
50
51
52 /**
53  *Checks if a timer has timed out.
54  */
55
56
57 /**
58  *Initiates a "timer", wich is a timeval structure,
59  *with the value given in time_value.
60  *@param time_value the value to initialize the timer with
61  *@param hold_timer the timer itself
62  *@return nada
63  */
64 inline void
65 olsr_init_timer(olsr_u32_t time_value, struct timeval *hold_timer)
66
67   olsr_u16_t  time_value_sec;
68   olsr_u16_t  time_value_msec;
69
70   time_value_sec = time_value/1000;
71   time_value_msec = time_value-(time_value_sec*1000);
72
73   hold_timer->tv_sec = time_value_sec;
74   hold_timer->tv_usec = time_value_msec*1000;   
75 }
76
77
78
79
80
81 /**
82  *Generaties a timestamp a certain number of milliseconds
83  *into the future.
84  *
85  *@param time_value how many milliseconds from now
86  *@param hold_timer the timer itself
87  *@return nada
88  */
89 inline void
90 olsr_get_timestamp(olsr_u32_t delay, struct timeval *hold_timer)
91
92   hold_timer->tv_sec = now.tv_sec + delay / 1000;
93   hold_timer->tv_usec = now.tv_usec + (delay % 1000) * 1000;
94   
95   if (hold_timer->tv_usec > 1000000)
96     {
97       hold_timer->tv_sec++;
98       hold_timer->tv_usec -= 1000000;
99     }
100 }
101
102
103
104 /**
105  *Initialize the message sequence number as a random value
106  */
107 void
108 init_msg_seqno()
109 {
110   message_seqno = random() & 0xFFFF;
111 }
112
113 /**
114  * Get and increment the message sequence number
115  *
116  *@return the seqno
117  */
118 inline olsr_u16_t
119 get_msg_seqno()
120 {
121   return message_seqno++;
122 }
123
124
125 void
126 register_pcf(int (*f)(int, int, int))
127 {
128   struct pcf *new_pcf;
129
130   olsr_printf(1, "Registering pcf function\n");
131
132   new_pcf = olsr_malloc(sizeof(struct pcf), "New PCF");
133
134   new_pcf->function = f;
135   new_pcf->next = pcf_list;
136   pcf_list = new_pcf;
137
138 }
139
140
141 /**
142  *Process changes in neighborhood or/and topology.
143  *Re-calculates the neighborhooh/topology if there
144  *are any updates - then calls the right functions to
145  *update the routing table.
146  *@return 0
147  */
148 inline void
149 olsr_process_changes()
150 {
151
152   struct pcf *tmp_pc_list;
153
154 #ifdef DEBUG
155   if(changes_neighborhood)
156     olsr_printf(3, "CHANGES IN NEIGHBORHOOD\n");
157   if(changes_topology)
158     olsr_printf(3, "CHANGES IN TOPOLOGY\n");
159   if(changes_hna)
160     olsr_printf(3, "CHANGES IN HNA\n");  
161 #endif
162
163   if(!changes_neighborhood &&
164      !changes_topology &&
165      !changes_hna)
166     return;
167
168   if (olsr_cnf->debug_level > 0 && olsr_cnf->clear_screen && isatty(1))
169     {
170       clear_console();
171       printf("<<<< %s (%s) >>>>\n", SOFTWARE_VERSION, __DATE__);
172     }
173
174   if(changes_neighborhood)
175     {
176       /* Calculate new mprs, HNA and routing table */
177 #if defined USE_LINK_QUALITY
178       if (olsr_cnf->lq_level < 1)
179         {
180 #endif
181           olsr_calculate_mpr();
182 #if defined USE_LINK_QUALITY
183         }
184
185       else
186         {
187           olsr_calculate_lq_mpr();
188         }
189
190
191       if (olsr_cnf->lq_level < 2)
192         {
193 #endif
194           olsr_calculate_routing_table();
195 #if defined USE_LINK_QUALITY
196         }
197
198       else
199         {
200           olsr_calculate_lq_routing_table();
201         }
202 #endif
203
204       olsr_calculate_hna_routes();
205       
206       /* Print updated info */
207       if(olsr_cnf->debug_level > 0) 
208         {
209 #ifdef USE_LINK_QUALITY
210           olsr_print_link_set();
211 #endif
212           olsr_print_neighbor_table();
213
214           if(olsr_cnf->debug_level > 1)
215             olsr_print_tc_table();
216
217           if(olsr_cnf->debug_level > 2) 
218             {
219               // the MPR selector set is now displayed as part of the
220               // neighbour table
221               // olsr_print_mprs_set();
222               olsr_print_mid_set();
223               olsr_print_duplicate_table();
224             }
225           if(changes_hna)
226             olsr_print_hna_set();
227
228         }
229       goto process_pcf;  
230     }
231   
232   if(changes_topology)
233     {
234       /* calculate the routing table and HNA */
235 #if defined USE_LINK_QUALITY
236       if (olsr_cnf->lq_level < 2)
237         {
238 #endif
239           olsr_calculate_routing_table();
240 #if defined USE_LINK_QUALITY
241         }
242
243       else
244         {
245           olsr_calculate_lq_routing_table();
246         }
247 #endif
248       olsr_calculate_hna_routes();
249
250       /* Print updated info */
251       if(olsr_cnf->debug_level > 1)
252         olsr_print_tc_table();
253
254       if(changes_hna)
255         olsr_print_hna_set();
256
257       goto process_pcf;  
258     }
259
260   if(changes_hna)
261     {
262       /* Update HNA routes */
263       olsr_calculate_hna_routes();
264
265       olsr_print_hna_set();
266
267       goto process_pcf;
268     }
269   
270  process_pcf:
271
272   for(tmp_pc_list = pcf_list; 
273       tmp_pc_list != NULL;
274       tmp_pc_list = tmp_pc_list->next)
275     {
276       tmp_pc_list->function(changes_neighborhood,
277                             changes_topology,
278                             changes_hna);
279     }
280
281   changes_neighborhood = OLSR_FALSE;
282   changes_topology = OLSR_FALSE;
283   changes_hna = OLSR_FALSE;
284
285
286   return;
287 }
288
289
290
291
292
293 /**
294  *Initialize all the tables used(neighbor,
295  *topology, MID,  HNA, MPR, dup).
296  *Also initalizes other variables
297  */
298 void
299 olsr_init_tables()
300 {
301   
302   changes_topology = OLSR_FALSE;
303   changes_neighborhood = OLSR_FALSE;
304   changes_hna = OLSR_FALSE;
305
306   /* Initialize link set */
307   olsr_init_link_set();
308
309   /* Initialize duplicate table */
310   olsr_init_duplicate_table();
311
312   /* Initialize neighbor table */
313   olsr_init_neighbor_table();
314
315   /* Initialize routing table */
316   olsr_init_routing_table();
317
318   /* Initialize two hop table */
319   olsr_init_two_hop_table();
320
321   /* Initialize old route table */
322   olsr_init_old_table();
323
324   /* Initialize topology */
325   olsr_init_tc();
326
327   /* Initialize mpr selector table */
328   olsr_init_mprs_set();
329
330   /* Initialize MID set */
331   olsr_init_mid_set();
332
333   /* Initialize HNA set */
334   olsr_init_hna_set();
335
336   /* Initialize ProcessChanges list */
337   ptf_list = NULL;
338   
339 }
340
341
342
343
344
345
346 /**
347  *Check if a message is to be forwarded and forward
348  *it if necessary.
349  *
350  *@param m the OLSR message recieved
351  *@param originator the originator of this message
352  *@param seqno the seqno of the message
353  *
354  *@returns positive if forwarded
355  */
356 int
357 olsr_forward_message(union olsr_message *m, 
358                      union olsr_ip_addr *originator, 
359                      olsr_u16_t seqno,
360                      struct interface *in_if, 
361                      union olsr_ip_addr *from_addr)
362 {
363   union olsr_ip_addr *src;
364   struct neighbor_entry *neighbor;
365   int msgsize;
366   struct interface *ifn;
367
368
369   if(!olsr_check_dup_table_fwd(originator, seqno, &in_if->ip_addr))
370     {
371 #ifdef DEBUG
372       olsr_printf(3, "Message already forwarded!\n");
373 #endif
374       return 0;
375     }
376
377   /* Lookup sender address */
378   if(!(src = mid_lookup_main_addr(from_addr)))
379     src = from_addr;
380
381
382   if(NULL == (neighbor=olsr_lookup_neighbor_table(src)))
383     return 0;
384
385   if(neighbor->status != SYM)
386     return 0;
387
388   /* Update duplicate table interface */
389   olsr_update_dup_entry(originator, seqno, &in_if->ip_addr);
390
391   
392   /* Check MPR */
393   if(olsr_lookup_mprs_set(src) == NULL)
394     {
395 #ifdef DEBUG
396       olsr_printf(5, "Forward - sender %s not MPR selector\n", olsr_ip_to_string(src));
397 #endif
398       return 0;
399     }
400
401
402   /* Treat TTL hopcnt */
403   if(olsr_cnf->ip_version == AF_INET)
404     {
405       /* IPv4 */
406       m->v4.hopcnt++;
407       m->v4.ttl--; 
408     }
409   else
410     {
411       /* IPv6 */
412       m->v6.hopcnt++;
413       m->v6.ttl--; 
414     }
415
416
417
418   /* Update dup forwarded */
419   olsr_set_dup_forward(originator, seqno);
420
421   /* Update packet data */
422
423
424   msgsize = ntohs(m->v4.olsr_msgsize);
425
426   /* looping trough interfaces */
427   for (ifn = ifnet; ifn ; ifn = ifn->int_next) 
428     { 
429       if(net_output_pending(ifn))
430         {
431           /*
432            * Check if message is to big to be piggybacked
433            */
434           if(net_outbuffer_push(ifn, (olsr_u8_t *)m, msgsize) != msgsize)
435             {
436               /* Send */
437               net_output(ifn);
438               /* Buffer message */
439               set_buffer_timer(ifn);
440               
441               if(net_outbuffer_push(ifn, (olsr_u8_t *)m, msgsize) != msgsize)
442                 {
443                   olsr_printf(1, "Received message to big to be forwarded in %s(%d bytes)!", ifn->int_name, msgsize);
444                   olsr_syslog(OLSR_LOG_ERR, "Received message to big to be forwarded on %s(%d bytes)!", ifn->int_name, msgsize);
445                 }
446
447             }
448         }
449       
450       else
451         {
452           /* No forwarding pending */
453           set_buffer_timer(ifn);
454           
455           if(net_outbuffer_push(ifn, (olsr_u8_t *)m, msgsize) != msgsize)
456             {
457               olsr_printf(1, "Received message to big to be forwarded in %s(%d bytes)!", ifn->int_name, msgsize);
458               olsr_syslog(OLSR_LOG_ERR, "Received message to big to be forwarded on %s(%d bytes)!", ifn->int_name, msgsize);
459             }
460         }
461     }
462
463   return 1;
464
465 }
466
467
468 void
469 set_buffer_timer(struct interface *ifn)
470 {
471   float jitter;
472   struct timeval jittertimer;
473       
474   /* Set timer */
475   jitter = (float) random()/RAND_MAX;
476   jitter *= max_jitter;
477
478   olsr_init_timer((olsr_u32_t) (jitter*1000), &jittertimer);
479
480   timeradd(&now, &jittertimer, &fwdtimer[ifn->if_nr]);
481
482 }
483
484
485
486 void
487 olsr_init_willingness()
488 {
489   if(olsr_cnf->willingness_auto)
490     olsr_register_scheduler_event(&olsr_update_willingness, NULL, will_int, will_int, NULL);
491 }
492
493 void
494 olsr_update_willingness(void *foo)
495 {
496   int tmp_will;
497
498   tmp_will = olsr_cnf->willingness;
499
500   /* Re-calculate willingness */
501   olsr_cnf->willingness = olsr_calculate_willingness();
502
503   if(tmp_will != olsr_cnf->willingness)
504     {
505       olsr_printf(1, "Local willingness updated: old %d new %d\n", tmp_will, olsr_cnf->willingness);
506     }
507 }
508
509
510 /**
511  *Calculate this nodes willingness to act as a MPR
512  *based on either a fixed value or the power status
513  *of the node using APM
514  *
515  *@return a 8bit value from 0-7 representing the willingness
516  */
517
518 olsr_u8_t
519 olsr_calculate_willingness()
520 {
521   struct olsr_apm_info ainfo;
522
523   /* If fixed willingness */
524   if(!olsr_cnf->willingness_auto)
525     return olsr_cnf->willingness;
526
527 #warning CHANGES IN THE apm INTERFACE(0.4.8)!
528
529   if(apm_read(&ainfo) < 1)
530     return WILL_DEFAULT;
531
532   apm_printinfo(&ainfo);
533
534   /* If AC powered */
535   if(ainfo.ac_line_status == OLSR_AC_POWERED)
536     return 6;
537
538   /* If battery powered 
539    *
540    * juice > 78% will: 3
541    * 78% > juice > 26% will: 2
542    * 26% > juice will: 1
543    */
544   return (ainfo.battery_percentage / 26);
545 }
546
547
548
549 /**
550  *Termination function to be called whenever a error occures
551  *that requires the daemon to terminate
552  *
553  *@param msg the message to write to the syslog and possibly stdout
554  */
555
556 void
557 olsr_exit(const char *msg, int val)
558 {
559   olsr_printf(1, "OLSR EXIT: %s\n", msg);
560   olsr_syslog(OLSR_LOG_ERR, "olsrd exit: %s\n", msg);
561   fflush(stdout);
562   exit_value = val;
563
564   raise(SIGTERM);
565 }
566
567
568 /**
569  *Wrapper for malloc(3) that does error-checking
570  *
571  *@param size the number of bytes to allocalte
572  *@param caller a string identifying the caller for
573  *use in error messaging
574  *
575  *@return a void pointer to the memory allocated
576  */
577 void *
578 olsr_malloc(size_t size, const char *id)
579 {
580   void *ptr;
581
582   if((ptr = malloc(size)) == 0) 
583     {
584       olsr_printf(1, "OUT OF MEMORY: %s\n", strerror(errno));
585       olsr_syslog(OLSR_LOG_ERR, "olsrd: out of memory!: %m\n");
586       olsr_exit((char *)id, EXIT_FAILURE);
587     }
588   return ptr;
589 }
590
591
592 /**
593  *Wrapper for printf that prints to a specific
594  *debuglevel upper limit
595  *
596  */
597
598 inline int
599 olsr_printf(int loglevel, char *format, ...)
600 {
601   va_list arglist;
602
603   if(loglevel <= olsr_cnf->debug_level)
604     {
605       va_start(arglist, format);
606       
607       vprintf(format, arglist);
608       
609       va_end(arglist);
610     }
611
612
613   return 0;
614 }