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