41f69fe5face152faeda1be72a023988838766cb
[olsrd.git] / src / interfaces.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include "defs.h"
43 #include "interfaces.h"
44 #include "scheduler.h"
45 #include "olsr.h"
46 #include "parser.h"
47 #include "net_olsr.h"
48 #include "ipcalc.h"
49 #include "common/string.h"
50 #include "common/avl.h"
51 #include "olsr_logging.h"
52 #include "os_net.h"
53
54 #include <signal.h>
55 #include <unistd.h>
56 #include <assert.h>
57
58 #define BUFSPACE  (127*1024)    /* max. input buffer size to request */
59
60 /* The interface list head */
61 struct list_entity interface_head;
62
63 /* tree of lost interface IPs */
64 struct avl_tree interface_lost_tree;
65
66 /* Ifchange functions */
67 struct ifchgf {
68   ifchg_cb_func function;
69   struct ifchgf *next;
70 };
71
72 static struct ifchgf *ifchgf_list = NULL;
73
74
75 /* Some cookies for stats keeping */
76 static struct olsr_cookie_info *interface_mem_cookie = NULL;
77 static struct olsr_cookie_info *interface_lost_mem_cookie = NULL;
78
79 static struct olsr_timer_info *interface_poll_timerinfo = NULL;
80 static struct olsr_timer_info *hello_gen_timerinfo = NULL;
81
82 static void check_interface_updates(void *);
83
84 /**
85  * Do initialization of various data needed for network interface management.
86  * This function also tries to set up the given interfaces.
87  *
88  * @return if more than zero interfaces were configured
89  */
90 bool
91 init_interfaces(void)
92 {
93   struct olsr_if_config *tmp_if;
94
95   /* Initial values */
96   list_init_head(&interface_head);
97   avl_init(&interface_lost_tree, avl_comp_default, false, NULL);
98
99   /*
100    * Get some cookies for getting stats to ease troubleshooting.
101    */
102   interface_mem_cookie = olsr_create_memcookie("Interface", sizeof(struct interface));
103
104   interface_lost_mem_cookie = olsr_create_memcookie("Interface lost", sizeof(struct interface_lost));
105
106   interface_poll_timerinfo = olsr_alloc_timerinfo("Interface Polling", &check_interface_updates, true);
107   hello_gen_timerinfo = olsr_alloc_timerinfo("Hello Generation", &generate_hello, true);
108
109   OLSR_INFO(LOG_INTERFACE, "\n ---- Interface configuration ---- \n\n");
110
111   /* Run trough all interfaces immediately */
112   for (tmp_if = olsr_cnf->if_configs; tmp_if != NULL; tmp_if = tmp_if->next) {
113     add_interface(tmp_if);
114   }
115
116   /* Kick a periodic timer for the network interface update function */
117   olsr_start_timer(olsr_cnf->nic_chgs_pollrate, 5,
118                    NULL, interface_poll_timerinfo);
119
120   return (!list_is_empty(&interface_head));
121 }
122
123 static void remove_lost_interface_ip(struct interface_lost *lost) {
124 #if !defined(REMOVE_LOG_DEBUG)
125   struct ipaddr_str buf;
126 #endif
127
128   OLSR_DEBUG(LOG_INTERFACE, "Remove %s from lost interface list\n",
129       olsr_ip_to_string(&buf, &lost->ip));
130   avl_delete(&interface_lost_tree, &lost->node);
131   olsr_cookie_free(interface_lost_mem_cookie, lost);
132 }
133
134 static void add_lost_interface_ip(union olsr_ip_addr *ip, uint32_t hello_timeout) {
135   struct interface_lost *lost;
136 #if !defined(REMOVE_LOG_DEBUG)
137   struct ipaddr_str buf;
138 #endif
139
140   lost = olsr_cookie_malloc(interface_lost_mem_cookie);
141   lost->node.key = &lost->ip;
142   lost->ip = *ip;
143   lost->valid_until = olsr_getTimestamp(hello_timeout * 2);
144   avl_insert(&interface_lost_tree, &lost->node);
145
146   OLSR_DEBUG(LOG_INTERFACE, "Added %s to lost interface list for %d ms\n",
147       olsr_ip_to_string(&buf, ip), hello_timeout*2);
148 }
149
150 static struct interface_lost *get_lost_interface_ip(union olsr_ip_addr *ip) {
151   struct interface_lost *lost;
152   assert(ip);
153   lost = avl_find_element(&interface_lost_tree, ip, lost, node);
154   return lost;
155 }
156
157 bool
158 is_lost_interface_ip(union olsr_ip_addr *ip) {
159   assert(ip);
160   return get_lost_interface_ip(ip) != NULL;
161 }
162
163 void destroy_interfaces(void) {
164   struct interface *iface;
165   struct interface_lost *lost;
166   struct list_iterator iterator;
167
168   OLSR_FOR_ALL_INTERFACES(iface, iterator) {
169     struct interface **ptr = &iface;
170     remove_interface(ptr);
171   }
172
173   OLSR_FOR_ALL_LOSTIF_ENTRIES(lost, iterator) {
174     remove_lost_interface_ip(lost);
175   }
176 }
177
178 struct interface *
179 add_interface(struct olsr_if_config *iface) {
180   struct interface *ifp;
181
182   ifp = olsr_cookie_malloc(interface_mem_cookie);
183   if ((os_init_interface(ifp, iface))) {
184     olsr_cookie_free(interface_mem_cookie, ifp);
185     return NULL;
186   }
187
188   if (olsr_cnf->ip_version == AF_INET) {
189     /* IP version 4 */
190     /*
191      * We create one socket for each interface and bind
192      * the socket to it. This to ensure that we can control
193      * on what interface the message is transmitted
194      */
195     ifp->olsr_socket = getsocket4(BUFSPACE, ifp, false, olsr_cnf->olsr_port);
196     ifp->send_socket = getsocket4(0, ifp, true, olsr_cnf->olsr_port);
197
198     if (ifp->olsr_socket < 0 || ifp->send_socket < 0) {
199       OLSR_ERROR(LOG_INTERFACE, "Could not initialize socket... exiting!\n\n");
200       olsr_exit(EXIT_FAILURE);
201     }
202   } else {
203     /* IP version 6 */
204
205     /*
206      * We create one socket for each interface and bind
207      * the socket to it. This to ensure that we can control
208      * on what interface the message is transmitted
209      */
210     ifp->olsr_socket = getsocket6(BUFSPACE, ifp, false, olsr_cnf->olsr_port);
211     ifp->send_socket = getsocket6(0, ifp, true, olsr_cnf->olsr_port);
212
213     if (ifp->olsr_socket < 0 || ifp->send_socket < 0) {
214       OLSR_ERROR(LOG_INTERFACE, "Could not initialize socket... exiting!\n\n");
215       olsr_exit(EXIT_FAILURE);
216     }
217
218     join_mcast(ifp, ifp->olsr_socket);
219   }
220
221   set_buffer_timer(ifp);
222
223   /* Register sockets */
224   add_olsr_socket(ifp->olsr_socket, &olsr_input, NULL, NULL, SP_PR_READ);
225   add_olsr_socket(ifp->send_socket, &olsr_input, NULL, NULL, SP_PR_READ);
226
227   os_set_olsr_socketoptions(ifp->olsr_socket);
228   os_set_olsr_socketoptions(ifp->send_socket);
229
230   /*
231    *Initialize packet sequencenumber as a random 16bit value
232    */
233   ifp->olsr_seqnum = random() & 0xFFFF;
234
235   /*
236    * Set main address if it's not set
237    */
238   if (olsr_ipcmp(&all_zero, &olsr_cnf->router_id) == 0) {
239     struct ipaddr_str buf;
240
241     olsr_cnf->router_id = ifp->ip_addr;
242     OLSR_INFO(LOG_INTERFACE, "New main address: %s\n", olsr_ip_to_string(&buf, &olsr_cnf->router_id));
243
244     /* initialize representation of this node in tc_set */
245     olsr_change_myself_tc();
246   }
247
248   /* Set up buffer */
249   net_add_buffer(ifp);
250
251   /*
252    * Register functions for periodic message generation
253    */
254   ifp->hello_gen_timer =
255     olsr_start_timer(iface->cnf->hello_params.emission_interval,
256                      HELLO_JITTER, ifp, hello_gen_timerinfo);
257   ifp->hello_interval = iface->cnf->hello_params.emission_interval;
258   ifp->hello_validity = iface->cnf->hello_params.validity_time;
259
260   ifp->mode = iface->cnf->mode;
261
262   /*
263    * Call possible ifchange functions registered by plugins
264    */
265   run_ifchg_cbs(ifp, IFCHG_IF_ADD);
266
267   /*
268    * The interface is ready, lock it.
269    */
270   lock_interface(ifp);
271
272   /*
273    * Link to config.
274    */
275   iface->interf = ifp;
276   lock_interface(iface->interf);
277
278   /* Queue */
279   list_add_before(&interface_head, &ifp->int_node);
280
281   return ifp;
282 }
283
284 /**
285  * Callback function for periodic check of interface parameters.
286  */
287 static void
288 check_interface_updates(void *foo __attribute__ ((unused)))
289 {
290   struct olsr_if_config *tmp_if;
291   struct interface_lost *lost;
292   struct list_iterator iterator;
293
294   OLSR_DEBUG(LOG_INTERFACE, "Checking for updates in the interface set\n");
295
296   for (tmp_if = olsr_cnf->if_configs; tmp_if != NULL; tmp_if = tmp_if->next) {
297
298     if (!tmp_if->cnf->autodetect_chg) {
299       /* Don't check this interface */
300       OLSR_DEBUG(LOG_INTERFACE, "Not checking interface %s\n", tmp_if->name);
301       continue;
302     }
303
304     if (tmp_if->interf) {
305       chk_if_changed(tmp_if);
306     } else {
307       if (add_interface(tmp_if)) {
308         lost = get_lost_interface_ip(&tmp_if->interf->ip_addr);
309         if (lost) {
310           remove_lost_interface_ip(lost);
311         }
312       }
313     }
314   }
315
316   /* clean up lost interface tree */
317   OLSR_FOR_ALL_LOSTIF_ENTRIES(lost, iterator) {
318     if (olsr_isTimedOut(lost->valid_until)) {
319       remove_lost_interface_ip(lost);
320     }
321   }
322 }
323
324 /**
325  * Remove and cleanup a physical interface.
326  */
327 void
328 remove_interface(struct interface **pinterf)
329 {
330   struct interface *ifp = *pinterf;
331
332   if (!ifp) {
333     return;
334   }
335
336   OLSR_INFO(LOG_INTERFACE, "Removing interface %s\n", ifp->int_name);
337
338   olsr_delete_link_entry_by_if(ifp);
339
340   /*
341    * Call possible ifchange functions registered by plugins
342    */
343   run_ifchg_cbs(ifp, IFCHG_IF_REMOVE);
344
345   /* Dequeue */
346   list_remove(&ifp->int_node);
347
348   /* Remove output buffer */
349   net_remove_buffer(ifp);
350
351   /*
352    * Deregister functions for periodic message generation
353    */
354   olsr_stop_timer(ifp->hello_gen_timer);
355   ifp->hello_gen_timer = NULL;
356
357   /*
358    * Stop interface pacing.
359    */
360   olsr_stop_timer(ifp->buffer_hold_timer);
361   ifp->buffer_hold_timer = NULL;
362
363   /*
364    * remember the IP for some time
365    */
366   add_lost_interface_ip(&ifp->ip_addr, ifp->hello_validity);
367
368   /*
369    * Unlink from config.
370    */
371   unlock_interface(*pinterf);
372   *pinterf = NULL;
373
374   /* Close olsr socket */
375   remove_olsr_socket(ifp->olsr_socket, &olsr_input, NULL);
376   CLOSESOCKET(ifp->olsr_socket);
377   CLOSESOCKET(ifp->send_socket);
378   ifp->olsr_socket = -1;
379
380 //  free(ifp->int_name);
381   unlock_interface(ifp);
382
383   if (list_is_empty(&interface_head) && !olsr_cnf->allow_no_interfaces) {
384     OLSR_ERROR(LOG_INTERFACE, "No more active interfaces - exiting.\n");
385     olsr_exit(EXIT_FAILURE);
386   }
387 }
388
389 void
390 run_ifchg_cbs(struct interface *ifp, int flag)
391 {
392   struct ifchgf *tmp;
393   for (tmp = ifchgf_list; tmp != NULL; tmp = tmp->next) {
394     tmp->function(ifp, flag);
395   }
396 }
397
398 /**
399  * Find the local interface with a given address.
400  *
401  * @param addr the address to check.
402  * @return the interface struct representing the interface
403  * that matched the address.
404  */
405 struct interface *
406 if_ifwithaddr(const union olsr_ip_addr *addr)
407 {
408   struct interface *ifp;
409   struct list_iterator iterator;
410   if (!addr) {
411     return NULL;
412   }
413
414   OLSR_FOR_ALL_INTERFACES(ifp, iterator) {
415     if (olsr_ipcmp(&ifp->ip_addr, addr) == 0) {
416       return ifp;
417     }
418   }
419   return NULL;
420 }
421
422 /**
423  * Find the interface with a given number.
424  *
425  * @param nr the number of the interface to find.
426  * @return return the interface struct representing the interface
427  * that matched the number.
428  */
429 struct interface *
430 if_ifwithsock(int fd)
431 {
432   struct interface *ifp;
433   struct list_iterator iterator;
434
435   OLSR_FOR_ALL_INTERFACES(ifp, iterator) {
436     if (ifp->olsr_socket == fd) {
437       return ifp;
438     }
439   }
440
441   return NULL;
442 }
443
444
445 /**
446  * Find the interface with a given label.
447  *
448  * @param if_name the label of the interface to find.
449  * @return return the interface struct representing the interface
450  * that matched the label.
451  */
452 struct interface *
453 if_ifwithname(const char *if_name)
454 {
455   struct interface *ifp;
456   struct list_iterator iterator;
457
458   OLSR_FOR_ALL_INTERFACES(ifp, iterator) {
459     /* good ol' strcmp should be sufficient here */
460     if (strcmp(ifp->int_name, if_name) == 0) {
461       return ifp;
462     }
463   }
464
465   return NULL;
466 }
467
468 /**
469  * Find the interface with a given interface index.
470  *
471  * @param iif_index of the interface to find.
472  * @return return the interface struct representing the interface
473  * that matched the iif_index.
474  */
475 struct interface *
476 if_ifwithindex(const int if_index)
477 {
478   struct interface *ifp;
479   struct list_iterator iterator;
480   OLSR_FOR_ALL_INTERFACES(ifp, iterator) {
481     if (ifp->if_index == if_index) {
482       return ifp;
483     }
484   }
485
486   return NULL;
487 }
488
489 /**
490  * Get an interface name for a given interface index
491  *
492  * @param iif_index of the interface to find.
493  * @return "" or interface name.
494  */
495 const char *
496 if_ifwithindex_name(const int if_index)
497 {
498   const struct interface *const ifp = if_ifwithindex(if_index);
499   return ifp == NULL ? "void" : ifp->int_name;
500 }
501
502 /**
503  * Lock an interface.
504  */
505 void
506 lock_interface(struct interface *ifp)
507 {
508   assert(ifp);
509
510   ifp->refcount++;
511 }
512
513 /**
514  * Unlock an interface and free it if the refcount went down to zero.
515  */
516 void
517 unlock_interface(struct interface *ifp)
518 {
519   /* Node must have a positive refcount balance */
520   assert(ifp->refcount);
521
522   if (--ifp->refcount) {
523     return;
524   }
525
526   /* Node must be dequeued at this point */
527   assert(!list_node_added(&ifp->int_node));
528
529   /* Free memory */
530   free(ifp->int_name);
531   olsr_cookie_free(interface_mem_cookie, ifp);
532 }
533
534
535 /**
536  * Add an ifchange function. These functions are called on all (non-initial)
537  * changes in the interface set.
538  */
539 void
540 add_ifchgf(ifchg_cb_func f)
541 {
542   struct ifchgf *tmp = olsr_malloc(sizeof(struct ifchgf), "Add ifchgfunction");
543
544   tmp->function = f;
545   tmp->next = ifchgf_list;
546   ifchgf_list = tmp;
547 }
548
549 #if 0
550
551 /*
552  * Remove an ifchange function
553  */
554 int
555 del_ifchgf(ifchg_cb_func f)
556 {
557   struct ifchgf *tmp, *prev;
558
559   for (tmp = ifchgf_list, prev = NULL; tmp != NULL; prev = tmp, tmp = tmp->next) {
560     if (tmp->function == f) {
561       /* Remove entry */
562       if (prev == NULL) {
563         ifchgf_list = tmp->next;
564       } else {
565         prev->next = tmp->next;
566       }
567       free(tmp);
568       return 1;
569     }
570   }
571   return 0;
572 }
573 #endif
574
575 /*
576  * Local Variables:
577  * c-basic-offset: 2
578  * indent-tabs-mode: nil
579  * End:
580  */