2168b4719057cffd8fe6a8cb47437a439d8c887d
[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 "ifnet.h"
45 #include "scheduler.h"
46 #include "olsr.h"
47 #include "log.h"
48 #include "parser.h"
49 #include "net_olsr.h"
50 #include "ipcalc.h"
51 #include "common/string.h"
52
53 #include <signal.h>
54 #include <unistd.h>
55 #include <assert.h>
56
57 /* The interface list head */
58 struct list_node interface_head;
59
60 /* Ifchange functions */
61 struct ifchgf {
62   ifchg_cb_func function;
63   struct ifchgf *next;
64 };
65
66 static struct ifchgf *ifchgf_list = NULL;
67
68
69 /* Some cookies for stats keeping */
70 struct olsr_cookie_info *interface_mem_cookie = NULL;
71 struct olsr_cookie_info *interface_poll_timer_cookie = NULL;
72 struct olsr_cookie_info *hello_gen_timer_cookie = NULL;
73 struct olsr_cookie_info *tc_gen_timer_cookie = NULL;
74 struct olsr_cookie_info *mid_gen_timer_cookie = NULL;
75 struct olsr_cookie_info *hna_gen_timer_cookie = NULL;
76 struct olsr_cookie_info *buffer_hold_timer_cookie = NULL;
77
78 static void check_interface_updates(void *);
79
80 /**
81  * Do initialization of various data needed for network interface management.
82  * This function also tries to set up the given interfaces.
83  *
84  * @return if more than zero interfaces were configured
85  */
86 bool
87 ifinit(void)
88 {
89   struct olsr_if_config *tmp_if;
90
91   /* Initial values */
92   list_head_init(&interface_head);
93
94   /*
95    * Get some cookies for getting stats to ease troubleshooting.
96    */
97   interface_mem_cookie =
98     olsr_alloc_cookie("Interface", OLSR_COOKIE_TYPE_MEMORY);
99   olsr_cookie_set_memory_size(interface_mem_cookie, sizeof(struct interface));
100
101   interface_poll_timer_cookie =
102     olsr_alloc_cookie("Interface Polling", OLSR_COOKIE_TYPE_TIMER);
103   buffer_hold_timer_cookie =
104     olsr_alloc_cookie("Buffer Hold", OLSR_COOKIE_TYPE_TIMER);
105
106   hello_gen_timer_cookie =
107     olsr_alloc_cookie("Hello Generation", OLSR_COOKIE_TYPE_TIMER);
108   tc_gen_timer_cookie =
109     olsr_alloc_cookie("TC Generation", OLSR_COOKIE_TYPE_TIMER);
110   mid_gen_timer_cookie =
111     olsr_alloc_cookie("MID Generation", OLSR_COOKIE_TYPE_TIMER);
112   hna_gen_timer_cookie =
113     olsr_alloc_cookie("HNA Generation", OLSR_COOKIE_TYPE_TIMER);
114
115   OLSR_PRINTF(1, "\n ---- Interface configuration ---- \n\n");
116
117   /* Run trough all interfaces immediately */
118   for (tmp_if = olsr_cnf->if_configs; tmp_if != NULL; tmp_if = tmp_if->next) {
119     chk_if_up(tmp_if, 1);
120   }
121
122   /* Kick a periodic timer for the network interface update function */
123   olsr_start_timer(olsr_cnf->nic_chgs_pollrate * MSEC_PER_SEC, 5,
124                    OLSR_TIMER_PERIODIC, &check_interface_updates, NULL,
125                    interface_poll_timer_cookie->ci_id);
126
127   return (!list_is_empty(&interface_head));
128 }
129
130 /**
131  * Callback function for periodic check of interface parameters.
132  */
133 static void
134 check_interface_updates(void *foo __attribute__((unused)))
135 {
136   struct olsr_if_config *tmp_if;
137
138 #ifdef DEBUG
139   OLSR_PRINTF(3, "Checking for updates in the interface set\n");
140 #endif
141
142   for (tmp_if = olsr_cnf->if_configs; tmp_if != NULL; tmp_if = tmp_if->next) {
143
144     if (!tmp_if->cnf->autodetect_chg) {
145 #ifdef DEBUG
146       /* Don't check this interface */
147       OLSR_PRINTF(3, "Not checking interface %s\n", tmp_if->name);
148 #endif
149       continue;
150     }
151
152     if (tmp_if->interf) {
153       chk_if_changed(tmp_if);
154     } else {
155       chk_if_up(tmp_if, 3);
156     }
157   }
158 }
159
160 /**
161  * Remove and cleanup a physical interface.
162  */
163 void
164 remove_interface(struct interface **pinterf)
165 {
166   struct interface *ifp = *pinterf;
167   struct ipaddr_str buf;
168
169   if (!ifp) {
170     return;
171   }
172
173   OLSR_INFO(LOG_NETWORKING, "Removing interface %s\n", ifp->int_name);
174
175   olsr_delete_link_entry_by_if(ifp);
176
177   /*
178    * Call possible ifchange functions registered by plugins
179    */
180   run_ifchg_cbs(ifp, IFCHG_IF_REMOVE);
181
182   /* Dequeue */
183   list_remove(&ifp->int_node);
184
185   /* Remove output buffer */
186   net_remove_buffer(ifp);
187
188   /* Check main addr */
189   if (!olsr_cnf->fixed_origaddr && olsr_ipequal(&olsr_cnf->router_id, &ifp->ip_addr)) {
190     if (list_is_empty(&interface_head)) {
191       /* No more interfaces */
192       memset(&olsr_cnf->router_id, 0, olsr_cnf->ipsize);
193       OLSR_PRINTF(1, "Removed last interface. Cleared main address.\n");
194     } else {
195
196       /* Grab the first interface in the list. */
197       olsr_cnf->router_id = list2interface(interface_head.next)->ip_addr;
198       olsr_ip_to_string(&buf, &olsr_cnf->router_id);
199       OLSR_INFO(LOG_NETWORKING, "New main address: %s\n", buf.buf);
200     }
201   }
202
203   /*
204    * Deregister functions for periodic message generation
205    */
206   olsr_stop_timer(ifp->hello_gen_timer);
207   olsr_stop_timer(ifp->tc_gen_timer);
208   olsr_stop_timer(ifp->mid_gen_timer);
209   olsr_stop_timer(ifp->hna_gen_timer);
210
211   /*
212    * Stop interface pacing.
213    */
214   olsr_stop_timer(ifp->buffer_hold_timer);
215
216   /*
217    * Unlink from config.
218    */
219   unlock_interface(*pinterf);
220   *pinterf = NULL;
221
222   /* Close olsr socket */
223   remove_olsr_socket(ifp->olsr_socket, &olsr_input, NULL);
224   CLOSESOCKET(ifp->olsr_socket);
225   ifp->olsr_socket = -1;
226
227   unlock_interface(ifp);
228
229   if (list_is_empty(&interface_head) && !olsr_cnf->allow_no_interfaces) {
230     OLSR_ERROR(LOG_NETWORKING, "No more active interfaces - exiting.\n");
231     olsr_exit(EXIT_FAILURE);
232   }
233 }
234
235 void
236 run_ifchg_cbs(struct interface *ifp, int flag)
237 {
238   struct ifchgf *tmp;
239   for (tmp = ifchgf_list; tmp != NULL; tmp = tmp->next) {
240     tmp->function(ifp, flag);
241   }
242 }
243
244 /**
245  * Find the local interface with a given address.
246  *
247  * @param addr the address to check.
248  * @return the interface struct representing the interface
249  * that matched the address.
250  */
251 struct interface *
252 if_ifwithaddr(const union olsr_ip_addr *addr)
253 {
254   struct interface *ifp;
255   if (!addr) {
256     return NULL;
257   }
258
259   if (olsr_cnf->ip_version == AF_INET) {
260
261     /* IPv4 */
262     OLSR_FOR_ALL_INTERFACES(ifp) {
263       if (ip4equal(&ifp->int_addr.sin_addr, &addr->v4)) {
264         return ifp;
265       }
266     } OLSR_FOR_ALL_INTERFACES_END(ifp);
267
268   } else {
269
270     /* IPv6 */
271     OLSR_FOR_ALL_INTERFACES(ifp) {
272       if (ip6equal(&ifp->int6_addr.sin6_addr, &addr->v6)) {
273         return ifp;
274       }
275     } OLSR_FOR_ALL_INTERFACES_END(ifp);
276   }
277   return NULL;
278 }
279
280 /**
281  * Find the interface with a given number.
282  *
283  * @param nr the number of the interface to find.
284  * @return return the interface struct representing the interface
285  * that matched the number.
286  */
287 struct interface *
288 if_ifwithsock(int fd)
289 {
290   struct interface *ifp;
291
292   OLSR_FOR_ALL_INTERFACES(ifp) {
293     if (ifp->olsr_socket == fd) {
294       return ifp;
295     }
296   } OLSR_FOR_ALL_INTERFACES_END(ifp);
297
298   return NULL;
299 }
300
301
302 /**
303  * Find the interface with a given label.
304  *
305  * @param if_name the label of the interface to find.
306  * @return return the interface struct representing the interface
307  * that matched the label.
308  */
309 struct interface *
310 if_ifwithname(const char *if_name)
311 {
312   struct interface *ifp;
313   OLSR_FOR_ALL_INTERFACES(ifp) {
314
315     /* good ol' strcmp should be sufficient here */
316     if (strcmp(ifp->int_name, if_name) == 0) {
317       return ifp;
318     }
319   } OLSR_FOR_ALL_INTERFACES_END(ifp);
320
321   return NULL;
322 }
323
324 #if 0
325 /**
326  * Find the interface with a given interface index.
327  *
328  * @param iif_index of the interface to find.
329  * @return return the interface struct representing the interface
330  * that matched the iif_index.
331  */
332 struct interface *
333 if_ifwithindex(const int if_index)
334 {
335   struct interface *ifp;
336   OLSR_FOR_ALL_INTERFACES(ifp) {
337     if (ifp->if_index == if_index) {
338       return ifp;
339     }
340   } OLSR_FOR_ALL_INTERFACES_END(ifp);
341
342   return NULL;
343 }
344 #endif
345
346 #if 0
347 /**
348  * Get an interface name for a given interface index
349  *
350  * @param iif_index of the interface to find.
351  * @return "" or interface name.
352  */
353 const char *
354 if_ifwithindex_name(const int if_index)
355 {
356   const struct interface *const ifp = if_ifwithindex(if_index);
357   return ifp == NULL ? "void" : ifp->int_name;
358 }
359 #endif
360
361 /**
362  * Lock an interface.
363  */
364 void
365 lock_interface(struct interface *ifp)
366 {
367   assert(ifp);
368
369   ifp->refcount++;
370 }
371
372 /**
373  * Unlock an interface and free it if the refcount went down to zero.
374  */
375 void
376 unlock_interface(struct interface *ifp)
377 {
378   /* Node must have a positive refcount balance */
379   assert(ifp->refcount);
380
381   if (--ifp->refcount) {
382     return;
383   }
384
385   /* Node must be dequeued at this point */
386   assert(!list_node_on_list(&ifp->int_node));
387
388   /* Free memory */
389   free(ifp->int_name);
390   olsr_cookie_free(interface_mem_cookie, ifp);
391 }
392
393
394 /**
395  * Add an ifchange function. These functions are called on all (non-initial)
396  * changes in the interface set.
397  */
398 void
399 add_ifchgf(ifchg_cb_func f)
400 {
401   struct ifchgf *tmp = olsr_malloc(sizeof(struct ifchgf), "Add ifchgfunction");
402
403   tmp->function = f;
404   tmp->next = ifchgf_list;
405   ifchgf_list = tmp;
406 }
407
408 #if 0
409 /*
410  * Remove an ifchange function
411  */
412 int
413 del_ifchgf(ifchg_cb_func f)
414 {
415   struct ifchgf *tmp, *prev;
416
417   for (tmp = ifchgf_list, prev = NULL;
418        tmp != NULL;
419        prev = tmp, tmp = tmp->next) {
420     if (tmp->function == f) {
421       /* Remove entry */
422       if (prev == NULL) {
423         ifchgf_list = tmp->next;
424       } else {
425         prev->next = tmp->next;
426       }
427       free(tmp);
428       return 1;
429     }
430   }
431   return 0;
432 }
433 #endif
434
435 /*
436  * Local Variables:
437  * c-basic-offset: 2
438  * indent-tabs-mode: nil
439  * End:
440  */