Rename "subsystems" directory to "base"
[oonf.git] / src / generic / dlep / radio / dlep_radio_session.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/base/oonf_class.h>
51 #include <oonf/base/oonf_layer2.h>
52 #include <oonf/base/oonf_packet_socket.h>
53 #include <oonf/base/oonf_stream_socket.h>
54 #include <oonf/base/oonf_timer.h>
55
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 #include <oonf/generic/dlep/radio/dlep_radio.h>
60 #include <oonf/generic/dlep/radio/dlep_radio_interface.h>
61 #include <oonf/generic/dlep/radio/dlep_radio_internal.h>
62 #include <oonf/generic/dlep/radio/dlep_radio_session.h>
63
64 static int _cb_incoming_tcp(struct oonf_stream_session *);
65 static void _cb_tcp_lost(struct oonf_stream_session *);
66 static enum oonf_stream_session_state _cb_tcp_receive_data(struct oonf_stream_session *);
67 static void _cb_send_buffer(struct dlep_session *session, int af_family);
68 static void _cb_end_session(struct dlep_session *session);
69
70 static struct oonf_class _radio_session_class = {
71   .name = "DLEP TCP session",
72   .size = sizeof(struct dlep_radio_session),
73 };
74
75 /**
76  * Initialize framework for dlep radio sessions
77  */
78 void
79 dlep_radio_session_init(void) {
80   oonf_class_add(&_radio_session_class);
81 }
82
83 /**
84  * Cleanup dlep radio session framework
85  */
86 void
87 dlep_radio_session_cleanup(void) {
88   oonf_class_remove(&_radio_session_class);
89 }
90
91 /**
92  * Initialize the callbacks for a dlep tcp socket
93  * @param config tcp socket config
94  */
95 void
96 dlep_radio_session_initialize_tcp_callbacks(struct oonf_stream_config *config) {
97   config->memcookie = &_radio_session_class;
98   config->init_session = _cb_incoming_tcp;
99   config->cleanup_session = _cb_tcp_lost;
100   config->receive_data = _cb_tcp_receive_data;
101 }
102
103 /**
104  * Remove existing dlep radio session
105  * @param radio_session dlep radio session
106  */
107 void
108 dlep_radio_remove_session(struct dlep_radio_session *radio_session) {
109   oonf_stream_close(&radio_session->stream);
110 }
111
112 /**
113  * Callback triggered when a new tcp session is accepted by the local socket
114  * @param tcp_session pointer to tcp session object
115  * @return always 0
116  */
117 static int
118 _cb_incoming_tcp(struct oonf_stream_session *tcp_session) {
119   struct dlep_radio_session *radio_session;
120   struct dlep_radio_if *interface;
121   struct dlep_extension *ext;
122
123   radio_session = container_of(tcp_session, struct dlep_radio_session, stream);
124   interface = container_of(tcp_session->stream_socket->managed, struct dlep_radio_if, tcp);
125
126   /* initialize back pointer */
127   radio_session->interface = interface;
128
129   /* activate session */
130   if (dlep_session_add(&radio_session->session, interface->interf.l2_ifname, interface->interf.session.l2_origin,
131         interface->interf.session.l2_default_origin, &tcp_session->out, true, NULL, LOG_DLEP_RADIO)) {
132     return -1;
133   }
134   radio_session->session.restrict_signal = DLEP_SESSION_INITIALIZATION;
135   radio_session->session.cb_send_buffer = _cb_send_buffer;
136   radio_session->session.cb_end_session = _cb_end_session;
137   memcpy(&radio_session->session.cfg, &interface->interf.session.cfg, sizeof(radio_session->session.cfg));
138   memcpy(
139     &radio_session->session.remote_socket, &tcp_session->remote_socket, sizeof(radio_session->session.remote_socket));
140
141   /* attach to session tree of interface */
142   radio_session->_node.key = &radio_session->stream.remote_socket;
143   avl_insert(&interface->interf.session_tree, &radio_session->_node);
144
145   /* copy socket information */
146   memcpy(
147     &radio_session->session.remote_socket, &tcp_session->remote_socket, sizeof(radio_session->session.remote_socket));
148
149   /* inform all extensions */
150   avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
151     if (ext->cb_session_init_radio) {
152       ext->cb_session_init_radio(&radio_session->session);
153     }
154   }
155
156   return 0;
157 }
158
159 /**
160  * Callback when a tcp session is lost and must be closed
161  * @param tcp_session pointer to tcp session object
162  */
163 static void
164 _cb_tcp_lost(struct oonf_stream_session *tcp_session) {
165   struct dlep_radio_session *radio_session;
166   struct dlep_extension *ext;
167 #ifdef OONF_LOG_DEBUG_INFO
168   struct netaddr_str nbuf;
169 #endif
170
171   radio_session = container_of(tcp_session, struct dlep_radio_session, stream);
172
173   OONF_DEBUG(LOG_DLEP_RADIO, "Lost tcp session to %s", netaddr_socket_to_string(&nbuf, &tcp_session->remote_socket));
174
175   avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
176     if (ext->cb_session_cleanup_radio) {
177       ext->cb_session_cleanup_radio(&radio_session->session);
178     }
179   }
180
181   /* kill embedded session object */
182   dlep_session_remove(&radio_session->session);
183
184   /* remove from session tree of interface */
185   avl_remove(&radio_session->interface->interf.session_tree, &radio_session->_node);
186 }
187
188 /**
189  * Callback to receive data over oonf_stream_socket
190  * @param tcp_session pointer to tcp session
191  * @return tcp session state
192  */
193 static enum oonf_stream_session_state
194 _cb_tcp_receive_data(struct oonf_stream_session *tcp_session) {
195   struct dlep_radio_session *radio_session;
196
197   radio_session = container_of(tcp_session, struct dlep_radio_session, stream);
198
199   return dlep_session_process_tcp(tcp_session, &radio_session->session);
200 }
201
202 static void
203 _cb_send_buffer(struct dlep_session *session, int af_family __attribute((unused))) {
204   struct dlep_radio_session *radio_session;
205
206   if (!abuf_getlen(session->writer.out)) {
207     return;
208   }
209
210   OONF_DEBUG(session->log_source, "Send buffer %" PRINTF_SIZE_T_SPECIFIER " bytes", abuf_getlen(session->writer.out));
211
212   /* get pointer to radio interface */
213   radio_session = container_of(session, struct dlep_radio_session, session);
214
215   oonf_stream_flush(&radio_session->stream);
216 }
217
218 static void
219 _cb_end_session(struct dlep_session *session) {
220   struct dlep_radio_session *radio_session;
221
222   /* get pointer to radio interface */
223   radio_session = container_of(session, struct dlep_radio_session, session);
224
225   dlep_radio_remove_session(radio_session);
226 }