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