blob: 7980df592f345268e57593ce6a331db8dd7bbe10 [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;
Harald Welted99e4ee2021-04-28 19:57:12 +020052 uint8_t priority;
Alexander Couzens6a161492020-07-12 13:45:50 +020053};
54
55struct priv_vc {
56 struct osmo_sockaddr remote;
57};
58
59/*! clean up all private driver state. Should be only called by gprs_ns2_free_bind() */
60static void free_bind(struct gprs_ns2_vc_bind *bind)
61{
62 struct priv_bind *priv;
63
64 if (!bind)
65 return;
66
Alexander Couzens55bc8692021-01-18 18:39:57 +010067 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
68
Alexander Couzens6a161492020-07-12 13:45:50 +020069 priv = bind->priv;
70
71 osmo_fd_close(&priv->fd);
72 talloc_free(priv);
73}
74
75static void free_vc(struct gprs_ns2_vc *nsvc)
76{
Alexander Couzensea377242021-01-17 16:51:55 +010077 if (!nsvc)
78 return;
79
Alexander Couzens6a161492020-07-12 13:45:50 +020080 if (!nsvc->priv)
81 return;
82
Alexander Couzens55bc8692021-01-18 18:39:57 +010083 OSMO_ASSERT(gprs_ns2_is_ip_bind(nsvc->bind));
Alexander Couzens6a161492020-07-12 13:45:50 +020084 talloc_free(nsvc->priv);
85 nsvc->priv = NULL;
86}
87
Alexander Couzens22f34712020-10-02 02:34:39 +020088static void dump_vty(const struct gprs_ns2_vc_bind *bind,
Alexander Couzens75b61882021-03-21 16:18:17 +010089 struct vty *vty, bool stats)
Alexander Couzens22f34712020-10-02 02:34:39 +020090{
91 struct priv_bind *priv;
92 struct gprs_ns2_vc *nsvc;
93 struct osmo_sockaddr_str sockstr = {};
94 unsigned long nsvcs = 0;
95
96 if (!bind)
97 return;
98
99 priv = bind->priv;
100 if (osmo_sockaddr_str_from_sockaddr(&sockstr, &priv->addr.u.sas))
101 strcpy(sockstr.ip, "invalid");
102
103 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
104 nsvcs++;
105 }
106
Harald Welted99e4ee2021-04-28 19:57:12 +0200107 vty_out(vty, "UDP bind: %s:%d DSCP: %d Priority: %u%s", sockstr.ip, sockstr.port,
108 priv->dscp, priv->priority, VTY_NEWLINE);
Alexander Couzensc4704762021-02-08 23:13:12 +0100109 vty_out(vty, " IP-SNS signalling weight: %u data weight: %u%s",
110 bind->sns_sig_weight, bind->sns_data_weight, VTY_NEWLINE);
Alexander Couzens8bd63b62021-03-21 17:45:22 +0100111 vty_out(vty, " %lu NS-VC:%s", nsvcs, VTY_NEWLINE);
Alexander Couzens22f34712020-10-02 02:34:39 +0200112
113 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
Alexander Couzens75b61882021-03-21 16:18:17 +0100114 ns2_vty_dump_nsvc(vty, nsvc, stats);
Alexander Couzens22f34712020-10-02 02:34:39 +0200115 }
116}
117
118
Harald Welte5bef2cc2020-09-18 22:33:24 +0200119/*! Find a NS-VC by its remote socket address.
120 * \param[in] bind in which to search
121 * \param[in] saddr remote peer socket adddress to search
Alexander Couzens38b19e82020-09-23 23:56:37 +0200122 * \returns NS-VC matching sockaddr; NULL if none found */
Vadim Yanitskiya07f25e2020-10-09 21:47:01 +0700123struct gprs_ns2_vc *gprs_ns2_nsvc_by_sockaddr_bind(struct gprs_ns2_vc_bind *bind,
124 const struct osmo_sockaddr *saddr)
Alexander Couzens6a161492020-07-12 13:45:50 +0200125{
126 struct gprs_ns2_vc *nsvc;
127 struct priv_vc *vcpriv;
128
Alexander Couzens55bc8692021-01-18 18:39:57 +0100129 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
130
Alexander Couzens6a161492020-07-12 13:45:50 +0200131 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
132 vcpriv = nsvc->priv;
133 if (vcpriv->remote.u.sa.sa_family != saddr->u.sa.sa_family)
134 continue;
135 if (osmo_sockaddr_cmp(&vcpriv->remote, saddr))
136 continue;
137
Alexander Couzens38b19e82020-09-23 23:56:37 +0200138 return nsvc;
Alexander Couzens6a161492020-07-12 13:45:50 +0200139 }
140
Alexander Couzens38b19e82020-09-23 23:56:37 +0200141 return NULL;
Alexander Couzens6a161492020-07-12 13:45:50 +0200142}
143
144static inline int nsip_sendmsg(struct gprs_ns2_vc_bind *bind,
145 struct msgb *msg,
146 struct osmo_sockaddr *dest)
147{
148 int rc;
149 struct priv_bind *priv = bind->priv;
150
151 rc = sendto(priv->fd.fd, msg->data, msg->len, 0,
152 &dest->u.sa, sizeof(*dest));
153
154 msgb_free(msg);
155
156 return rc;
157}
158
Harald Welte5bef2cc2020-09-18 22:33:24 +0200159/*! send the msg and free it afterwards.
160 * \param nsvc NS-VC on which the message shall be sent
161 * \param msg message to be sent
162 * \return number of bytes transmitted; negative on error */
Alexander Couzens6a161492020-07-12 13:45:50 +0200163static int nsip_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
164{
165 int rc;
166 struct gprs_ns2_vc_bind *bind = nsvc->bind;
167 struct priv_vc *priv = nsvc->priv;
168
169 rc = nsip_sendmsg(bind, msg, &priv->remote);
170
171 return rc;
172}
173
174/* Read a single NS-over-IP message */
Harald Weltef2949742021-01-20 14:54:14 +0100175static struct msgb *read_nsip_msg(struct osmo_fd *bfd, int *error, struct osmo_sockaddr *saddr,
176 const struct gprs_ns2_vc_bind *bind)
Alexander Couzens6a161492020-07-12 13:45:50 +0200177{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100178 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200179 int ret = 0;
180 socklen_t saddr_len = sizeof(*saddr);
181
182 if (!msg) {
183 *error = -ENOMEM;
184 return NULL;
185 }
186
187 ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE - NS_ALLOC_HEADROOM, 0,
188 &saddr->u.sa, &saddr_len);
189 if (ret < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100190 LOGBIND(bind, LOGL_ERROR, "recv error %s during NSIP recvfrom %s\n",
191 strerror(errno), osmo_sock_get_name2(bfd->fd));
Alexander Couzens6a161492020-07-12 13:45:50 +0200192 msgb_free(msg);
193 *error = ret;
194 return NULL;
195 } else if (ret == 0) {
196 msgb_free(msg);
197 *error = ret;
198 return NULL;
199 }
200
201 msg->l2h = msg->data;
202 msgb_put(msg, ret);
203
204 return msg;
205}
206
207static struct priv_vc *ns2_driver_alloc_vc(struct gprs_ns2_vc_bind *bind, struct gprs_ns2_vc *nsvc, struct osmo_sockaddr *remote)
208{
209 struct priv_vc *priv = talloc_zero(bind, struct priv_vc);
210 if (!priv)
211 return NULL;
212
213 nsvc->priv = priv;
214 priv->remote = *remote;
215
216 return priv;
217}
218
219static int handle_nsip_read(struct osmo_fd *bfd)
220{
Alexander Couzenscce88282020-10-26 00:25:50 +0100221 int rc = 0;
Alexander Couzens6a161492020-07-12 13:45:50 +0200222 int error = 0;
223 struct gprs_ns2_vc_bind *bind = bfd->data;
224 struct osmo_sockaddr saddr;
225 struct gprs_ns2_vc *nsvc;
Harald Weltef2949742021-01-20 14:54:14 +0100226 struct msgb *msg = read_nsip_msg(bfd, &error, &saddr, bind);
Alexander Couzens6a161492020-07-12 13:45:50 +0200227 struct msgb *reject;
228
229 if (!msg)
230 return -EINVAL;
231
232 /* check if a vc is available */
Alexander Couzens38b19e82020-09-23 23:56:37 +0200233 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &saddr);
234 if (!nsvc) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200235 /* VC not found */
Harald Welte7d0daac2021-03-02 23:08:43 +0100236 rc = ns2_create_vc(bind, msg, &saddr, "newconnection", &reject, &nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200237 switch (rc) {
Alexander Couzensba5a9922021-01-25 16:03:23 +0100238 case NS2_CS_FOUND:
Alexander Couzens6a161492020-07-12 13:45:50 +0200239 break;
Alexander Couzensba5a9922021-01-25 16:03:23 +0100240 case NS2_CS_ERROR:
241 case NS2_CS_SKIPPED:
Alexander Couzens6a161492020-07-12 13:45:50 +0200242 rc = 0;
Alexander Couzens13010122020-09-24 00:54:51 +0200243 goto out;
Alexander Couzensba5a9922021-01-25 16:03:23 +0100244 case NS2_CS_REJECTED:
Alexander Couzens6a161492020-07-12 13:45:50 +0200245 /* nsip_sendmsg will free reject */
Alexander Couzens772ca612020-09-24 16:19:02 +0200246 rc = nsip_sendmsg(bind, reject, &saddr);
247 goto out;
Alexander Couzensba5a9922021-01-25 16:03:23 +0100248 case NS2_CS_CREATED:
Alexander Couzens6a161492020-07-12 13:45:50 +0200249 ns2_driver_alloc_vc(bind, nsvc, &saddr);
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100250 ns2_vc_fsm_start(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200251 break;
252 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200253 }
254
Alexander Couzenscce88282020-10-26 00:25:50 +0100255 return ns2_recv_vc(nsvc, msg);
256
Alexander Couzens13010122020-09-24 00:54:51 +0200257out:
Alexander Couzens6a161492020-07-12 13:45:50 +0200258 msgb_free(msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200259 return rc;
260}
261
262static int handle_nsip_write(struct osmo_fd *bfd)
263{
264 /* FIXME: actually send the data here instead of nsip_sendmsg() */
265 return -EIO;
266}
267
268static int nsip_fd_cb(struct osmo_fd *bfd, unsigned int what)
269{
270 int rc = 0;
271
272 if (what & OSMO_FD_READ)
273 rc = handle_nsip_read(bfd);
274 if (what & OSMO_FD_WRITE)
275 rc = handle_nsip_write(bfd);
276
277 return rc;
278}
279
Alexander Couzens4f608452020-10-11 18:41:24 +0200280/*! Find NS bind for a given socket address
281 * \param[in] nsi NS instance
282 * \param[in] sockaddr socket address to search for
283 * \return
284 */
285struct gprs_ns2_vc_bind *gprs_ns2_ip_bind_by_sockaddr(struct gprs_ns2_inst *nsi,
286 const struct osmo_sockaddr *sockaddr)
287{
288 struct gprs_ns2_vc_bind *bind;
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200289 const struct osmo_sockaddr *local;
Alexander Couzens4f608452020-10-11 18:41:24 +0200290
291 OSMO_ASSERT(nsi);
292 OSMO_ASSERT(sockaddr);
293
294 llist_for_each_entry(bind, &nsi->binding, list) {
295 if (!gprs_ns2_is_ip_bind(bind))
296 continue;
297
298 local = gprs_ns2_ip_bind_sockaddr(bind);
299 if (!osmo_sockaddr_cmp(sockaddr, local))
300 return bind;
301 }
302
303 return NULL;
304}
305
Harald Welte5bef2cc2020-09-18 22:33:24 +0200306/*! Bind to an IPv4/IPv6 address
307 * \param[in] nsi NS Instance in which to create the NSVC
308 * \param[in] local the local address to bind to
309 * \param[in] dscp the DSCP/TOS bits used for transmitted data
Alexander Couzensc80a8742021-02-03 11:27:52 +0100310 * \param[out] result pointer to the created bind or if a bind with the name exists return the bind.
311 * \return 0 on success; negative on error. -EALREADY returned in case a bind with the name exists */
Alexander Couzens6a161492020-07-12 13:45:50 +0200312int gprs_ns2_ip_bind(struct gprs_ns2_inst *nsi,
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100313 const char *name,
Vadim Yanitskiya07f25e2020-10-09 21:47:01 +0700314 const struct osmo_sockaddr *local,
Alexander Couzens6a161492020-07-12 13:45:50 +0200315 int dscp,
316 struct gprs_ns2_vc_bind **result)
317{
Alexander Couzens6090b1d2020-10-11 18:41:37 +0200318 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6a161492020-07-12 13:45:50 +0200319 struct priv_bind *priv;
320 int rc;
321
Harald Weltec3aa8f92021-01-31 11:41:34 +0100322 if (local->u.sa.sa_family != AF_INET && local->u.sa.sa_family != AF_INET6)
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100323 return -EINVAL;
324
Harald Weltec96d7162021-04-27 21:56:25 +0200325 if (dscp < 0 || dscp > 63)
326 return -EINVAL;
327
Alexander Couzens6090b1d2020-10-11 18:41:37 +0200328 bind = gprs_ns2_ip_bind_by_sockaddr(nsi, local);
329 if (bind) {
Alexander Couzensc80a8742021-02-03 11:27:52 +0100330 if (result)
331 *result = bind;
Alexander Couzens6090b1d2020-10-11 18:41:37 +0200332 return -EBUSY;
333 }
334
Harald Weltec3aa8f92021-01-31 11:41:34 +0100335 rc = ns2_bind_alloc(nsi, name, &bind);
336 if (rc < 0)
337 return rc;
Alexander Couzens6a161492020-07-12 13:45:50 +0200338
339 bind->driver = &vc_driver_ip;
Alexander Couzensaac90162020-11-19 02:44:04 +0100340 bind->ll = GPRS_NS2_LL_UDP;
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100341 /* expect 100 mbit at least.
342 * TODO: ask the network layer about the speed. But would require
343 * notification on change. */
344 bind->transfer_capability = 100;
Alexander Couzens6a161492020-07-12 13:45:50 +0200345 bind->send_vc = nsip_vc_sendmsg;
346 bind->free_vc = free_vc;
Alexander Couzens22f34712020-10-02 02:34:39 +0200347 bind->dump_vty = dump_vty;
Alexander Couzens6a161492020-07-12 13:45:50 +0200348
349 priv = bind->priv = talloc_zero(bind, struct priv_bind);
350 if (!priv) {
Harald Weltec3aa8f92021-01-31 11:41:34 +0100351 gprs_ns2_free_bind(bind);
Harald Weltebdfb8b92021-01-31 11:44:57 +0100352 return -ENOMEM;
Alexander Couzens6a161492020-07-12 13:45:50 +0200353 }
354 priv->fd.cb = nsip_fd_cb;
355 priv->fd.data = bind;
356 priv->addr = *local;
Harald Welte485b3f72021-04-28 19:45:34 +0200357 priv->dscp = dscp;
Alexander Couzens6a161492020-07-12 13:45:50 +0200358
Alexander Couzens6a161492020-07-12 13:45:50 +0200359 rc = osmo_sock_init_osa_ofd(&priv->fd, SOCK_DGRAM, IPPROTO_UDP,
360 local, NULL,
Harald Welte485b3f72021-04-28 19:45:34 +0200361 OSMO_SOCK_F_BIND | OSMO_SOCK_F_DSCP(priv->dscp));
Alexander Couzens6a161492020-07-12 13:45:50 +0200362 if (rc < 0) {
Harald Weltec3aa8f92021-01-31 11:41:34 +0100363 gprs_ns2_free_bind(bind);
Alexander Couzens6a161492020-07-12 13:45:50 +0200364 return rc;
365 }
366
Alexander Couzens4f1128f2021-01-20 17:42:48 +0100367 /* IPv4: max fragmented payload can be (13 bit) * 8 byte => 65535.
368 * IPv6: max payload can be 65535 (RFC 2460).
369 * UDP header = 8 byte */
370 bind->mtu = 65535 - 8;
Alexander Couzens6a161492020-07-12 13:45:50 +0200371 if (result)
372 *result = bind;
373
374 return 0;
375}
376
Harald Welte5bef2cc2020-09-18 22:33:24 +0200377/*! Create new NS-VC to a given remote address
378 * \param[in] bind the bind we want to connect
379 * \param[in] nse NS entity to be used for the new NS-VC
380 * \param[in] remote remote address to connect to
381 * \return pointer to newly-allocated and connected NS-VC; NULL on error */
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100382struct gprs_ns2_vc *ns2_ip_bind_connect(struct gprs_ns2_vc_bind *bind,
383 struct gprs_ns2_nse *nse,
384 const struct osmo_sockaddr *remote)
Alexander Couzens6a161492020-07-12 13:45:50 +0200385{
386 struct gprs_ns2_vc *nsvc;
387 struct priv_vc *priv;
Alexander Couzensd923cff2020-12-01 01:03:52 +0100388 enum gprs_ns2_vc_mode vc_mode;
Harald Welte603f4042020-11-29 17:39:19 +0100389 char *sockaddr_str;
390 char idbuf[64];
Alexander Couzens6a161492020-07-12 13:45:50 +0200391
Alexander Couzens55bc8692021-01-18 18:39:57 +0100392 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
393
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100394 vc_mode = ns2_dialect_to_vc_mode(nse->dialect);
Alexander Couzensd923cff2020-12-01 01:03:52 +0100395 if ((int) vc_mode == -1) {
Harald Weltef2949742021-01-20 14:54:14 +0100396 LOGNSE(nse, LOGL_ERROR, "Can not derive vc mode from dialect %d. Maybe libosmocore is too old.\n",
397 nse->dialect);
Alexander Couzensd923cff2020-12-01 01:03:52 +0100398 return NULL;
399 }
400
Alexander Couzens7bb39e32021-02-16 23:06:53 +0100401 /* duplicate */
402 if (gprs_ns2_nsvc_by_sockaddr_bind(bind, remote))
403 return NULL;
404
Harald Welte603f4042020-11-29 17:39:19 +0100405 sockaddr_str = (char *)osmo_sockaddr_to_str(remote);
406 osmo_identifier_sanitize_buf(sockaddr_str, NULL, '_');
407 snprintf(idbuf, sizeof(idbuf), "%s-NSE%05u-remote-%s", gprs_ns2_lltype_str(nse->ll),
408 nse->nsei, sockaddr_str);
409 nsvc = ns2_vc_alloc(bind, nse, true, vc_mode, idbuf);
Alexander Couzensc06aa712020-11-18 23:56:45 +0100410 if (!nsvc)
411 return NULL;
412
Alexander Couzens6a161492020-07-12 13:45:50 +0200413 nsvc->priv = talloc_zero(bind, struct priv_vc);
414 if (!nsvc->priv) {
415 gprs_ns2_free_nsvc(nsvc);
416 return NULL;
417 }
418
419 priv = nsvc->priv;
420 priv->remote = *remote;
421
Alexander Couzens6a161492020-07-12 13:45:50 +0200422 return nsvc;
423}
424
Alexander Couzens979f5f52020-10-11 21:01:48 +0200425/*! Return the socket address of the local peer of a NS-VC.
426 * \param[in] nsvc NS-VC whose local peer we want to know
427 * \return address of the local peer; NULL in case of error */
428const struct osmo_sockaddr *gprs_ns2_ip_vc_local(const struct gprs_ns2_vc *nsvc)
429{
430 struct priv_bind *priv;
431
Alexander Couzens979f5f52020-10-11 21:01:48 +0200432 if (nsvc->bind->driver != &vc_driver_ip)
433 return NULL;
434
435 priv = nsvc->bind->priv;
436 return &priv->addr;
437}
438
Harald Welte5bef2cc2020-09-18 22:33:24 +0200439/*! Return the socket address of the remote peer of a NS-VC.
440 * \param[in] nsvc NS-VC whose remote peer we want to know
441 * \return address of the remote peer; NULL in case of error */
Alexander Couzensd33512b2020-10-11 21:42:11 +0200442const struct osmo_sockaddr *gprs_ns2_ip_vc_remote(const struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +0200443{
444 struct priv_vc *priv;
445
Alexander Couzensaac90162020-11-19 02:44:04 +0100446 if (nsvc->bind->driver != &vc_driver_ip)
Alexander Couzens6a161492020-07-12 13:45:50 +0200447 return NULL;
448
449 priv = nsvc->priv;
450 return &priv->remote;
451}
452
Alexander Couzensd420ea92020-10-12 01:11:05 +0200453/*! Compare the NS-VC with the given parameter
454 * \param[in] nsvc NS-VC to compare with
455 * \param[in] local The local address
456 * \param[in] remote The remote address
457 * \param[in] nsvci NS-VCI will only be used if the NS-VC in BLOCKRESET mode otherwise NS-VCI isn't applicable.
458 * \return true if the NS-VC has the same properties as given
459 */
460bool gprs_ns2_ip_vc_equal(const struct gprs_ns2_vc *nsvc,
461 const struct osmo_sockaddr *local,
462 const struct osmo_sockaddr *remote,
463 uint16_t nsvci)
464{
465 struct priv_vc *vpriv;
466 struct priv_bind *bpriv;
467
Alexander Couzensaac90162020-11-19 02:44:04 +0100468 if (nsvc->bind->driver != &vc_driver_ip)
Alexander Couzensd420ea92020-10-12 01:11:05 +0200469 return false;
470
471 vpriv = nsvc->priv;
472 bpriv = nsvc->bind->priv;
473
474 if (osmo_sockaddr_cmp(local, &bpriv->addr))
475 return false;
476
477 if (osmo_sockaddr_cmp(remote, &vpriv->remote))
478 return false;
479
Alexander Couzens138b96f2021-01-25 16:23:29 +0100480 if (nsvc->mode == GPRS_NS2_VC_MODE_BLOCKRESET)
Alexander Couzensd420ea92020-10-12 01:11:05 +0200481 if (nsvc->nsvci != nsvci)
482 return false;
483
484 return true;
485}
486
Harald Welte5bef2cc2020-09-18 22:33:24 +0200487/*! Return the locally bound socket address of the bind.
488 * \param[in] bind The bind whose local address we want to know
489 * \return address of the local bind */
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200490const struct osmo_sockaddr *gprs_ns2_ip_bind_sockaddr(struct gprs_ns2_vc_bind *bind)
Alexander Couzens6a161492020-07-12 13:45:50 +0200491{
492 struct priv_bind *priv;
Alexander Couzens55bc8692021-01-18 18:39:57 +0100493 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
Alexander Couzens6a161492020-07-12 13:45:50 +0200494
495 priv = bind->priv;
496 return &priv->addr;
497}
498
Harald Welte5bef2cc2020-09-18 22:33:24 +0200499/*! Is the given bind an IP bind? */
Alexander Couzens6a161492020-07-12 13:45:50 +0200500int gprs_ns2_is_ip_bind(struct gprs_ns2_vc_bind *bind)
501{
502 return (bind->driver == &vc_driver_ip);
503}
504
Harald Welte5bef2cc2020-09-18 22:33:24 +0200505/*! Set the DSCP (TOS) bit value of the given bind. */
Alexander Couzens6a161492020-07-12 13:45:50 +0200506int gprs_ns2_ip_bind_set_dscp(struct gprs_ns2_vc_bind *bind, int dscp)
507{
508 struct priv_bind *priv;
509 int rc = 0;
510
Harald Welte628f5342021-04-28 19:41:07 +0200511 if (dscp < 0 || dscp > 63)
512 return -EINVAL;
513
Alexander Couzens55bc8692021-01-18 18:39:57 +0100514 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
Alexander Couzens6a161492020-07-12 13:45:50 +0200515 priv = bind->priv;
516
517 if (dscp != priv->dscp) {
518 priv->dscp = dscp;
519
Harald Welte628f5342021-04-28 19:41:07 +0200520 rc = osmo_sock_set_dscp(priv->fd.fd, dscp);
Harald Weltef2949742021-01-20 14:54:14 +0100521 if (rc < 0) {
Harald Welte628f5342021-04-28 19:41:07 +0200522 LOGBIND(bind, LOGL_ERROR, "Failed to set the DSCP to %u with ret(%d) errno(%d)\n",
Harald Weltef2949742021-01-20 14:54:14 +0100523 dscp, rc, errno);
524 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200525 }
526
527 return rc;
528}
Alexander Couzense769f522020-12-07 07:37:07 +0100529
Harald Welted99e4ee2021-04-28 19:57:12 +0200530/*! Set the socket priority of the given bind. */
531int gprs_ns2_ip_bind_set_priority(struct gprs_ns2_vc_bind *bind, uint8_t priority)
532{
533 struct priv_bind *priv;
534 int rc = 0;
535
536 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
537 priv = bind->priv;
538
539 if (priority != priv->priority) {
540 priv->priority = priority;
541
542 rc = osmo_sock_set_priority(priv->fd.fd, priority);
543 if (rc < 0) {
544 LOGBIND(bind, LOGL_ERROR, "Failed to set the priority to %u with ret(%d) errno(%d)\n",
545 priority, rc, errno);
546 }
547 }
548
549 return rc;
550}
551
552
Alexander Couzense769f522020-12-07 07:37:07 +0100553/*! Count UDP binds compatible with remote */
554int ns2_ip_count_bind(struct gprs_ns2_inst *nsi, struct osmo_sockaddr *remote)
555{
556 struct gprs_ns2_vc_bind *bind;
557 const struct osmo_sockaddr *sa;
558 int count = 0;
559
560 llist_for_each_entry(bind, &nsi->binding, list) {
561 if (!gprs_ns2_is_ip_bind(bind))
562 continue;
563
564 sa = gprs_ns2_ip_bind_sockaddr(bind);
565 if (!sa)
566 continue;
567
568 if (sa->u.sa.sa_family == remote->u.sa.sa_family)
569 count++;
570 }
571
572 return count;
573}
574
575/* return the matching bind by index */
576struct gprs_ns2_vc_bind *ns2_ip_get_bind_by_index(struct gprs_ns2_inst *nsi,
577 struct osmo_sockaddr *remote,
578 int index)
579{
580 struct gprs_ns2_vc_bind *bind;
581 const struct osmo_sockaddr *sa;
582 int i = 0;
583
584 llist_for_each_entry(bind, &nsi->binding, list) {
585 if (!gprs_ns2_is_ip_bind(bind))
586 continue;
587
588 sa = gprs_ns2_ip_bind_sockaddr(bind);
589 if (!sa)
590 continue;
591
592 if (sa->u.sa.sa_family == remote->u.sa.sa_family) {
593 if (index == i)
594 return bind;
595 i++;
596 }
597 }
598
599 return NULL;
600}
Alexander Couzensc4704762021-02-08 23:13:12 +0100601
602/*! set the signalling and data weight for this bind
603 * \param[in] bind
604 * \param[in] signalling the signalling weight
605 * \param[in] data the data weight
606 */
607void gprs_ns2_ip_bind_set_sns_weight(struct gprs_ns2_vc_bind *bind, uint8_t signalling, uint8_t data)
608{
609 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
610 bind->sns_sig_weight = signalling;
611 bind->sns_data_weight = data;
612 ns2_sns_update_weights(bind);
613}