Fix segfault in if-down path
[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 "common/avl_olsr_comp.h"
43 #include "common/avl.h"
44 #include "common/string.h"
45
46 #include "defs.h"
47 #include "interfaces.h"
48 #include "olsr_timer.h"
49 #include "olsr_socket.h"
50 #include "olsr.h"
51 #include "parser.h"
52 #include "net_olsr.h"
53 #include "ipcalc.h"
54 #include "olsr_logging.h"
55 #include "os_net.h"
56
57 #include <signal.h>
58 #include <unistd.h>
59 #include <assert.h>
60
61 #define BUFSPACE  (127*1024)    /* max. input buffer size to request */
62
63 const char *INTERFACE_MODE_NAMES[] = {
64   "mesh",
65   "ether"
66 };
67
68 /* The interface list head */
69 struct list_entity interface_head;
70
71 /* tree of lost interface IPs */
72 struct avl_tree interface_lost_tree;
73
74 /* Ifchange functions */
75 struct ifchgf {
76   ifchg_cb_func function;
77   struct ifchgf *next;
78 };
79
80 static struct ifchgf *ifchgf_list = NULL;
81
82 /* Some cookies for stats keeping */
83 static struct olsr_memcookie_info *interface_mem_cookie = NULL;
84 static struct olsr_memcookie_info *interface_lost_mem_cookie = NULL;
85
86 static struct olsr_timer_info *interface_poll_timerinfo = NULL;
87 static struct olsr_timer_info *hello_gen_timerinfo = NULL;
88
89 static void check_interface_updates(void *);
90
91 /**
92  * Do initialization of various data needed for network interface management.
93  * This function also tries to set up the given interfaces.
94  *
95  * @return if more than zero interfaces were configured
96  */
97 bool
98 init_interfaces(void)
99 {
100   struct olsr_if_config *tmp_if;
101
102   /* Initial values */
103   list_init_head(&interface_head);
104   avl_init(&interface_lost_tree, avl_comp_default, false, NULL);
105
106   /*
107    * Get some cookies for getting stats to ease troubleshooting.
108    */
109   interface_mem_cookie = olsr_memcookie_add("Interface", sizeof(struct interface));
110
111   interface_lost_mem_cookie = olsr_memcookie_add("Interface lost", sizeof(struct interface_lost));
112
113   interface_poll_timerinfo = olsr_timer_add("Interface Polling", &check_interface_updates, true);
114   hello_gen_timerinfo = olsr_timer_add("Hello Generation", &generate_hello, true);
115
116   OLSR_INFO(LOG_INTERFACE, "\n ---- Interface configuration ---- \n\n");
117
118   /* Run trough all interfaces immediately */
119   for (tmp_if = olsr_cnf->if_configs; tmp_if != NULL; tmp_if = tmp_if->next) {
120     add_interface(tmp_if);
121   }
122
123   /* Kick a periodic timer for the network interface update function */
124   olsr_timer_start(olsr_cnf->nic_chgs_pollrate, 5,
125                    NULL, interface_poll_timerinfo);
126
127   return (!list_is_empty(&interface_head));
128 }
129
130 static void remove_lost_interface_ip(struct interface_lost *lost) {
131 #if !defined(REMOVE_LOG_DEBUG)
132   struct ipaddr_str buf;
133 #endif
134
135   OLSR_DEBUG(LOG_INTERFACE, "Remove %s from lost interface list\n",
136       olsr_ip_to_string(&buf, &lost->ip));
137   avl_delete(&interface_lost_tree, &lost->node);
138   olsr_memcookie_free(interface_lost_mem_cookie, lost);
139 }
140
141 static void add_lost_interface_ip(union olsr_ip_addr *ip, uint32_t hello_timeout) {
142   struct interface_lost *lost;
143 #if !defined(REMOVE_LOG_DEBUG)
144   struct ipaddr_str buf;
145 #endif
146
147   lost = olsr_memcookie_malloc(interface_lost_mem_cookie);
148   lost->node.key = &lost->ip;
149   lost->ip = *ip;
150   lost->valid_until = olsr_clock_getAbsolute(hello_timeout * 2);
151   avl_insert(&interface_lost_tree, &lost->node);
152
153   OLSR_DEBUG(LOG_INTERFACE, "Added %s to lost interface list for %d ms\n",
154       olsr_ip_to_string(&buf, ip), hello_timeout*2);
155 }
156
157 static struct interface_lost *get_lost_interface_ip(union olsr_ip_addr *ip) {
158   struct interface_lost *lost;
159   assert(ip);
160   lost = avl_find_element(&interface_lost_tree, ip, lost, node);
161   return lost;
162 }
163
164 bool
165 is_lost_interface_ip(union olsr_ip_addr *ip) {
166   assert(ip);
167   return get_lost_interface_ip(ip) != NULL;
168 }
169
170 void destroy_interfaces(void) {
171   struct interface *iface, *iface_iterator;
172   struct interface_lost *lost, *lost_iterator;
173
174   OLSR_FOR_ALL_INTERFACES(iface, iface_iterator) {
175     remove_interface(iface);
176   }
177
178   OLSR_FOR_ALL_LOSTIF_ENTRIES(lost, lost_iterator) {
179     remove_lost_interface_ip(lost);
180   }
181 }
182
183 struct interface *
184 add_interface(struct olsr_if_config *iface) {
185   struct interface *ifp;
186   int sock_rcv, sock_send;
187
188   ifp = olsr_memcookie_malloc(interface_mem_cookie);
189   ifp->int_name = iface->name;
190
191   if ((os_init_interface(ifp, iface))) {
192     olsr_memcookie_free(interface_mem_cookie, ifp);
193     return NULL;
194   }
195
196   sock_rcv = os_getsocket46(olsr_cnf->ip_version, ifp->int_name, olsr_cnf->olsr_port, BUFSPACE, NULL);
197   sock_send = os_getsocket46(olsr_cnf->ip_version, ifp->int_name, olsr_cnf->olsr_port, BUFSPACE, &ifp->int_multicast);
198   if (sock_rcv < 0 || sock_send < 0) {
199     OLSR_ERROR(LOG_INTERFACE, "Could not initialize socket... exiting!\n\n");
200     olsr_exit(EXIT_FAILURE);
201   }
202
203   set_buffer_timer(ifp);
204
205   /* Register sockets */
206   ifp->olsr_socket = olsr_socket_add(sock_rcv, &olsr_input, NULL, OLSR_SOCKET_READ);
207   ifp->send_socket = olsr_socket_add(sock_send, &olsr_input, NULL, OLSR_SOCKET_READ);
208
209   os_socket_set_olsr_options(ifp, ifp->olsr_socket->fd, &ifp->int_multicast);
210   os_socket_set_olsr_options(ifp, ifp->send_socket->fd, &ifp->int_multicast);
211
212   /*
213    *Initialize packet sequencenumber as a random 16bit value
214    */
215   ifp->olsr_seqnum = random() & 0xFFFF;
216
217   /*
218    * Set main address if it's not set
219    */
220   if (olsr_ipcmp(&all_zero, &olsr_cnf->router_id) == 0) {
221 #if !defined(REMOVE_LOG_INFO)
222     struct ipaddr_str buf;
223 #endif
224     olsr_cnf->router_id = ifp->ip_addr;
225     OLSR_INFO(LOG_INTERFACE, "New main address: %s\n", olsr_ip_to_string(&buf, &olsr_cnf->router_id));
226
227     /* initialize representation of this node in tc_set */
228     olsr_change_myself_tc();
229   }
230
231   /* Set up buffer */
232   net_add_buffer(ifp);
233
234   /*
235    * Register functions for periodic message generation
236    */
237   ifp->hello_gen_timer =
238     olsr_timer_start(iface->cnf->hello_params.emission_interval,
239                      HELLO_JITTER, ifp, hello_gen_timerinfo);
240   ifp->hello_interval = iface->cnf->hello_params.emission_interval;
241   ifp->hello_validity = iface->cnf->hello_params.validity_time;
242
243   ifp->mode = iface->cnf->mode;
244
245   /*
246    * Call possible ifchange functions registered by plugins
247    */
248   run_ifchg_cbs(ifp, IFCHG_IF_ADD);
249
250   /*
251    * The interface is ready, lock it.
252    */
253   lock_interface(ifp);
254
255   /*
256    * Link to config.
257    */
258   iface->interf = ifp;
259   ifp->if_cfg = iface;
260   lock_interface(iface->interf);
261
262   /* Queue */
263   list_add_before(&interface_head, &ifp->int_node);
264
265   return ifp;
266 }
267
268 /**
269  * Callback function for periodic check of interface parameters.
270  */
271 static void
272 check_interface_updates(void *foo __attribute__ ((unused)))
273 {
274   struct olsr_if_config *tmp_if;
275   struct interface_lost *lost, *iterator;
276
277   OLSR_DEBUG(LOG_INTERFACE, "Checking for updates in the interface set\n");
278
279   for (tmp_if = olsr_cnf->if_configs; tmp_if != NULL; tmp_if = tmp_if->next) {
280
281     if (!tmp_if->cnf->autodetect_chg) {
282       /* Don't check this interface */
283       OLSR_DEBUG(LOG_INTERFACE, "Not checking interface %s\n", tmp_if->name);
284       continue;
285     }
286
287     if (tmp_if->interf) {
288       chk_if_changed(tmp_if);
289     } else {
290       if (add_interface(tmp_if)) {
291         lost = get_lost_interface_ip(&tmp_if->interf->ip_addr);
292         if (lost) {
293           remove_lost_interface_ip(lost);
294         }
295       }
296     }
297   }
298
299   /* clean up lost interface tree */
300   OLSR_FOR_ALL_LOSTIF_ENTRIES(lost, iterator) {
301     if (olsr_clock_isPast(lost->valid_until)) {
302       remove_lost_interface_ip(lost);
303     }
304   }
305 }
306
307 /**
308  * Remove and cleanup a physical interface.
309  */
310 void
311 remove_interface(struct interface *ifp)
312 {
313   if (!ifp) {
314     return;
315   }
316
317   OLSR_INFO(LOG_INTERFACE, "Removing interface %s\n", ifp->int_name);
318
319   ifp->if_cfg->interf = NULL;
320
321   os_cleanup_interface(ifp);
322
323   olsr_delete_link_entry_by_if(ifp);
324
325   /*
326    * Call possible ifchange functions registered by plugins
327    */
328   run_ifchg_cbs(ifp, IFCHG_IF_REMOVE);
329
330   /* Dequeue */
331   list_remove(&ifp->int_node);
332
333   /* Remove output buffer */
334   net_remove_buffer(ifp);
335
336   /*
337    * Deregister functions for periodic message generation
338    */
339   olsr_timer_stop(ifp->hello_gen_timer);
340   ifp->hello_gen_timer = NULL;
341
342   /*
343    * Stop interface pacing.
344    */
345   olsr_timer_stop(ifp->buffer_hold_timer);
346   ifp->buffer_hold_timer = NULL;
347
348   /*
349    * remember the IP for some time
350    */
351   add_lost_interface_ip(&ifp->ip_addr, ifp->hello_validity);
352
353   /*
354    * Unlink from config.
355    */
356   unlock_interface(ifp);
357
358   /* Close olsr socket */
359   os_close(ifp->olsr_socket->fd);
360   os_close(ifp->send_socket->fd);
361
362   olsr_socket_remove(ifp->olsr_socket);
363   olsr_socket_remove(ifp->send_socket);
364
365   ifp->int_name = NULL;
366   unlock_interface(ifp);
367
368   if (list_is_empty(&interface_head) && !olsr_cnf->allow_no_interfaces) {
369     OLSR_ERROR(LOG_INTERFACE, "No more active interfaces - exiting.\n");
370     olsr_exit(EXIT_FAILURE);
371   }
372 }
373
374 void
375 run_ifchg_cbs(struct interface *ifp, int flag)
376 {
377   struct ifchgf *tmp;
378   for (tmp = ifchgf_list; tmp != NULL; tmp = tmp->next) {
379     tmp->function(ifp, flag);
380   }
381 }
382
383 /**
384  * Find the local interface with a given address.
385  *
386  * @param addr the address to check.
387  * @return the interface struct representing the interface
388  * that matched the address.
389  */
390 struct interface *
391 if_ifwithaddr(const union olsr_ip_addr *addr)
392 {
393   struct interface *ifp, *iterator;
394   if (!addr) {
395     return NULL;
396   }
397
398   OLSR_FOR_ALL_INTERFACES(ifp, iterator) {
399     if (olsr_ipcmp(&ifp->ip_addr, addr) == 0) {
400       return ifp;
401     }
402   }
403   return NULL;
404 }
405
406 /**
407  * Find the interface with a given number.
408  *
409  * @param nr the number of the interface to find.
410  * @return return the interface struct representing the interface
411  * that matched the number.
412  */
413 struct interface *
414 if_ifwithsock(int fd)
415 {
416   struct interface *ifp, *iterator;
417
418   OLSR_FOR_ALL_INTERFACES(ifp, iterator) {
419     if (ifp->olsr_socket->fd == fd) {
420       return ifp;
421     }
422     if (ifp->send_socket->fd == fd) {
423       return ifp;
424     }
425   }
426
427   return NULL;
428 }
429
430
431 /**
432  * Find the interface with a given label.
433  *
434  * @param if_name the label of the interface to find.
435  * @return return the interface struct representing the interface
436  * that matched the label.
437  */
438 struct interface *
439 if_ifwithname(const char *if_name)
440 {
441   struct interface *ifp, *iterator;
442
443   OLSR_FOR_ALL_INTERFACES(ifp, iterator) {
444     /* good ol' strcmp should be sufficient here */
445     if (strcmp(ifp->int_name, if_name) == 0) {
446       return ifp;
447     }
448   }
449
450   return NULL;
451 }
452
453 /**
454  * Find the interface with a given interface index.
455  *
456  * @param iif_index of the interface to find.
457  * @return return the interface struct representing the interface
458  * that matched the iif_index.
459  */
460 struct interface *
461 if_ifwithindex(const int if_index)
462 {
463   struct interface *ifp, *iterator;
464   OLSR_FOR_ALL_INTERFACES(ifp, iterator) {
465     if (ifp->if_index == if_index) {
466       return ifp;
467     }
468   }
469
470   return NULL;
471 }
472
473 /**
474  * Get an interface name for a given interface index
475  *
476  * @param iif_index of the interface to find.
477  * @return "" or interface name.
478  */
479 const char *
480 if_ifwithindex_name(const int if_index)
481 {
482   const struct interface *const ifp = if_ifwithindex(if_index);
483   return ifp == NULL ? "void" : ifp->int_name;
484 }
485
486 /**
487  * Lock an interface.
488  */
489 void
490 lock_interface(struct interface *ifp)
491 {
492   assert(ifp);
493
494   ifp->refcount++;
495 }
496
497 /**
498  * Unlock an interface and free it if the refcount went down to zero.
499  */
500 void
501 unlock_interface(struct interface *ifp)
502 {
503   /* Node must have a positive refcount balance */
504   assert(ifp->refcount);
505
506   if (--ifp->refcount) {
507     return;
508   }
509
510   /* Node must be dequeued at this point */
511   assert(!list_node_added(&ifp->int_node));
512
513   /* Free memory */
514   free(ifp->int_name);
515   olsr_memcookie_free(interface_mem_cookie, ifp);
516 }
517
518
519 /**
520  * Add an ifchange function. These functions are called on all (non-initial)
521  * changes in the interface set.
522  */
523 void
524 add_ifchgf(ifchg_cb_func f)
525 {
526   struct ifchgf *tmp = olsr_malloc(sizeof(struct ifchgf), "Add ifchgfunction");
527
528   tmp->function = f;
529   tmp->next = ifchgf_list;
530   ifchgf_list = tmp;
531 }
532
533 #if 0
534
535 /*
536  * Remove an ifchange function
537  */
538 int
539 del_ifchgf(ifchg_cb_func f)
540 {
541   struct ifchgf *tmp, *prev;
542
543   for (tmp = ifchgf_list, prev = NULL; tmp != NULL; prev = tmp, tmp = tmp->next) {
544     if (tmp->function == f) {
545       /* Remove entry */
546       if (prev == NULL) {
547         ifchgf_list = tmp->next;
548       } else {
549         prev->next = tmp->next;
550       }
551       free(tmp);
552       return 1;
553     }
554   }
555   return 0;
556 }
557 #endif
558
559 /*
560  * Local Variables:
561  * c-basic-offset: 2
562  * indent-tabs-mode: nil
563  * End:
564  */