Fix DLEP handling of mandatory TLVs
[oonf.git] / src-plugins / generic / dlep / radio / dlep_radio_interface.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 "common/avl.h"
47 #include "common/avl_comp.h"
48 #include "common/netaddr.h"
49
50 #include "subsystems/oonf_class.h"
51 #include "subsystems/oonf_packet_socket.h"
52 #include "subsystems/oonf_stream_socket.h"
53 #include "subsystems/oonf_timer.h"
54
55 #include "dlep/dlep_extension.h"
56 #include "dlep/dlep_iana.h"
57 #include "dlep/dlep_session.h"
58 #include "dlep/dlep_writer.h"
59
60 #include "dlep/radio/dlep_radio.h"
61 #include "dlep/radio/dlep_radio_interface.h"
62
63 #include "dlep/ext_base_ip/ip.h"
64 #include "dlep/ext_base_metric/metric.h"
65 #include "dlep/ext_base_proto/proto_radio.h"
66 #include "dlep/ext_l1_statistics/l1_statistics.h"
67 #include "dlep/ext_l2_statistics/l2_statistics.h"
68 #include "dlep/ext_radio_attributes/radio_attributes.h"
69 #include "dlep/radio/dlep_radio_internal.h"
70 #include "dlep/radio/dlep_radio_session.h"
71
72 static void _cleanup_interface(struct dlep_radio_if *interface);
73
74 /* DLEP interfaces */
75 static struct oonf_class _interface_class = {
76   .name = "DLEP radio interface",
77   .size = sizeof(struct dlep_radio_if),
78 };
79
80 static bool _shutting_down;
81
82 static struct oonf_layer2_origin _l2_origin = {
83   .name = "dlep radio",
84   .proactive = true,
85   .priority = OONF_LAYER2_ORIGIN_RELIABLE,
86 };
87
88 static struct oonf_layer2_origin _l2_default_origin = {
89   .name = "dlep radio defaults",
90   .proactive = false,
91   .priority = OONF_LAYER2_ORIGIN_UNRELIABLE,
92 };
93
94 /**
95  * Initialize everything for dlep radio interfaces. This function also
96  * initializes the dlep sessions.
97  * @return -1 if an error happened, 0 otherwise
98  */
99 int
100 dlep_radio_interface_init(void) {
101   oonf_class_add(&_interface_class);
102
103   dlep_extension_init();
104   dlep_session_init();
105   dlep_radio_session_init();
106   dlep_base_proto_radio_init();
107   dlep_base_ip_init();
108   dlep_base_metric_init();
109   dlep_l1_statistics_init();
110   dlep_l2_statistics_init();
111   dlep_radio_attributes_init();
112
113   _shutting_down = false;
114   return 0;
115 }
116
117 /**
118  * Cleanup everything allocated for dlep radio interfaces. This will
119  * also clean up all dlep sessions.
120  */
121 void
122 dlep_radio_interface_cleanup(void) {
123   struct dlep_radio_if *interf, *it;
124
125   avl_for_each_element_safe(dlep_if_get_tree(true), interf, interf._node, it) {
126     dlep_radio_remove_interface(interf);
127   }
128
129   oonf_class_remove(&_interface_class);
130   dlep_radio_session_cleanup();
131   dlep_extension_cleanup();
132 }
133
134 /**
135  * Get a dlep radio interface by layer2 interface name
136  * @param l2_ifname interface name
137  * @return dlep radio interface, NULL if not found
138  */
139 struct dlep_radio_if *
140 dlep_radio_get_by_layer2_if(const char *l2_ifname) {
141   struct dlep_radio_if *interf;
142
143   return avl_find_element(dlep_if_get_tree(true), l2_ifname, interf, interf._node);
144 }
145
146 /**
147  * Get a dlep radio interface by dlep datapath name
148  * @param ifname interface name
149  * @return dlep radio interface, NULL if not found
150  */
151 struct dlep_radio_if *
152 dlep_radio_get_by_datapath_if(const char *ifname) {
153   struct dlep_radio_if *interf;
154
155   avl_for_each_element(dlep_if_get_tree(true), interf, interf._node) {
156     if (strcmp(interf->interf.udp_config.interface, ifname) == 0) {
157       return interf;
158     }
159   }
160   return NULL;
161 }
162
163 /**
164  * Add a new dlep radio interface to the database
165  * (keep existing one if already there).
166  * @param ifname interface name
167  * @return dlep radio interface, NULL if allocation failed
168  */
169 struct dlep_radio_if *
170 dlep_radio_add_interface(const char *ifname) {
171   struct dlep_radio_if *interface;
172
173   interface = dlep_radio_get_by_layer2_if(ifname);
174   if (interface) {
175     return interface;
176   }
177
178   interface = oonf_class_malloc(&_interface_class);
179   if (!interface) {
180     return NULL;
181   }
182
183   if (dlep_if_add(&interface->interf, ifname, &_l2_origin, &_l2_default_origin, NULL, LOG_DLEP_RADIO, true)) {
184     oonf_class_free(&_interface_class, interface);
185     return NULL;
186   }
187
188   /* configure TCP server socket */
189   interface->tcp.config.session_timeout = 120000; /* 120 seconds */
190   interface->tcp.config.maximum_input_buffer = 4096;
191   interface->tcp.config.allowed_sessions = 3;
192   dlep_radio_session_initialize_tcp_callbacks(&interface->tcp.config);
193
194   oonf_stream_add_managed(&interface->tcp);
195
196   return interface;
197 }
198
199 /**
200  * Remove a dlep radio interface
201  * @param interface dlep radio interface
202  */
203 void
204 dlep_radio_remove_interface(struct dlep_radio_if *interface) {
205   /* close all sessions */
206   _cleanup_interface(interface);
207
208   /* cleanup tcp socket */
209   oonf_stream_remove_managed(&interface->tcp, true);
210
211   /* cleanup generic interface */
212   dlep_if_remove(&interface->interf);
213
214   /* free memory */
215   oonf_stream_free_managed_config(&interface->tcp_config);
216   free(interface->interf.session.cfg.peer_type);
217   abuf_free(&interface->interf.udp_out);
218   oonf_class_free(&_interface_class, interface);
219 }
220
221 /**
222  * Apply settings for dlep radio interface
223  * @param interface dlep radio interface
224  */
225 void
226 dlep_radio_apply_interface_settings(struct dlep_radio_if *interface) {
227   struct dlep_extension *ext;
228
229   oonf_packet_apply_managed(&interface->interf.udp, &interface->interf.udp_config);
230   oonf_stream_apply_managed(&interface->tcp, &interface->tcp_config);
231
232   avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
233     if (ext->cb_session_apply_radio) {
234       ext->cb_session_apply_radio(&interface->interf.session);
235     }
236   }
237 }
238
239 /**
240  * Send all active sessions a Peer Terminate signal
241  */
242 void
243 dlep_radio_terminate_all_sessions(void) {
244   struct dlep_radio_if *interf;
245   struct dlep_radio_session *radio_session;
246
247   _shutting_down = true;
248
249   avl_for_each_element(dlep_if_get_tree(true), interf, interf._node) {
250     avl_for_each_element(&interf->interf.session_tree, radio_session, _node) {
251       dlep_session_terminate(&radio_session->session, DLEP_STATUS_OKAY, "DLEP radio is shutting down");
252     }
253   }
254 }
255
256 /**
257  * Close all existing dlep sessions of a dlep interface
258  * @param interface dlep router interface
259  */
260 static void
261 _cleanup_interface(struct dlep_radio_if *interface) {
262   struct dlep_radio_session *stream, *it;
263
264   /* close TCP connection and socket */
265   avl_for_each_element_safe(&interface->interf.session_tree, stream, _node, it) {
266     dlep_radio_remove_session(stream);
267   }
268 }