f83e439650b9816d3a909755e47b5b9b152e88c9
[oonf.git] / src / generic / dlep / dlep_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/oonf.h>
49 #include <oonf/subsystems/oonf_packet_socket.h>
50
51 #include <oonf/generic/dlep/dlep_extension.h>
52 #include <oonf/generic/dlep/dlep_iana.h>
53 #include <oonf/generic/dlep/dlep_interface.h>
54 #include <oonf/generic/dlep/dlep_session.h>
55 #include <oonf/generic/dlep/dlep_writer.h>
56
57 static void _cb_receive_udp(struct oonf_packet_socket *, union netaddr_socket *from, void *ptr, size_t length);
58 static void _cb_send_multicast(struct dlep_session *session, int af_family);
59
60 static const char _DLEP_PREFIX[] = DLEP_RFC8175_PREFIX;
61
62 static struct avl_tree _radio_if_tree = AVL_STATIC_INIT(_radio_if_tree, avl_comp_strcasecmp, false);
63 static struct avl_tree _router_if_tree = AVL_STATIC_INIT(_router_if_tree, avl_comp_strcasecmp, false);
64
65 struct avl_tree *
66 dlep_if_get_tree(bool radio) {
67   return radio ? &_radio_if_tree : &_router_if_tree;
68 }
69
70 /**
71  * Add a new interface to this dlep instance
72  * @param interf pointer to interface
73  * @param ifname name of interface
74  * @param l2_origin layer2 originator that shall be used
75  * @param l2_default_origin layer2 originator that shall be used for setting defaults
76  * @param if_changed interface listener bound to UDP session, can be NULL
77  * @param log_src logging source that shall be used
78  * @param radio true if it is a radio interface, false for router
79  * @return -1 if an error happened, 0 otherwise
80  */
81 int
82 dlep_if_add(struct dlep_if *interf, const char *ifname, const struct oonf_layer2_origin *l2_origin,
83   const struct oonf_layer2_origin *l2_default_origin,
84   int (*if_changed)(struct os_interface_listener *), enum oonf_log_source log_src, bool radio) {
85   struct dlep_extension *ext;
86
87   /* initialize key */
88   strscpy(interf->l2_ifname, ifname, sizeof(interf->l2_ifname));
89   interf->_node.key = interf->l2_ifname;
90
91   if (abuf_init(&interf->udp_out)) {
92     return -1;
93   }
94
95   /* add dlep prefix to buffer */
96   abuf_memcpy(&interf->udp_out, _DLEP_PREFIX, sizeof(_DLEP_PREFIX) - 1);
97
98   if (dlep_session_add(&interf->session, interf->l2_ifname,
99     l2_origin, l2_default_origin, &interf->udp_out, radio, if_changed, log_src)) {
100     abuf_free(&interf->udp_out);
101     return -1;
102   }
103
104   /* remember if this is a radio interface */
105   interf->radio = radio;
106
107   /* initialize stream list */
108   avl_init(&interf->session_tree, avl_comp_netaddr_socket, false);
109
110   /* initialize discovery socket */
111   interf->udp.config.user = interf;
112   interf->udp.config.receive_data = _cb_receive_udp;
113   oonf_packet_add_managed(&interf->udp);
114
115   /* initialize session */
116   interf->session.cb_send_buffer = _cb_send_multicast;
117   interf->session.cb_end_session = NULL;
118   interf->session.restrict_signal = radio ? DLEP_UDP_PEER_DISCOVERY : DLEP_UDP_PEER_OFFER;
119   interf->session.writer.out = &interf->udp_out;
120
121   /* add to tree */
122   avl_insert(dlep_if_get_tree(radio), &interf->_node);
123
124   /* inform all extension */
125   avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
126     if (radio) {
127       if (ext->cb_session_init_radio) {
128         ext->cb_session_init_radio(&interf->session);
129       }
130     }
131     else {
132       if (ext->cb_session_init_router) {
133         ext->cb_session_init_router(&interf->session);
134       }
135     }
136   }
137   return 0;
138 }
139
140 /**
141  * Remove dlep router interface
142  * @param interface dlep router interface
143  */
144 void
145 dlep_if_remove(struct dlep_if *interface) {
146   struct dlep_extension *ext;
147
148   OONF_DEBUG(interface->session.log_source, "remove session %s", interface->l2_ifname);
149
150   avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
151     if (interface->session.radio) {
152       if (ext->cb_session_cleanup_radio) {
153         ext->cb_session_cleanup_radio(&interface->session);
154       }
155     }
156     else {
157       if (ext->cb_session_cleanup_router) {
158         ext->cb_session_cleanup_router(&interface->session);
159       }
160     }
161   }
162
163   /* remove from tree */
164   avl_remove(dlep_if_get_tree(interface->radio), &interface->_node);
165
166   /* close UDP interface */
167   oonf_packet_remove_managed(&interface->udp, true);
168
169   /* kill dlep session */
170   dlep_session_remove(&interface->session);
171
172   /* free allocated memory data */
173   oonf_packet_free_managed_config(&interface->udp_config);
174   abuf_free(&interface->udp_out);
175 }
176 /**
177  * Callback to receive UDP data through oonf_packet_managed API
178  * @param pkt packet socket
179  * @param from network socket the packet was received from
180  * @param ptr pointer to packet data
181  * @param length length of packet data
182  */
183 static void
184 _cb_receive_udp(struct oonf_packet_socket *pkt, union netaddr_socket *from, void *ptr, size_t length) {
185   struct dlep_if *interf;
186   uint8_t *buffer;
187   ssize_t processed;
188   struct netaddr_str nbuf;
189
190   interf = pkt->config.user;
191   buffer = ptr;
192
193   switch (interf->udp_mode) {
194     case DLEP_IF_UDP_NONE:
195       return;
196     case DLEP_IF_UDP_SINGLE_SESSION:
197       if(interf->session_tree.count > 0) {
198         return;
199       }
200       break;
201     default:
202       break;
203   }
204
205   if (length < sizeof(_DLEP_PREFIX) - 1) {
206     /* ignore unknown prefix */
207     return;
208   }
209
210   if (netaddr_socket_cmp(from, &pkt->local_socket) == 0) {
211     /* we hear outselves, ignore it */
212     return;
213   }
214
215   if (memcmp(buffer, _DLEP_PREFIX, sizeof(_DLEP_PREFIX) - 1) != 0) {
216     OONF_WARN(interf->session.log_source, "Incoming UDP packet with unknown signature");
217     return;
218   }
219
220   /* advance pointer and fix length */
221   buffer += (sizeof(_DLEP_PREFIX) - 1);
222   length -= (sizeof(_DLEP_PREFIX) - 1);
223
224   /* copy socket information */
225   memcpy(&interf->session.remote_socket, from, sizeof(interf->session.remote_socket));
226
227   processed = dlep_session_process_buffer(&interf->session, buffer, length, true);
228   if (processed < 0) {
229     /* Session is now most likely invalid */
230     return;
231   }
232
233   if (interf->session.restrict_signal == DLEP_KILL_SESSION) {
234     /* Session was terminated */
235     return;
236   }
237
238   if ((size_t)processed < length) {
239     OONF_WARN(interf->session.log_source, "Received malformed or too short UDP packet from %s",
240       netaddr_socket_to_string(&nbuf, from));
241     /* incomplete or bad packet, just ignore it */
242     return;
243   }
244
245   if (abuf_getlen(interf->session.writer.out) > sizeof(_DLEP_PREFIX) - 1) {
246     /* send an unicast response */
247     oonf_packet_send_managed(
248       &interf->udp, from, abuf_getptr(interf->session.writer.out), abuf_getlen(interf->session.writer.out));
249     abuf_clear(interf->session.writer.out);
250
251     /* add dlep prefix to buffer */
252     abuf_memcpy(interf->session.writer.out, _DLEP_PREFIX, sizeof(_DLEP_PREFIX) - 1);
253   }
254
255   netaddr_socket_invalidate(&interf->session.remote_socket);
256 }
257
258 /**
259  * Callback to send multicast over interface
260  * @param session dlep session
261  * @param af_family address family for multicast
262  */
263 static void
264 _cb_send_multicast(struct dlep_session *session, int af_family) {
265   struct dlep_if *interf;
266
267   if (abuf_getlen(session->writer.out) <= sizeof(_DLEP_PREFIX) - 1 ||
268       !netaddr_socket_is_unspec(&session->remote_socket)) {
269     return;
270   }
271
272   /* get pointer to radio interface */
273   interf = container_of(session, struct dlep_if, session);
274
275   switch (interf->udp_mode) {
276     case DLEP_IF_UDP_NONE:
277       return;
278     case DLEP_IF_UDP_SINGLE_SESSION:
279       if(interf->session_tree.count > 0) {
280         return;
281       }
282       break;
283     default:
284       break;
285   }
286
287   OONF_DEBUG(
288     session->log_source, "Send multicast %" PRINTF_SIZE_T_SPECIFIER " bytes", abuf_getlen(session->writer.out));
289
290   oonf_packet_send_managed_multicast(
291     &interf->udp, abuf_getptr(session->writer.out), abuf_getlen(session->writer.out), af_family);
292
293   abuf_clear(session->writer.out);
294
295   /* add dlep prefix to buffer */
296   abuf_memcpy(session->writer.out, _DLEP_PREFIX, sizeof(_DLEP_PREFIX) - 1);
297 }