b2acda767ea37cba202a49d176bc5ca86fa21940
[oonf.git] / src-api / subsystems / oonf_layer2.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2013, 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.h"
43 #include "common/avl_comp.h"
44 #include "common/common_types.h"
45
46 #include "core/oonf_logging.h"
47 #include "core/oonf_subsystem.h"
48 #include "subsystems/oonf_class.h"
49 #include "subsystems/oonf_layer2.h"
50 #include "subsystems/oonf_rfc5444.h"
51 #include "subsystems/oonf_timer.h"
52
53 /* definitions and constants */
54 #define CFG_KEY_LINKSPEED "linkspeed"
55
56 /* prototypes */
57 static int _init(void);
58 static void _cleanup(void);
59
60 static void _remove_neighbor(struct oonf_layer2_neighbor *);
61 static void _remove_network(struct oonf_layer2_network *);
62 static void _cb_neighbor_timeout(void *ptr);
63 static void _cb_network_timeout(void *ptr);
64 static int _avl_comp_l2neigh(const void *k1, const void *k2);
65 static const char *_cb_get_neighbor_name(
66     struct oonf_objectkey_str *, struct oonf_class *, void *);
67 static const char *_cb_get_network_name(
68     struct oonf_objectkey_str *, struct oonf_class *, void *);
69
70 struct avl_tree oonf_layer2_network_id_tree;
71 struct avl_tree oonf_layer2_neighbor_tree;
72
73 static struct oonf_class _network_cookie = {
74   .name = "layer2 networks",
75   .size = sizeof(struct oonf_layer2_network),
76   .to_keystring = _cb_get_network_name,
77 };
78
79 static struct oonf_class _neighbor_cookie = {
80   .name = "layer2 neighbors",
81   .size = sizeof(struct oonf_layer2_neighbor),
82   .to_keystring = _cb_get_neighbor_name,
83 };
84
85 static struct oonf_timer_info _network_vtime_info = {
86   .name = "layer2 network vtime",
87   .callback = _cb_network_timeout,
88   .periodic = true,
89 };
90
91 static struct oonf_timer_info _neighbor_vtime_info = {
92   .name = "layer2 neighbor vtime",
93   .callback = _cb_neighbor_timeout,
94   .periodic = true,
95 };
96
97 struct oonf_subsystem oonf_layer2_subsystem = {
98   .name = "layer2",
99   .init = _init,
100   .cleanup = _cleanup,
101 };
102
103 /**
104  * Initialize layer2 subsystem
105  * @return always returns 0
106  */
107 static int
108 _init(void) {
109   oonf_class_add(&_network_cookie);
110   oonf_class_add(&_neighbor_cookie);
111
112   oonf_timer_add(&_network_vtime_info);
113   oonf_timer_add(&_neighbor_vtime_info);
114
115   avl_init(&oonf_layer2_network_id_tree, avl_comp_netaddr, false);
116   avl_init(&oonf_layer2_neighbor_tree, _avl_comp_l2neigh, false);
117   return 0;
118 }
119
120 /**
121  * Cleanup all resources allocated by layer2 subsystem
122  */
123 static void
124 _cleanup(void) {
125   struct oonf_layer2_neighbor *neigh, *neigh_it;
126   struct oonf_layer2_network *net, *net_it;
127
128   avl_for_each_element_safe(&oonf_layer2_network_id_tree, net, _id_node, net_it) {
129     net->active = false;
130     oonf_layer2_remove_network(net);
131   }
132
133   avl_for_each_element_safe(&oonf_layer2_neighbor_tree, neigh, _node, neigh_it) {
134     neigh->active = false;
135     oonf_layer2_remove_neighbor(neigh);
136   }
137
138   oonf_timer_remove(&_network_vtime_info);
139   oonf_timer_remove(&_neighbor_vtime_info);
140   oonf_class_remove(&_network_cookie);
141   oonf_class_remove(&_neighbor_cookie);
142 }
143
144 /**
145  * Add an active network to the database. If an entry for the
146  * interface does already exists, it will be returned by this
147  * function and no new entry will be created.
148  * @param radio_id ID of the radio (might be NULL)
149  * @param if_index local interface index of network
150  * @param name interface name of the radio (might be NULL)
151  * @param vtime validity time of data
152  * @return pointer to layer2 network data, NULL if OOM
153  */
154 struct oonf_layer2_network *
155 oonf_layer2_add_network(struct netaddr *radio_id, uint32_t if_index,
156     uint64_t vtime) {
157   struct oonf_layer2_network *net;
158
159   net = oonf_layer2_get_network_by_id(radio_id);
160   if (!net) {
161     net = oonf_class_malloc(&_network_cookie);
162     if (!net) {
163       return NULL;
164     }
165
166     /* initialize the nodes */
167     net->_id_node.key = &net->radio_id;
168     memcpy (&net->radio_id, radio_id, sizeof(*radio_id));
169     avl_insert(&oonf_layer2_network_id_tree, &net->_id_node);
170
171     net->if_index = if_index;
172     net->_valitity_timer.info = &_network_vtime_info;
173     net->_valitity_timer.cb_context = net;
174
175     oonf_class_event(&_network_cookie, net, OONF_OBJECT_ADDED);
176   }
177
178   OONF_DEBUG(LOG_LAYER2, "Reset validity of network timer: %"PRIu64,
179       vtime);
180   net->active = true;
181   oonf_timer_set(&net->_valitity_timer, vtime);
182   return net;
183 }
184
185 /**
186  * Remove a layer2 network from the database
187  * @param net pointer to layer2 network data
188  */
189 void
190 oonf_layer2_remove_network(struct oonf_layer2_network *net) {
191   if (net->active) {
192     /* restart validity timer */
193     oonf_timer_set(&net->_valitity_timer,
194       oonf_timer_get_period(&net->_valitity_timer));
195   }
196   _remove_network(net);
197 }
198
199 /**
200  * Retrieve a layer2 neighbor from the database
201  * @param radio_id pointer to radio_id of network
202  * @param neigh_mac pointer to layer2 address of neighbor
203  * @return pointer to layer2 neighbor data, NULL if not found
204  */
205 struct oonf_layer2_neighbor *
206 oonf_layer2_get_neighbor(struct netaddr *radio_id, struct netaddr *neigh_mac) {
207   struct oonf_layer2_neighbor_key key;
208   struct oonf_layer2_neighbor *neigh;
209
210   key.radio_mac = *radio_id;
211   key.neighbor_mac = *neigh_mac;
212
213   return avl_find_element(&oonf_layer2_neighbor_tree, &key, neigh, _node);
214 }
215
216 /**
217  * Add a layer2 neighbor to the database. If an entry for the
218  * neighbor on the interface does already exists, it will be
219  * returned by this function and no new entry will be created.
220  * @param radio_id pointer to radio_id of network
221  * @param neigh_mac layer2 address of neighbor
222  * @param if_index local interface index of the neighbor
223  * @param vtime validity time of data
224  * @return pointer to layer2 neighbor data, NULL if OOM
225  */
226 struct oonf_layer2_neighbor *
227 oonf_layer2_add_neighbor(struct netaddr *radio_id, struct netaddr *neigh_mac,
228     uint32_t if_index, uint64_t vtime) {
229   struct oonf_layer2_neighbor *neigh;
230
231   assert (vtime > 0);
232
233   neigh = oonf_layer2_get_neighbor(radio_id, neigh_mac);
234   if (!neigh) {
235     neigh = oonf_class_malloc(&_neighbor_cookie);
236     if (!neigh) {
237       return NULL;
238     }
239
240     neigh->if_index = if_index;
241     memcpy(&neigh->key.radio_mac, radio_id, sizeof(*radio_id));
242     memcpy(&neigh->key.neighbor_mac, neigh_mac, sizeof(*neigh_mac));
243
244     neigh->_node.key = &neigh->key;
245     neigh->_valitity_timer.info = &_neighbor_vtime_info;
246     neigh->_valitity_timer.cb_context = neigh;
247
248     avl_insert(&oonf_layer2_neighbor_tree, &neigh->_node);
249     oonf_class_event(&_neighbor_cookie, neigh, OONF_OBJECT_ADDED);
250   }
251
252   neigh->active = true;
253   oonf_timer_set(&neigh->_valitity_timer, vtime);
254   return neigh;
255 }
256
257 /**
258  * Remove a layer2 neighbor from the database
259  * @param neigh pointer to layer2 neighbor
260  */
261 void
262 oonf_layer2_remove_neighbor(struct oonf_layer2_neighbor *neigh) {
263   if (neigh->active) {
264     /* restart validity timer */
265     oonf_timer_set(&neigh->_valitity_timer,
266         oonf_timer_get_period(&neigh->_valitity_timer));
267   }
268   _remove_neighbor(neigh);
269 }
270
271 /**
272  * Set a new list of supported rates. Data will not be changed if an
273  * error happens.
274  * @param net pointer to layer2 network
275  * @param rate_array pointer to array of supported rates
276  * @param rate_count number of supported rates
277  * @return -1 if an out of memory error happened, 0 otherwise.
278  */
279 int
280 oonf_layer2_network_set_supported_rates(struct oonf_layer2_network *net,
281     uint64_t *rate_array, size_t rate_count) {
282   uint64_t *rates;
283
284   rates = realloc(net->supported_rates, rate_count * sizeof(uint64_t));
285   if (rates == NULL) {
286     return -1;
287   }
288
289   net->_available_data |= OONF_L2NET_SUPPORTED_RATES;
290   net->supported_rates = rates;
291   net->rate_count = rate_count;
292   memcpy(rates, rate_array, sizeof(uint64_t) * rate_count);
293
294   return 0;
295 }
296
297 /**
298  * Triggers a change callback for a layer2 neighbor
299  * @param neigh pointer to layer2 neighbor
300  */
301 void
302 oonf_layer2_neighbor_commit(struct oonf_layer2_neighbor *neigh) {
303   oonf_class_event(&_neighbor_cookie, neigh, OONF_OBJECT_CHANGED);
304 }
305
306 /**
307  * Triggers a change callback for a layer2 network
308  * @param net pointer to layer2 network
309  */
310 void
311 oonf_layer2_network_commit(struct oonf_layer2_network *net) {
312   oonf_class_event(&_network_cookie, net, OONF_OBJECT_CHANGED);
313 }
314
315 /**
316  * Remove a layer2 neighbor from the database
317  * @param neigh pointer to layer2 neighbor
318  */
319 static void
320 _remove_neighbor(struct oonf_layer2_neighbor *neigh) {
321   if (neigh->active) {
322     oonf_class_event(&_neighbor_cookie, neigh, OONF_OBJECT_REMOVED);
323     neigh->active = false;
324     return;
325   }
326   avl_remove(&oonf_layer2_neighbor_tree, &neigh->_node);
327   oonf_timer_stop(&neigh->_valitity_timer);
328   oonf_class_free(&_neighbor_cookie, neigh);
329 }
330
331 /**
332  * Remove a layer2 network from the database
333  * @param net pointer to layer2 network data
334  */
335 static void
336 _remove_network(struct oonf_layer2_network *net) {
337   if (net->active) {
338     oonf_class_event(&_network_cookie, net, OONF_OBJECT_REMOVED);
339     net->active = false;
340     return;
341   }
342
343   avl_remove(&oonf_layer2_network_id_tree, &net->_id_node);
344
345   oonf_timer_stop(&net->_valitity_timer);
346   free (net->supported_rates);
347   oonf_class_free(&_network_cookie, net);
348 }
349
350 /**
351  * Validity time callback for neighbor entries
352  * @param ptr pointer to neighbor entry
353  */
354 static void
355 _cb_neighbor_timeout(void *ptr) {
356 #ifdef OONF_LOG_DEBUG_INFO
357   struct oonf_layer2_neighbor *neigh = ptr;
358 #endif
359   OONF_DEBUG(LOG_LAYER2, "Layer-2 neighbor timeout (was %sactive)", neigh->active ? "" : "in");
360   _remove_neighbor(ptr);
361 }
362
363 /**
364  * Validity time callback for network entries
365  * @param ptr pointer to network entry
366  */
367 static void
368 _cb_network_timeout(void *ptr) {
369 #ifdef OONF_LOG_DEBUG_INFO
370   struct oonf_layer2_network *net = ptr;
371 #endif
372   OONF_DEBUG(LOG_LAYER2, "Layer-2 network timeout (was %sactive)", net->active ? "" : "in");
373   _remove_network(ptr);
374 }
375
376 /**
377  * AVL comparator for layer2 neighbor nodes
378  * @param k1 pointer to first layer2 neighbor
379  * @param k2 pointer to second layer2 neighbor
380  * @param ptr unused
381  * @return +1 if k1>k2, -1 if k1<k2, 0 if k1==k2
382  */
383 static int
384 _avl_comp_l2neigh(const void *k1, const void *k2) {
385   const struct oonf_layer2_neighbor_key *key1, *key2;
386   int result;
387
388   key1 = k1;
389   key2 = k2;
390
391   result = netaddr_cmp(&key1->radio_mac, &key2->radio_mac);
392   if (!result) {
393     result = netaddr_cmp(&key1->neighbor_mac, &key2->neighbor_mac);
394   }
395   return result;
396 }
397
398 /**
399  * Construct human readable object id of neighbor for callbacks
400  * @param buf pointer to key output buffer
401  * @param cl pointer to class
402  * @param ptr pointer to l2 neighbor
403  * @return pointer to id
404  */
405 static const char *
406 _cb_get_neighbor_name(struct oonf_objectkey_str *buf,
407     struct oonf_class *cl, void *ptr) {
408   struct netaddr_str nbuf1, nbuf2;
409   struct oonf_layer2_neighbor *nbr;
410
411   nbr = ptr;
412
413   snprintf(buf->buf, sizeof(*buf), "%s::neigh=%s/radio=%s",
414       cl->name,
415       netaddr_to_string(&nbuf1, &nbr->key.neighbor_mac),
416       netaddr_to_string(&nbuf2, &nbr->key.radio_mac));
417   return buf->buf;
418 }
419
420 /**
421  * Construct human readable object id of network for callbacks
422  * @param buf pointer to key output buffer
423  * @param cl pointer to class
424  * @param ptr pointer to l2 neighbor
425  * @return pointer to id
426  */
427 static const char *
428 _cb_get_network_name(struct oonf_objectkey_str *buf,
429     struct oonf_class *cl, void *ptr) {
430   struct netaddr_str buf1;
431   struct oonf_layer2_network *net;
432
433   net = ptr;
434
435   snprintf(buf->buf, sizeof(*buf), "%s::radio=%s",
436       cl->name, netaddr_to_string(&buf1, &net->radio_id));
437   return buf->buf;
438 }