Fix coverity 185458: split index variable into two enums
[oonf.git] / src-plugins / generic / dlep / dlep_extension.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2015, 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 /**
43  * @file
44  */
45
46 #include <stdlib.h>
47
48 #include "common/common_types.h"
49 #include "common/avl.h"
50 #include "common/avl_comp.h"
51
52 #include "subsystems/oonf_layer2.h"
53
54 #include "dlep/dlep_reader.h"
55 #include "dlep/dlep_session.h"
56 #include "dlep/dlep_writer.h"
57 #include "dlep/dlep_extension.h"
58
59 static int _process_interface_specific_update(
60     struct dlep_extension *ext, struct dlep_session *session);
61
62 static struct avl_tree _extension_tree;
63
64 static uint16_t *_id_array = NULL;
65 static uint16_t _id_array_length = 0;
66
67 /**
68  * Initialize the dlep extension system
69  */
70 void
71 dlep_extension_init(void) {
72   avl_init(&_extension_tree, avl_comp_int32, false);
73 }
74
75 /**
76  * Cleanup DLEP extension resources
77  */
78 void
79 dlep_extension_cleanup(void) {
80   free (_id_array);
81   _id_array = NULL;
82   _id_array_length = 0;
83 }
84
85 /**
86  * Add a new dlep extension
87  * @param ext pointer to initialized extension handler
88  */
89 void
90 dlep_extension_add(struct dlep_extension *ext) {
91   uint16_t *ptr;
92
93   if (avl_is_node_added(&ext->_node)) {
94     return;
95   }
96
97   /* add to tree */
98   ext->_node.key = &ext->id;
99   avl_insert(&_extension_tree, &ext->_node);
100
101   /* refresh id array */
102   ptr = realloc(_id_array, sizeof(uint16_t) * _extension_tree.count);
103   if (!ptr) {
104     return;
105   }
106
107   _id_array_length = 0;
108   _id_array = ptr;
109
110   avl_for_each_element(&_extension_tree, ext, _node) {
111     if (ext->id >= 0 && ext->id <= 0xffff) {
112       ptr[_id_array_length] = htons(ext->id);
113       _id_array_length++;
114     }
115   }
116 }
117
118 /**
119  * Get tree of dlep extensions
120  * @return tree of extensions
121  */
122 struct avl_tree *
123 dlep_extension_get_tree(void) {
124   return &_extension_tree;
125 }
126
127 /**
128  * Add processing callbacks to DLEP extension
129  * @param ext dlep extension
130  * @param radio true if radio extension, false if router
131  * @param processing array of dlep extension processing handlers
132  * @param proc_count number of processing handlers
133  */
134 void
135 dlep_extension_add_processing(struct dlep_extension *ext, bool radio,
136     struct dlep_extension_implementation *processing, size_t proc_count) {
137   size_t i,j;
138
139   for (j=0; j<proc_count; j++) {
140     for (i=0; i<ext->signal_count; i++) {
141       if (ext->signals[i].id == processing[j].id) {
142         if (radio) {
143           ext->signals[i].process_radio = processing[j].process;
144           ext->signals[i].add_radio_tlvs = processing[j].add_tlvs;
145         }
146         else {
147           ext->signals[i].process_router = processing[j].process;
148           ext->signals[i].add_router_tlvs = processing[j].add_tlvs;
149         }
150         break;
151       }
152     }
153   }
154 }
155
156 /**
157  * Get the array of supported dlep extension ids
158  * @param length pointer to length field to store id count
159  * @return pointer to array with ids
160  */
161 const uint16_t *
162 dlep_extension_get_ids(uint16_t *length) {
163   *length = _id_array_length;
164   return _id_array;
165 }
166
167 /**
168  * Handle peer init ack for DLEP extension by automatically
169  * mapping oonf_layer2_data to DLEP TLVs
170  * @param ext dlep extension
171  * @param session dlep session
172  * @return -1 if an error happened, 0 otherwise
173  */
174 int
175 dlep_extension_router_process_session_init_ack(
176     struct dlep_extension *ext, struct dlep_session *session) {
177   if (session->restrict_signal != DLEP_SESSION_INITIALIZATION_ACK) {
178     /* ignore unless we are in initialization mode */
179     return 0;
180   }
181   return _process_interface_specific_update(ext, session);
182 }
183
184 /**
185  * Handle peer update for DLEP extension by automatically
186  * mapping oonf_layer2_data to DLEP TLVs
187  * @param ext dlep extension
188  * @param session dlep session
189  * @return -1 if an error happened, 0 otherwise
190  */
191 int
192 dlep_extension_router_process_session_update(
193     struct dlep_extension *ext, struct dlep_session *session) {
194   if (session->restrict_signal != DLEP_ALL_SIGNALS) {
195     /* ignore unless we have an established session */
196     return 0;
197   }
198
199   return _process_interface_specific_update(ext, session);
200 }
201
202 /**
203  * Handle handle destination up/update for DLEP extension
204  * by automatically mapping oonf_layer2_data to DLEP TLVs
205  * @param ext dlep extension
206  * @param session dlep session
207  * @return -1 if an error happened, 0 otherwise
208  */
209 int
210 dlep_extension_router_process_destination(
211     struct dlep_extension *ext, struct dlep_session *session) {
212   struct oonf_layer2_net *l2net;
213   struct oonf_layer2_neigh *l2neigh;
214   struct netaddr mac;
215   int result;
216
217   if (session->restrict_signal != DLEP_ALL_SIGNALS) {
218     /* ignore unless we have an established session */
219     return 0;
220   }
221
222   if (dlep_reader_mac_tlv(&mac, session, NULL)) {
223     OONF_INFO(session->log_source, "mac tlv missing");
224     return -1;
225   }
226
227   l2net = oonf_layer2_net_get(session->l2_listener.name);
228   if (!l2net) {
229     return 0;
230   }
231   l2neigh = oonf_layer2_neigh_add(l2net, &mac);
232   if (!l2neigh) {
233     return 0;
234   }
235
236   result = dlep_reader_map_l2neigh_data(l2neigh->data, session, ext);
237   if (result) {
238     OONF_INFO(session->log_source, "tlv mapping for extension %d failed: %d",
239         ext->id, result);
240     return result;
241   }
242   return 0;
243 }
244
245 /**
246  * Generate peer init ack for DLEP extension by automatically
247  * mapping oonf_layer2_data to DLEP TLVs
248  * @param ext dlep extension
249  * @param session dlep session
250  * @param neigh unused for this callback
251  * @return -1 if an error happened, 0 otherwise
252  */
253 int
254 dlep_extension_radio_write_session_init_ack(
255     struct dlep_extension *ext, struct dlep_session *session,
256     const struct netaddr *neigh __attribute__((unused))) {
257   const struct oonf_layer2_metadata *meta;
258   struct oonf_layer2_net *l2net;
259   struct oonf_layer2_data *l2data;
260   enum oonf_layer2_neighbor_index neigh_idx;
261   enum oonf_layer2_network_index net_idx;
262   size_t i;
263   int result;
264
265   /* first make sure defaults are set correctly */
266   l2net = oonf_layer2_net_add(session->l2_listener.name);
267   if (!l2net) {
268     OONF_WARN(session->log_source, "Could not add l2net for new interface");
269     return -1;
270   }
271
272   /* adding default neighbor data for mandatory values */
273   for (i=0; i<ext->neigh_mapping_count; i++) {
274     if (!ext->neigh_mapping[i].mandatory) {
275       continue;
276     }
277
278     neigh_idx = ext->neigh_mapping[i].layer2;
279     l2data = &l2net->neighdata[neigh_idx];
280
281
282     if (!oonf_layer2_data_has_value(l2data)) {
283       meta = oonf_layer2_neigh_metadata_get(neigh_idx);
284       oonf_layer2_data_set(l2data, session->l2_origin,
285           meta->type, &ext->neigh_mapping[i].default_value);
286     }
287   }
288
289   /* adding default interface data for mandatory values */
290   for (i=0; i<ext->if_mapping_count; i++) {
291     if (!ext->if_mapping[i].mandatory) {
292       continue;
293     }
294
295     net_idx = ext->if_mapping[i].layer2;
296     l2data = &l2net->data[net_idx];
297
298     if (!oonf_layer2_data_has_value(l2data)) {
299       meta = oonf_layer2_net_metadata_get(net_idx);
300       oonf_layer2_data_set(l2data, session->l2_origin,
301           meta->type, &ext->if_mapping[i].default_value);
302     }
303   }
304
305   /* write default metric values */
306   result = dlep_writer_map_l2neigh_data(&session->writer, ext,
307       l2net->neighdata, NULL);
308   if (result) {
309     OONF_WARN(session->log_source, "tlv mapping for extension %d failed: %d",
310         ext->id, result);
311     return result;
312   }
313
314   /* write network wide data */
315   result = dlep_writer_map_l2net_data(&session->writer, ext, l2net->data);
316   if(result) {
317     OONF_WARN(session->log_source, "tlv mapping for extension %d failed: %d",
318         ext->id, result);
319     return result;
320   }
321   return 0;
322 }
323
324 /**
325  * Generate peer update for DLEP extension by automatically
326  * mapping oonf_layer2_data to DLEP TLVs
327  * @param ext dlep extension
328  * @param session dlep session
329  * @param neigh unused for this callback
330  * @return -1 if an error happened, 0 otherwise
331  */
332 int
333 dlep_extension_radio_write_session_update(
334     struct dlep_extension *ext, struct dlep_session *session,
335     const struct netaddr *neigh __attribute__((unused))) {
336   struct oonf_layer2_net *l2net;
337   int result;
338
339   l2net = oonf_layer2_net_get(session->l2_listener.name);
340   if (!l2net) {
341     OONF_WARN(session->log_source, "Could not find l2net for new interface");
342     return -1;
343   }
344
345   result = dlep_writer_map_l2neigh_data(&session->writer, ext,
346       l2net->neighdata, NULL);
347   if (result) {
348     OONF_WARN(session->log_source, "tlv mapping for extension %d failed: %d",
349         ext->id, result);
350     return result;
351   }
352   return 0;
353 }
354
355 /**
356  * Generate destination up/update for DLEP extension
357  * by automatically mapping oonf_layer2_data to DLEP TLVs
358  * @param ext dlep extension
359  * @param session dlep session
360  * @param neigh neighbor that should be updated
361  * @return -1 if an error happened, 0 otherwise
362  */
363 int
364 dlep_extension_radio_write_destination(struct dlep_extension *ext,
365     struct dlep_session *session, const struct netaddr *neigh) {
366   struct oonf_layer2_neigh *l2neigh;
367   struct netaddr_str nbuf;
368   int result;
369
370   l2neigh = dlep_session_get_local_l2_neighbor(session, neigh);
371   if (!l2neigh) {
372     OONF_WARN(session->log_source, "Could not find l2neigh "
373         "for neighbor %s", netaddr_to_string(&nbuf, neigh));
374     return -1;
375   }
376
377   result = dlep_writer_map_l2neigh_data(&session->writer, ext,
378       l2neigh->data, l2neigh->network->neighdata);
379   if (result) {
380     OONF_WARN(session->log_source, "tlv mapping for extension %d"
381         " and neighbor %s failed: %d",
382         ext->id, netaddr_to_string(&nbuf, neigh), result);
383     return result;
384   }
385   return 0;
386 }
387
388 /**
389  * Handle peer update and session init ACK for DLEP extension
390  * by automatically mapping oonf_layer2_data to DLEP TLVs
391  * @param ext dlep extension
392  * @param session dlep session
393  * @return -1 if an error happened, 0 otherwise
394  */
395 static int
396 _process_interface_specific_update(
397     struct dlep_extension *ext, struct dlep_session *session) {
398   struct oonf_layer2_net *l2net;
399   int result;
400
401   l2net = oonf_layer2_net_add(session->l2_listener.name);
402   if (!l2net) {
403     OONF_INFO(session->log_source, "Could not add l2net for new interface");
404     return -1;
405   }
406
407   result = dlep_reader_map_l2neigh_data(l2net->neighdata, session, ext);
408   if (result) {
409     OONF_INFO(session->log_source, "tlv mapping for extension %d failed: %d",
410         ext->id, result);
411     return result;
412   }
413
414   result = dlep_reader_map_l2net_data(l2net->data, session, ext);
415   if (result) {
416     OONF_INFO(session->log_source, "tlv mapping for extension %d failed: %d",
417         ext->id, result);
418     return result;
419   }
420   return 0;
421 }