blob: f317219d9fea1446c014d779d8a233066ddaf228 [file] [log] [blame]
Alexander Couzens6a161492020-07-12 13:45:50 +02001/*! \file gprs_ns2_udp.c
2 * NS-over-UDP implementation.
3 * GPRS Networks Service (NS) messages on the Gb interface.
4 * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05)
5 * as well as its successor 3GPP TS 48.016 */
6
7/* (C) 2020 sysmocom - s.f.m.c. GmbH
8 * Author: Alexander Couzens <lynxis@fe80.eu>
9 *
10 * All Rights Reserved
11 *
12 * SPDX-License-Identifier: GPL-2.0+
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 *
27 */
28
29#include <errno.h>
30
31#include <osmocom/core/select.h>
32#include <osmocom/core/sockaddr_str.h>
33#include <osmocom/core/socket.h>
34#include <osmocom/gprs/gprs_ns2.h>
35
36#include "common_vty.h"
37#include "gprs_ns2_internal.h"
38
39
40static void free_bind(struct gprs_ns2_vc_bind *bind);
41
42
43struct gprs_ns2_vc_driver vc_driver_ip = {
44 .name = "GB UDP IPv4/IPv6",
45 .free_bind = free_bind,
46};
47
48struct priv_bind {
49 struct osmo_fd fd;
50 struct osmo_sockaddr addr;
51 int dscp;
52};
53
54struct priv_vc {
55 struct osmo_sockaddr remote;
56};
57
58/*! clean up all private driver state. Should be only called by gprs_ns2_free_bind() */
59static void free_bind(struct gprs_ns2_vc_bind *bind)
60{
61 struct priv_bind *priv;
62
63 if (!bind)
64 return;
65
66 priv = bind->priv;
67
68 osmo_fd_close(&priv->fd);
69 talloc_free(priv);
70}
71
72static void free_vc(struct gprs_ns2_vc *nsvc)
73{
74 if (!nsvc->priv)
75 return;
76
77 talloc_free(nsvc->priv);
78 nsvc->priv = NULL;
79}
80
81int gprs_ns2_find_vc_by_sockaddr(struct gprs_ns2_vc_bind *bind, struct osmo_sockaddr *saddr, struct gprs_ns2_vc **result)
82{
83 struct gprs_ns2_vc *nsvc;
84 struct priv_vc *vcpriv;
85
86 if (!result)
87 return -EINVAL;
88
89 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
90 vcpriv = nsvc->priv;
91 if (vcpriv->remote.u.sa.sa_family != saddr->u.sa.sa_family)
92 continue;
93 if (osmo_sockaddr_cmp(&vcpriv->remote, saddr))
94 continue;
95
96 *result = nsvc;
97 return 0;
98 }
99
100 return 1;
101}
102
103static inline int nsip_sendmsg(struct gprs_ns2_vc_bind *bind,
104 struct msgb *msg,
105 struct osmo_sockaddr *dest)
106{
107 int rc;
108 struct priv_bind *priv = bind->priv;
109
110 rc = sendto(priv->fd.fd, msg->data, msg->len, 0,
111 &dest->u.sa, sizeof(*dest));
112
113 msgb_free(msg);
114
115 return rc;
116}
117
118/*!
119 * \brief nsip_vc_sendmsg will send the msg and free msgb afterwards.
120 * \param vc
121 * \param msg
122 * \return < 0 on erros, otherwise the bytes sent.
123 */
124static int nsip_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
125{
126 int rc;
127 struct gprs_ns2_vc_bind *bind = nsvc->bind;
128 struct priv_vc *priv = nsvc->priv;
129
130 rc = nsip_sendmsg(bind, msg, &priv->remote);
131
132 return rc;
133}
134
135/* Read a single NS-over-IP message */
136static struct msgb *read_nsip_msg(struct osmo_fd *bfd, int *error,
137 struct osmo_sockaddr *saddr)
138{
139 struct msgb *msg = gprs_ns2_msgb_alloc();
140 int ret = 0;
141 socklen_t saddr_len = sizeof(*saddr);
142
143 if (!msg) {
144 *error = -ENOMEM;
145 return NULL;
146 }
147
148 ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE - NS_ALLOC_HEADROOM, 0,
149 &saddr->u.sa, &saddr_len);
150 if (ret < 0) {
151 LOGP(DLNS, LOGL_ERROR, "recv error %s during NSIP recvfrom %s\n",
152 strerror(errno), osmo_sock_get_name2(bfd->fd));
153 msgb_free(msg);
154 *error = ret;
155 return NULL;
156 } else if (ret == 0) {
157 msgb_free(msg);
158 *error = ret;
159 return NULL;
160 }
161
162 msg->l2h = msg->data;
163 msgb_put(msg, ret);
164
165 return msg;
166}
167
168static struct priv_vc *ns2_driver_alloc_vc(struct gprs_ns2_vc_bind *bind, struct gprs_ns2_vc *nsvc, struct osmo_sockaddr *remote)
169{
170 struct priv_vc *priv = talloc_zero(bind, struct priv_vc);
171 if (!priv)
172 return NULL;
173
174 nsvc->priv = priv;
175 priv->remote = *remote;
176
177 return priv;
178}
179
180static int handle_nsip_read(struct osmo_fd *bfd)
181{
182 int rc;
183 int error = 0;
184 struct gprs_ns2_vc_bind *bind = bfd->data;
185 struct osmo_sockaddr saddr;
186 struct gprs_ns2_vc *nsvc;
187 struct msgb *msg = read_nsip_msg(bfd, &error, &saddr);
188 struct msgb *reject;
189
190 if (!msg)
191 return -EINVAL;
192
193 /* check if a vc is available */
194 rc = gprs_ns2_find_vc_by_sockaddr(bind, &saddr, &nsvc);
195 if (rc) {
196 /* VC not found */
197 rc = ns2_create_vc(bind, msg, "newconnection", &reject, &nsvc);
198 switch (rc) {
199 case GPRS_NS2_CS_FOUND:
200 rc = ns2_recv_vc(bind->nsi, nsvc, msg);
201 break;
202 case GPRS_NS2_CS_ERROR:
203 case GPRS_NS2_CS_SKIPPED:
204 rc = 0;
205 break;
206 case GPRS_NS2_CS_REJECTED:
207 /* nsip_sendmsg will free reject */
208 nsip_sendmsg(bind, reject, &saddr);
209 return 0;
210 case GPRS_NS2_CS_CREATED:
211 ns2_driver_alloc_vc(bind, nsvc, &saddr);
212 gprs_ns2_vc_fsm_start(nsvc);
213 rc = ns2_recv_vc(bind->nsi, nsvc, msg);
214 break;
215 }
216 } else {
217 /* VC found */
218 rc = ns2_recv_vc(bind->nsi, nsvc, msg);
219 }
220
221 msgb_free(msg);
222
223 return rc;
224}
225
226static int handle_nsip_write(struct osmo_fd *bfd)
227{
228 /* FIXME: actually send the data here instead of nsip_sendmsg() */
229 return -EIO;
230}
231
232static int nsip_fd_cb(struct osmo_fd *bfd, unsigned int what)
233{
234 int rc = 0;
235
236 if (what & OSMO_FD_READ)
237 rc = handle_nsip_read(bfd);
238 if (what & OSMO_FD_WRITE)
239 rc = handle_nsip_write(bfd);
240
241 return rc;
242}
243
244/*!
245 * \brief bind to an IPv4/IPv6 address
246 * \param[in] nsi NS Instance in which to create the NSVC
247 * \param[in] address the address to bind to
248 * \param[out] result if set, returns the bind object
249 * \return
250 */
251int gprs_ns2_ip_bind(struct gprs_ns2_inst *nsi,
252 struct osmo_sockaddr *local,
253 int dscp,
254 struct gprs_ns2_vc_bind **result)
255{
256 struct gprs_ns2_vc_bind *bind = talloc_zero(nsi, struct gprs_ns2_vc_bind);
257 struct priv_bind *priv;
258 int rc;
259
260 if (!bind)
261 return -ENOSPC;
262
263 if (local->u.sa.sa_family != AF_INET && local->u.sa.sa_family != AF_INET6) {
264 talloc_free(bind);
265 return -EINVAL;
266 }
267
268 bind->driver = &vc_driver_ip;
269 bind->send_vc = nsip_vc_sendmsg;
270 bind->free_vc = free_vc;
271 bind->nsi = nsi;
272
273 priv = bind->priv = talloc_zero(bind, struct priv_bind);
274 if (!priv) {
275 talloc_free(bind);
276 return -ENOSPC;
277 }
278 priv->fd.cb = nsip_fd_cb;
279 priv->fd.data = bind;
280 priv->addr = *local;
281 INIT_LLIST_HEAD(&bind->nsvc);
282
283 llist_add(&bind->list, &nsi->binding);
284
285 rc = osmo_sock_init_osa_ofd(&priv->fd, SOCK_DGRAM, IPPROTO_UDP,
286 local, NULL,
287 OSMO_SOCK_F_BIND);
288 if (rc < 0) {
289 talloc_free(priv);
290 talloc_free(bind);
291 return rc;
292 }
293
294 if (dscp > 0) {
295 priv->dscp = dscp;
296
297 rc = setsockopt(priv->fd.fd, IPPROTO_IP, IP_TOS,
298 &dscp, sizeof(dscp));
299 if (rc < 0)
300 LOGP(DLNS, LOGL_ERROR,
301 "Failed to set the DSCP to %d with ret(%d) errno(%d)\n",
302 dscp, rc, errno);
303 }
304
305 ns2_vty_bind_apply(bind);
306
307 if (result)
308 *result = bind;
309
310 return 0;
311}
312
313struct gprs_ns2_vc *gprs_ns2_ip_bind_connect(struct gprs_ns2_vc_bind *bind,
314 struct gprs_ns2_nse *nse,
315 struct osmo_sockaddr *remote)
316{
317 struct gprs_ns2_vc *nsvc;
318 struct priv_vc *priv;
319
320 nsvc = ns2_vc_alloc(bind, nse, true);
321 nsvc->priv = talloc_zero(bind, struct priv_vc);
322 if (!nsvc->priv) {
323 gprs_ns2_free_nsvc(nsvc);
324 return NULL;
325 }
326
327 priv = nsvc->priv;
328 priv->remote = *remote;
329
330 nsvc->ll = GPRS_NS_LL_UDP;
331
332 return nsvc;
333}
334
335struct osmo_sockaddr *gprs_ns2_ip_vc_sockaddr(struct gprs_ns2_vc *nsvc)
336{
337 struct priv_vc *priv;
338
339 if (nsvc->ll != GPRS_NS_LL_UDP)
340 return NULL;
341
342 priv = nsvc->priv;
343 return &priv->remote;
344}
345
346struct osmo_sockaddr *gprs_ns2_ip_bind_sockaddr(struct gprs_ns2_vc_bind *bind)
347{
348 struct priv_bind *priv;
349
350 priv = bind->priv;
351 return &priv->addr;
352}
353
354int gprs_ns2_is_ip_bind(struct gprs_ns2_vc_bind *bind)
355{
356 return (bind->driver == &vc_driver_ip);
357}
358
359int gprs_ns2_ip_bind_set_dscp(struct gprs_ns2_vc_bind *bind, int dscp)
360{
361 struct priv_bind *priv;
362 int rc = 0;
363
364 priv = bind->priv;
365
366 if (dscp != priv->dscp) {
367 priv->dscp = dscp;
368
369 rc = setsockopt(priv->fd.fd, IPPROTO_IP, IP_TOS,
370 &dscp, sizeof(dscp));
371 if (rc < 0)
372 LOGP(DLNS, LOGL_ERROR,
373 "Failed to set the DSCP to %d with ret(%d) errno(%d)\n",
374 dscp, rc, errno);
375 }
376
377 return rc;
378}