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