blob: 3eb8116bb3ef9c5052a32204895961bebe64de90 [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
Alexander Couzens22f34712020-10-02 02:34:39 +020081static void dump_vty(const struct gprs_ns2_vc_bind *bind,
82 struct vty *vty, bool _stats)
83{
84 struct priv_bind *priv;
85 struct gprs_ns2_vc *nsvc;
86 struct osmo_sockaddr_str sockstr = {};
87 unsigned long nsvcs = 0;
88
89 if (!bind)
90 return;
91
92 priv = bind->priv;
93 if (osmo_sockaddr_str_from_sockaddr(&sockstr, &priv->addr.u.sas))
94 strcpy(sockstr.ip, "invalid");
95
96 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
97 nsvcs++;
98 }
99
Harald Welte1e72df02020-12-01 18:20:25 +0100100 vty_out(vty, "UDP bind: %s:%d DSCP: %d%s", sockstr.ip, sockstr.port, priv->dscp, VTY_NEWLINE);
Alexander Couzens22f34712020-10-02 02:34:39 +0200101 vty_out(vty, " %lu NS-VC: %s", nsvcs, VTY_NEWLINE);
102
103 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
Harald Welte96ec84a2020-12-01 17:56:05 +0100104 vty_out(vty, " NSVCI %05u: %s%s", nsvc->nsvci, gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens22f34712020-10-02 02:34:39 +0200105 }
106}
107
108
Harald Welte5bef2cc2020-09-18 22:33:24 +0200109/*! Find a NS-VC by its remote socket address.
110 * \param[in] bind in which to search
111 * \param[in] saddr remote peer socket adddress to search
Alexander Couzens38b19e82020-09-23 23:56:37 +0200112 * \returns NS-VC matching sockaddr; NULL if none found */
Vadim Yanitskiya07f25e2020-10-09 21:47:01 +0700113struct gprs_ns2_vc *gprs_ns2_nsvc_by_sockaddr_bind(struct gprs_ns2_vc_bind *bind,
114 const struct osmo_sockaddr *saddr)
Alexander Couzens6a161492020-07-12 13:45:50 +0200115{
116 struct gprs_ns2_vc *nsvc;
117 struct priv_vc *vcpriv;
118
Alexander Couzens6a161492020-07-12 13:45:50 +0200119 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
120 vcpriv = nsvc->priv;
121 if (vcpriv->remote.u.sa.sa_family != saddr->u.sa.sa_family)
122 continue;
123 if (osmo_sockaddr_cmp(&vcpriv->remote, saddr))
124 continue;
125
Alexander Couzens38b19e82020-09-23 23:56:37 +0200126 return nsvc;
Alexander Couzens6a161492020-07-12 13:45:50 +0200127 }
128
Alexander Couzens38b19e82020-09-23 23:56:37 +0200129 return NULL;
Alexander Couzens6a161492020-07-12 13:45:50 +0200130}
131
132static inline int nsip_sendmsg(struct gprs_ns2_vc_bind *bind,
133 struct msgb *msg,
134 struct osmo_sockaddr *dest)
135{
136 int rc;
137 struct priv_bind *priv = bind->priv;
138
139 rc = sendto(priv->fd.fd, msg->data, msg->len, 0,
140 &dest->u.sa, sizeof(*dest));
141
142 msgb_free(msg);
143
144 return rc;
145}
146
Harald Welte5bef2cc2020-09-18 22:33:24 +0200147/*! send the msg and free it afterwards.
148 * \param nsvc NS-VC on which the message shall be sent
149 * \param msg message to be sent
150 * \return number of bytes transmitted; negative on error */
Alexander Couzens6a161492020-07-12 13:45:50 +0200151static int nsip_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
152{
153 int rc;
154 struct gprs_ns2_vc_bind *bind = nsvc->bind;
155 struct priv_vc *priv = nsvc->priv;
156
157 rc = nsip_sendmsg(bind, msg, &priv->remote);
158
159 return rc;
160}
161
162/* Read a single NS-over-IP message */
163static struct msgb *read_nsip_msg(struct osmo_fd *bfd, int *error,
164 struct osmo_sockaddr *saddr)
165{
166 struct msgb *msg = gprs_ns2_msgb_alloc();
167 int ret = 0;
168 socklen_t saddr_len = sizeof(*saddr);
169
170 if (!msg) {
171 *error = -ENOMEM;
172 return NULL;
173 }
174
175 ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE - NS_ALLOC_HEADROOM, 0,
176 &saddr->u.sa, &saddr_len);
177 if (ret < 0) {
178 LOGP(DLNS, LOGL_ERROR, "recv error %s during NSIP recvfrom %s\n",
179 strerror(errno), osmo_sock_get_name2(bfd->fd));
180 msgb_free(msg);
181 *error = ret;
182 return NULL;
183 } else if (ret == 0) {
184 msgb_free(msg);
185 *error = ret;
186 return NULL;
187 }
188
189 msg->l2h = msg->data;
190 msgb_put(msg, ret);
191
192 return msg;
193}
194
195static struct priv_vc *ns2_driver_alloc_vc(struct gprs_ns2_vc_bind *bind, struct gprs_ns2_vc *nsvc, struct osmo_sockaddr *remote)
196{
197 struct priv_vc *priv = talloc_zero(bind, struct priv_vc);
198 if (!priv)
199 return NULL;
200
201 nsvc->priv = priv;
202 priv->remote = *remote;
203
204 return priv;
205}
206
207static int handle_nsip_read(struct osmo_fd *bfd)
208{
Alexander Couzenscce88282020-10-26 00:25:50 +0100209 int rc = 0;
Alexander Couzens6a161492020-07-12 13:45:50 +0200210 int error = 0;
211 struct gprs_ns2_vc_bind *bind = bfd->data;
212 struct osmo_sockaddr saddr;
213 struct gprs_ns2_vc *nsvc;
214 struct msgb *msg = read_nsip_msg(bfd, &error, &saddr);
215 struct msgb *reject;
216
217 if (!msg)
218 return -EINVAL;
219
220 /* check if a vc is available */
Alexander Couzens38b19e82020-09-23 23:56:37 +0200221 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &saddr);
222 if (!nsvc) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200223 /* VC not found */
224 rc = ns2_create_vc(bind, msg, "newconnection", &reject, &nsvc);
225 switch (rc) {
226 case GPRS_NS2_CS_FOUND:
Alexander Couzens6a161492020-07-12 13:45:50 +0200227 break;
228 case GPRS_NS2_CS_ERROR:
229 case GPRS_NS2_CS_SKIPPED:
230 rc = 0;
Alexander Couzens13010122020-09-24 00:54:51 +0200231 goto out;
Alexander Couzens6a161492020-07-12 13:45:50 +0200232 case GPRS_NS2_CS_REJECTED:
233 /* nsip_sendmsg will free reject */
Alexander Couzens772ca612020-09-24 16:19:02 +0200234 rc = nsip_sendmsg(bind, reject, &saddr);
235 goto out;
Alexander Couzens6a161492020-07-12 13:45:50 +0200236 case GPRS_NS2_CS_CREATED:
237 ns2_driver_alloc_vc(bind, nsvc, &saddr);
238 gprs_ns2_vc_fsm_start(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200239 break;
240 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200241 }
242
Alexander Couzenscce88282020-10-26 00:25:50 +0100243 return ns2_recv_vc(nsvc, msg);
244
Alexander Couzens13010122020-09-24 00:54:51 +0200245out:
Alexander Couzens6a161492020-07-12 13:45:50 +0200246 msgb_free(msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200247 return rc;
248}
249
250static int handle_nsip_write(struct osmo_fd *bfd)
251{
252 /* FIXME: actually send the data here instead of nsip_sendmsg() */
253 return -EIO;
254}
255
256static int nsip_fd_cb(struct osmo_fd *bfd, unsigned int what)
257{
258 int rc = 0;
259
260 if (what & OSMO_FD_READ)
261 rc = handle_nsip_read(bfd);
262 if (what & OSMO_FD_WRITE)
263 rc = handle_nsip_write(bfd);
264
265 return rc;
266}
267
Alexander Couzens4f608452020-10-11 18:41:24 +0200268/*! Find NS bind for a given socket address
269 * \param[in] nsi NS instance
270 * \param[in] sockaddr socket address to search for
271 * \return
272 */
273struct gprs_ns2_vc_bind *gprs_ns2_ip_bind_by_sockaddr(struct gprs_ns2_inst *nsi,
274 const struct osmo_sockaddr *sockaddr)
275{
276 struct gprs_ns2_vc_bind *bind;
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200277 const struct osmo_sockaddr *local;
Alexander Couzens4f608452020-10-11 18:41:24 +0200278
279 OSMO_ASSERT(nsi);
280 OSMO_ASSERT(sockaddr);
281
282 llist_for_each_entry(bind, &nsi->binding, list) {
283 if (!gprs_ns2_is_ip_bind(bind))
284 continue;
285
286 local = gprs_ns2_ip_bind_sockaddr(bind);
287 if (!osmo_sockaddr_cmp(sockaddr, local))
288 return bind;
289 }
290
291 return NULL;
292}
293
Harald Welte5bef2cc2020-09-18 22:33:24 +0200294/*! Bind to an IPv4/IPv6 address
295 * \param[in] nsi NS Instance in which to create the NSVC
296 * \param[in] local the local address to bind to
297 * \param[in] dscp the DSCP/TOS bits used for transmitted data
298 * \param[out] result if set, returns the bind object
299 * \return 0 on success; negative in case of error */
Alexander Couzens6a161492020-07-12 13:45:50 +0200300int gprs_ns2_ip_bind(struct gprs_ns2_inst *nsi,
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100301 const char *name,
Vadim Yanitskiya07f25e2020-10-09 21:47:01 +0700302 const struct osmo_sockaddr *local,
Alexander Couzens6a161492020-07-12 13:45:50 +0200303 int dscp,
304 struct gprs_ns2_vc_bind **result)
305{
Alexander Couzens6090b1d2020-10-11 18:41:37 +0200306 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6a161492020-07-12 13:45:50 +0200307 struct priv_bind *priv;
308 int rc;
309
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100310 if (!name)
311 return -EINVAL;
312
313 if (gprs_ns2_bind_by_name(nsi, name))
314 return -EALREADY;
315
Alexander Couzens6090b1d2020-10-11 18:41:37 +0200316 bind = gprs_ns2_ip_bind_by_sockaddr(nsi, local);
317 if (bind) {
318 *result = bind;
319 return -EBUSY;
320 }
321
322 bind = talloc_zero(nsi, struct gprs_ns2_vc_bind);
Alexander Couzens6a161492020-07-12 13:45:50 +0200323 if (!bind)
324 return -ENOSPC;
325
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100326 bind->name = talloc_strdup(bind, name);
327 if (!bind->name) {
328 talloc_free(bind);
329 return -ENOSPC;
330 }
331
Alexander Couzens6a161492020-07-12 13:45:50 +0200332 if (local->u.sa.sa_family != AF_INET && local->u.sa.sa_family != AF_INET6) {
333 talloc_free(bind);
334 return -EINVAL;
335 }
336
337 bind->driver = &vc_driver_ip;
Alexander Couzensaac90162020-11-19 02:44:04 +0100338 bind->ll = GPRS_NS2_LL_UDP;
Alexander Couzens6a161492020-07-12 13:45:50 +0200339 bind->send_vc = nsip_vc_sendmsg;
340 bind->free_vc = free_vc;
Alexander Couzens22f34712020-10-02 02:34:39 +0200341 bind->dump_vty = dump_vty;
Alexander Couzens6a161492020-07-12 13:45:50 +0200342 bind->nsi = nsi;
343
344 priv = bind->priv = talloc_zero(bind, struct priv_bind);
345 if (!priv) {
346 talloc_free(bind);
347 return -ENOSPC;
348 }
349 priv->fd.cb = nsip_fd_cb;
350 priv->fd.data = bind;
351 priv->addr = *local;
352 INIT_LLIST_HEAD(&bind->nsvc);
353
Alexander Couzens6a161492020-07-12 13:45:50 +0200354 rc = osmo_sock_init_osa_ofd(&priv->fd, SOCK_DGRAM, IPPROTO_UDP,
355 local, NULL,
356 OSMO_SOCK_F_BIND);
357 if (rc < 0) {
358 talloc_free(priv);
359 talloc_free(bind);
360 return rc;
361 }
362
363 if (dscp > 0) {
364 priv->dscp = dscp;
365
366 rc = setsockopt(priv->fd.fd, IPPROTO_IP, IP_TOS,
367 &dscp, sizeof(dscp));
368 if (rc < 0)
369 LOGP(DLNS, LOGL_ERROR,
370 "Failed to set the DSCP to %d with ret(%d) errno(%d)\n",
371 dscp, rc, errno);
372 }
373
Pau Espin Pedrolaa83d412020-10-09 14:20:13 +0200374 llist_add(&bind->list, &nsi->binding);
Alexander Couzens6a161492020-07-12 13:45:50 +0200375 if (result)
376 *result = bind;
377
378 return 0;
379}
380
Harald Welte5bef2cc2020-09-18 22:33:24 +0200381/*! Create new NS-VC to a given remote address
382 * \param[in] bind the bind we want to connect
383 * \param[in] nse NS entity to be used for the new NS-VC
384 * \param[in] remote remote address to connect to
385 * \return pointer to newly-allocated and connected NS-VC; NULL on error */
Alexander Couzens6a161492020-07-12 13:45:50 +0200386struct gprs_ns2_vc *gprs_ns2_ip_bind_connect(struct gprs_ns2_vc_bind *bind,
387 struct gprs_ns2_nse *nse,
Vadim Yanitskiya07f25e2020-10-09 21:47:01 +0700388 const struct osmo_sockaddr *remote)
Alexander Couzens6a161492020-07-12 13:45:50 +0200389{
390 struct gprs_ns2_vc *nsvc;
391 struct priv_vc *priv;
Alexander Couzensd923cff2020-12-01 01:03:52 +0100392 enum gprs_ns2_vc_mode vc_mode;
Alexander Couzens6a161492020-07-12 13:45:50 +0200393
Alexander Couzensd923cff2020-12-01 01:03:52 +0100394 vc_mode = gprs_ns2_dialect_to_vc_mode(nse->dialect);
395 if ((int) vc_mode == -1) {
396 LOGP(DLNS, LOGL_ERROR, "Can not derive vc mode from dialect %d. Maybe libosmocore is too old.\n",
397 nse->dialect);
398 return NULL;
399 }
400
401 nsvc = ns2_vc_alloc(bind, nse, true, vc_mode);
Alexander Couzensc06aa712020-11-18 23:56:45 +0100402 if (!nsvc)
403 return NULL;
404
Alexander Couzens6a161492020-07-12 13:45:50 +0200405 nsvc->priv = talloc_zero(bind, struct priv_vc);
406 if (!nsvc->priv) {
407 gprs_ns2_free_nsvc(nsvc);
408 return NULL;
409 }
410
411 priv = nsvc->priv;
412 priv->remote = *remote;
413
Alexander Couzens6a161492020-07-12 13:45:50 +0200414 return nsvc;
415}
416
Alexander Couzens979f5f52020-10-11 21:01:48 +0200417/*! Return the socket address of the local peer of a NS-VC.
418 * \param[in] nsvc NS-VC whose local peer we want to know
419 * \return address of the local peer; NULL in case of error */
420const struct osmo_sockaddr *gprs_ns2_ip_vc_local(const struct gprs_ns2_vc *nsvc)
421{
422 struct priv_bind *priv;
423
Alexander Couzens979f5f52020-10-11 21:01:48 +0200424 if (nsvc->bind->driver != &vc_driver_ip)
425 return NULL;
426
427 priv = nsvc->bind->priv;
428 return &priv->addr;
429}
430
Harald Welte5bef2cc2020-09-18 22:33:24 +0200431/*! Return the socket address of the remote peer of a NS-VC.
432 * \param[in] nsvc NS-VC whose remote peer we want to know
433 * \return address of the remote peer; NULL in case of error */
Alexander Couzensd33512b2020-10-11 21:42:11 +0200434const struct osmo_sockaddr *gprs_ns2_ip_vc_remote(const struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +0200435{
436 struct priv_vc *priv;
437
Alexander Couzensaac90162020-11-19 02:44:04 +0100438 if (nsvc->bind->driver != &vc_driver_ip)
Alexander Couzens6a161492020-07-12 13:45:50 +0200439 return NULL;
440
441 priv = nsvc->priv;
442 return &priv->remote;
443}
444
Alexander Couzensd420ea92020-10-12 01:11:05 +0200445/*! Compare the NS-VC with the given parameter
446 * \param[in] nsvc NS-VC to compare with
447 * \param[in] local The local address
448 * \param[in] remote The remote address
449 * \param[in] nsvci NS-VCI will only be used if the NS-VC in BLOCKRESET mode otherwise NS-VCI isn't applicable.
450 * \return true if the NS-VC has the same properties as given
451 */
452bool gprs_ns2_ip_vc_equal(const struct gprs_ns2_vc *nsvc,
453 const struct osmo_sockaddr *local,
454 const struct osmo_sockaddr *remote,
455 uint16_t nsvci)
456{
457 struct priv_vc *vpriv;
458 struct priv_bind *bpriv;
459
Alexander Couzensaac90162020-11-19 02:44:04 +0100460 if (nsvc->bind->driver != &vc_driver_ip)
Alexander Couzensd420ea92020-10-12 01:11:05 +0200461 return false;
462
463 vpriv = nsvc->priv;
464 bpriv = nsvc->bind->priv;
465
466 if (osmo_sockaddr_cmp(local, &bpriv->addr))
467 return false;
468
469 if (osmo_sockaddr_cmp(remote, &vpriv->remote))
470 return false;
471
472 if (nsvc->mode == NS2_VC_MODE_BLOCKRESET)
473 if (nsvc->nsvci != nsvci)
474 return false;
475
476 return true;
477}
478
Harald Welte5bef2cc2020-09-18 22:33:24 +0200479/*! Return the locally bound socket address of the bind.
480 * \param[in] bind The bind whose local address we want to know
481 * \return address of the local bind */
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200482const struct osmo_sockaddr *gprs_ns2_ip_bind_sockaddr(struct gprs_ns2_vc_bind *bind)
Alexander Couzens6a161492020-07-12 13:45:50 +0200483{
484 struct priv_bind *priv;
485
486 priv = bind->priv;
487 return &priv->addr;
488}
489
Harald Welte5bef2cc2020-09-18 22:33:24 +0200490/*! Is the given bind an IP bind? */
Alexander Couzens6a161492020-07-12 13:45:50 +0200491int gprs_ns2_is_ip_bind(struct gprs_ns2_vc_bind *bind)
492{
493 return (bind->driver == &vc_driver_ip);
494}
495
Harald Welte5bef2cc2020-09-18 22:33:24 +0200496/*! Set the DSCP (TOS) bit value of the given bind. */
Alexander Couzens6a161492020-07-12 13:45:50 +0200497int gprs_ns2_ip_bind_set_dscp(struct gprs_ns2_vc_bind *bind, int dscp)
498{
499 struct priv_bind *priv;
500 int rc = 0;
501
502 priv = bind->priv;
503
504 if (dscp != priv->dscp) {
505 priv->dscp = dscp;
506
507 rc = setsockopt(priv->fd.fd, IPPROTO_IP, IP_TOS,
508 &dscp, sizeof(dscp));
509 if (rc < 0)
510 LOGP(DLNS, LOGL_ERROR,
511 "Failed to set the DSCP to %d with ret(%d) errno(%d)\n",
512 dscp, rc, errno);
513 }
514
515 return rc;
516}