Refactoring of olsr_interface data to if_index instead of name
[oonf.git] / src-api / core / olsr_interface.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2012, 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/common_types.h"
43 #include "common/avl.h"
44 #include "common/avl_comp.h"
45 #include "common/list.h"
46 #include "common/netaddr.h"
47
48 #include "olsr_interface.h"
49 #include "olsr_logging.h"
50 #include "olsr_timer.h"
51 #include "olsr.h"
52 #include "os_net.h"
53 #include "os_system.h"
54 #include "os_routing.h"
55
56 /* timeinterval to delay change in interface to trigger actions */
57 #define OLSR_INTERFACE_CHANGE_INTERVAL 100
58
59 static struct olsr_interface *_interface_add(uint32_t, bool mesh);
60 static void _interface_remove(uint32_t, bool mesh);
61 static void _cb_change_handler(void *);
62 static void _trigger_change_timer(struct olsr_interface *);
63
64 /* global tree of known interfaces */
65 struct avl_tree olsr_interface_tree;
66
67 /* remember state of subsystem */
68 OLSR_SUBSYSTEM_STATE(_interface_state);
69
70 static struct list_entity _interface_listener;
71 static struct olsr_timer_info _change_timer_info = {
72   .name = "Interface change",
73   .callback = _cb_change_handler,
74 };
75
76 /**
77  * Initialize interface subsystem
78  * @return -1 if an error happened, 0 otherwise
79  */
80 int
81 olsr_interface_init(void) {
82   if (olsr_subsystem_is_initialized(&_interface_state))
83     return 0;
84
85   olsr_timer_add(&_change_timer_info);
86
87   avl_init(&olsr_interface_tree, avl_comp_uint32, false, NULL);
88   list_init_head(&_interface_listener);
89
90   olsr_subsystem_init(&_interface_state);
91   return 0;
92 }
93
94 /**
95  * Cleanup interface subsystem
96  */
97 void
98 olsr_interface_cleanup(void) {
99   struct olsr_interface_listener *listener, *l_it;
100
101   if (olsr_subsystem_cleanup(&_interface_state))
102     return;
103
104   list_for_each_element_safe(&_interface_listener, listener, node, l_it) {
105     olsr_interface_remove_listener(listener);
106   }
107
108   olsr_timer_remove(&_change_timer_info);
109 }
110
111 /**
112  * Add a listener to a specific interface
113  * @param listener initialized listener object
114  * @return pointer to olsr_interface struct, NULL if an error happened
115  */
116 struct olsr_interface *
117 olsr_interface_add_listener(
118     struct olsr_interface_listener *listener) {
119   struct olsr_interface *interf;
120
121   if (listener->if_index == 0 && listener->name) {
122     listener->if_index = if_nametoindex(listener->name);
123   }
124   interf = _interface_add(listener->if_index, listener->mesh);
125   if (interf != NULL && listener->process != NULL) {
126     list_add_tail(&_interface_listener, &listener->node);
127   }
128
129   return interf;
130 }
131
132 /**
133  * Removes a listener to an interface object
134  * @param listener pointer to listener object
135  */
136 void
137 olsr_interface_remove_listener(
138     struct olsr_interface_listener *listener) {
139   if (listener->process) {
140     list_remove(&listener->node);
141   }
142   _interface_remove(listener->if_index, listener->mesh);
143 }
144
145 /**
146  * Trigger a potential change in the interface settings. Normally
147  * called by os_system code
148  * @param if_index index of interface
149  */
150 void
151 olsr_interface_trigger_change(uint32_t if_index) {
152   struct olsr_interface *interf;
153
154   interf = avl_find_element(&olsr_interface_tree, &if_index, interf, node);
155   if (interf == NULL) {
156     return;
157   }
158
159   /* trigger interface reload in 100 ms */
160   _trigger_change_timer(interf);
161 }
162
163 struct olsr_interface_data *
164 olsr_interface_get_data(uint32_t if_index) {
165   struct olsr_interface *interf;
166
167   interf = avl_find_element(&olsr_interface_tree, &if_index, interf, node);
168   if (interf == NULL) {
169     return NULL;
170   }
171
172   return &interf->data;
173 }
174
175 /**
176  * Add an interface to the listener system
177  * @param if_index index of interface
178  * @param mesh true if interface is used for mesh traffic
179  * @return pointer to interface struct, NULL if an error happened
180  */
181 static struct olsr_interface *
182 _interface_add(uint32_t if_index, bool mesh) {
183   struct olsr_interface *interf;
184
185   interf = avl_find_element(&olsr_interface_tree, &if_index, interf, node);
186   if (!interf) {
187     /* allocate new interface */
188     interf = calloc(1, sizeof(*interf));
189     if (interf == NULL) {
190       OLSR_WARN_OOM(LOG_INTERFACE);
191       return NULL;
192     }
193
194     /* hookup */
195     interf->data.index = if_index;
196     interf->node.key = &interf->data.index;
197     avl_insert(&olsr_interface_tree, &interf->node);
198
199     interf->change_timer.info = &_change_timer_info;
200     interf->change_timer.cb_context = interf;
201
202     /* initialize data of interface */
203     os_net_update_interface(&interf->data, if_index);
204   }
205
206   /* update reference counters */
207   interf->usage_counter++;
208   if(mesh) {
209     if (interf->mesh_counter == 0) {
210       os_routing_init_mesh_if(interf);
211     }
212     interf->mesh_counter++;
213   }
214
215   /* trigger update */
216   _trigger_change_timer(interf);
217
218   return interf;
219 }
220
221 /**
222  * Remove an interface from the listener system. If multiple listeners
223  * share an interface, this will only decrease the reference counter.
224  * @param if_index index of interface
225  * @param mesh true if interface is used for mesh traffic
226  */
227 static void
228 _interface_remove(uint32_t if_index, bool mesh) {
229   struct olsr_interface *interf;
230
231   interf = avl_find_element(&olsr_interface_tree, &if_index, interf, node);
232   if (!interf) {
233     return;
234   }
235
236   interf->usage_counter--;
237   if (mesh) {
238     interf->mesh_counter--;
239
240     if (interf->mesh_counter < 1) {
241       os_routing_cleanup_mesh_if(interf);
242     }
243   }
244
245   if (interf->usage_counter > 0) {
246     return;
247   }
248
249   avl_remove(&olsr_interface_tree, &interf->node);
250   free(interf);
251 }
252
253
254 /**
255  * Timer callback to handle potential change of data of an interface
256  * @param ptr pointer to interface object
257  */
258 static void
259 _cb_change_handler(void *ptr) {
260   struct olsr_interface_data old_data, new_data;
261   struct olsr_interface_listener *listener, *l_it;
262   struct olsr_interface *interf;
263
264   interf = ptr;
265
266   /* read interface data */
267   if (os_net_update_interface(&new_data, interf->data.index)) {
268     /* an error happened, try again */
269     _trigger_change_timer(interf);
270     return;
271   }
272
273   /* something changed ? */
274   if (memcmp(&interf->data, &new_data, sizeof(new_data)) == 0) {
275     return;
276   }
277
278   /* copy data to interface object, but remember the old data */
279   memcpy(&old_data, &interf->data, sizeof(old_data));
280   memcpy(&interf->data, &new_data, sizeof(interf->data));
281
282   /* call listeners */
283   list_for_each_element_safe(&_interface_listener, listener, node, l_it) {
284     if (listener->process != NULL && listener->if_index == interf->data.index) {
285       listener->process(interf, &old_data);
286     }
287   }
288 }
289
290 /**
291  * Activate the change timer of an interface object
292  * @param interf pointer to interface object
293  */
294 static void
295 _trigger_change_timer(struct olsr_interface *interf) {
296   olsr_timer_set(&interf->change_timer, OLSR_INTERFACE_CHANGE_INTERVAL);
297 }