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