blob: 30816802d242070b1d42efc7a32c4be25c30f3cc [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
Alexander Couzens55bc8692021-01-18 18:39:57 +010066 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
67
Alexander Couzens6a161492020-07-12 13:45:50 +020068 priv = bind->priv;
69
70 osmo_fd_close(&priv->fd);
71 talloc_free(priv);
72}
73
74static void free_vc(struct gprs_ns2_vc *nsvc)
75{
Alexander Couzensea377242021-01-17 16:51:55 +010076 if (!nsvc)
77 return;
78
Alexander Couzens6a161492020-07-12 13:45:50 +020079 if (!nsvc->priv)
80 return;
81
Alexander Couzens55bc8692021-01-18 18:39:57 +010082 OSMO_ASSERT(gprs_ns2_is_ip_bind(nsvc->bind));
Alexander Couzens6a161492020-07-12 13:45:50 +020083 talloc_free(nsvc->priv);
84 nsvc->priv = NULL;
85}
86
Alexander Couzens22f34712020-10-02 02:34:39 +020087static void dump_vty(const struct gprs_ns2_vc_bind *bind,
88 struct vty *vty, bool _stats)
89{
90 struct priv_bind *priv;
91 struct gprs_ns2_vc *nsvc;
92 struct osmo_sockaddr_str sockstr = {};
93 unsigned long nsvcs = 0;
94
95 if (!bind)
96 return;
97
98 priv = bind->priv;
99 if (osmo_sockaddr_str_from_sockaddr(&sockstr, &priv->addr.u.sas))
100 strcpy(sockstr.ip, "invalid");
101
102 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
103 nsvcs++;
104 }
105
Harald Welte1e72df02020-12-01 18:20:25 +0100106 vty_out(vty, "UDP bind: %s:%d DSCP: %d%s", sockstr.ip, sockstr.port, priv->dscp, VTY_NEWLINE);
Alexander Couzensc4704762021-02-08 23:13:12 +0100107 vty_out(vty, " IP-SNS signalling weight: %u data weight: %u%s",
108 bind->sns_sig_weight, bind->sns_data_weight, VTY_NEWLINE);
Alexander Couzens22f34712020-10-02 02:34:39 +0200109 vty_out(vty, " %lu NS-VC: %s", nsvcs, VTY_NEWLINE);
110
111 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
Harald Welte96ec84a2020-12-01 17:56:05 +0100112 vty_out(vty, " NSVCI %05u: %s%s", nsvc->nsvci, gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens22f34712020-10-02 02:34:39 +0200113 }
114}
115
116
Harald Welte5bef2cc2020-09-18 22:33:24 +0200117/*! Find a NS-VC by its remote socket address.
118 * \param[in] bind in which to search
119 * \param[in] saddr remote peer socket adddress to search
Alexander Couzens38b19e82020-09-23 23:56:37 +0200120 * \returns NS-VC matching sockaddr; NULL if none found */
Vadim Yanitskiya07f25e2020-10-09 21:47:01 +0700121struct gprs_ns2_vc *gprs_ns2_nsvc_by_sockaddr_bind(struct gprs_ns2_vc_bind *bind,
122 const struct osmo_sockaddr *saddr)
Alexander Couzens6a161492020-07-12 13:45:50 +0200123{
124 struct gprs_ns2_vc *nsvc;
125 struct priv_vc *vcpriv;
126
Alexander Couzens55bc8692021-01-18 18:39:57 +0100127 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
128
Alexander Couzens6a161492020-07-12 13:45:50 +0200129 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
130 vcpriv = nsvc->priv;
131 if (vcpriv->remote.u.sa.sa_family != saddr->u.sa.sa_family)
132 continue;
133 if (osmo_sockaddr_cmp(&vcpriv->remote, saddr))
134 continue;
135
Alexander Couzens38b19e82020-09-23 23:56:37 +0200136 return nsvc;
Alexander Couzens6a161492020-07-12 13:45:50 +0200137 }
138
Alexander Couzens38b19e82020-09-23 23:56:37 +0200139 return NULL;
Alexander Couzens6a161492020-07-12 13:45:50 +0200140}
141
142static inline int nsip_sendmsg(struct gprs_ns2_vc_bind *bind,
143 struct msgb *msg,
144 struct osmo_sockaddr *dest)
145{
146 int rc;
147 struct priv_bind *priv = bind->priv;
148
149 rc = sendto(priv->fd.fd, msg->data, msg->len, 0,
150 &dest->u.sa, sizeof(*dest));
151
152 msgb_free(msg);
153
154 return rc;
155}
156
Harald Welte5bef2cc2020-09-18 22:33:24 +0200157/*! send the msg and free it afterwards.
158 * \param nsvc NS-VC on which the message shall be sent
159 * \param msg message to be sent
160 * \return number of bytes transmitted; negative on error */
Alexander Couzens6a161492020-07-12 13:45:50 +0200161static int nsip_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
162{
163 int rc;
164 struct gprs_ns2_vc_bind *bind = nsvc->bind;
165 struct priv_vc *priv = nsvc->priv;
166
167 rc = nsip_sendmsg(bind, msg, &priv->remote);
168
169 return rc;
170}
171
172/* Read a single NS-over-IP message */
Harald Weltef2949742021-01-20 14:54:14 +0100173static struct msgb *read_nsip_msg(struct osmo_fd *bfd, int *error, struct osmo_sockaddr *saddr,
174 const struct gprs_ns2_vc_bind *bind)
Alexander Couzens6a161492020-07-12 13:45:50 +0200175{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100176 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200177 int ret = 0;
178 socklen_t saddr_len = sizeof(*saddr);
179
180 if (!msg) {
181 *error = -ENOMEM;
182 return NULL;
183 }
184
185 ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE - NS_ALLOC_HEADROOM, 0,
186 &saddr->u.sa, &saddr_len);
187 if (ret < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100188 LOGBIND(bind, LOGL_ERROR, "recv error %s during NSIP recvfrom %s\n",
189 strerror(errno), osmo_sock_get_name2(bfd->fd));
Alexander Couzens6a161492020-07-12 13:45:50 +0200190 msgb_free(msg);
191 *error = ret;
192 return NULL;
193 } else if (ret == 0) {
194 msgb_free(msg);
195 *error = ret;
196 return NULL;
197 }
198
199 msg->l2h = msg->data;
200 msgb_put(msg, ret);
201
202 return msg;
203}
204
205static struct priv_vc *ns2_driver_alloc_vc(struct gprs_ns2_vc_bind *bind, struct gprs_ns2_vc *nsvc, struct osmo_sockaddr *remote)
206{
207 struct priv_vc *priv = talloc_zero(bind, struct priv_vc);
208 if (!priv)
209 return NULL;
210
211 nsvc->priv = priv;
212 priv->remote = *remote;
213
214 return priv;
215}
216
217static int handle_nsip_read(struct osmo_fd *bfd)
218{
Alexander Couzenscce88282020-10-26 00:25:50 +0100219 int rc = 0;
Alexander Couzens6a161492020-07-12 13:45:50 +0200220 int error = 0;
221 struct gprs_ns2_vc_bind *bind = bfd->data;
222 struct osmo_sockaddr saddr;
223 struct gprs_ns2_vc *nsvc;
Harald Weltef2949742021-01-20 14:54:14 +0100224 struct msgb *msg = read_nsip_msg(bfd, &error, &saddr, bind);
Alexander Couzens6a161492020-07-12 13:45:50 +0200225 struct msgb *reject;
226
227 if (!msg)
228 return -EINVAL;
229
230 /* check if a vc is available */
Alexander Couzens38b19e82020-09-23 23:56:37 +0200231 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &saddr);
232 if (!nsvc) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200233 /* VC not found */
234 rc = ns2_create_vc(bind, msg, "newconnection", &reject, &nsvc);
235 switch (rc) {
Alexander Couzensba5a9922021-01-25 16:03:23 +0100236 case NS2_CS_FOUND:
Alexander Couzens6a161492020-07-12 13:45:50 +0200237 break;
Alexander Couzensba5a9922021-01-25 16:03:23 +0100238 case NS2_CS_ERROR:
239 case NS2_CS_SKIPPED:
Alexander Couzens6a161492020-07-12 13:45:50 +0200240 rc = 0;
Alexander Couzens13010122020-09-24 00:54:51 +0200241 goto out;
Alexander Couzensba5a9922021-01-25 16:03:23 +0100242 case NS2_CS_REJECTED:
Alexander Couzens6a161492020-07-12 13:45:50 +0200243 /* nsip_sendmsg will free reject */
Alexander Couzens772ca612020-09-24 16:19:02 +0200244 rc = nsip_sendmsg(bind, reject, &saddr);
245 goto out;
Alexander Couzensba5a9922021-01-25 16:03:23 +0100246 case NS2_CS_CREATED:
Alexander Couzens6a161492020-07-12 13:45:50 +0200247 ns2_driver_alloc_vc(bind, nsvc, &saddr);
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100248 ns2_vc_fsm_start(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200249 break;
250 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200251 }
252
Alexander Couzenscce88282020-10-26 00:25:50 +0100253 return ns2_recv_vc(nsvc, msg);
254
Alexander Couzens13010122020-09-24 00:54:51 +0200255out:
Alexander Couzens6a161492020-07-12 13:45:50 +0200256 msgb_free(msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200257 return rc;
258}
259
260static int handle_nsip_write(struct osmo_fd *bfd)
261{
262 /* FIXME: actually send the data here instead of nsip_sendmsg() */
263 return -EIO;
264}
265
266static int nsip_fd_cb(struct osmo_fd *bfd, unsigned int what)
267{
268 int rc = 0;
269
270 if (what & OSMO_FD_READ)
271 rc = handle_nsip_read(bfd);
272 if (what & OSMO_FD_WRITE)
273 rc = handle_nsip_write(bfd);
274
275 return rc;
276}
277
Alexander Couzens4f608452020-10-11 18:41:24 +0200278/*! Find NS bind for a given socket address
279 * \param[in] nsi NS instance
280 * \param[in] sockaddr socket address to search for
281 * \return
282 */
283struct gprs_ns2_vc_bind *gprs_ns2_ip_bind_by_sockaddr(struct gprs_ns2_inst *nsi,
284 const struct osmo_sockaddr *sockaddr)
285{
286 struct gprs_ns2_vc_bind *bind;
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200287 const struct osmo_sockaddr *local;
Alexander Couzens4f608452020-10-11 18:41:24 +0200288
289 OSMO_ASSERT(nsi);
290 OSMO_ASSERT(sockaddr);
291
292 llist_for_each_entry(bind, &nsi->binding, list) {
293 if (!gprs_ns2_is_ip_bind(bind))
294 continue;
295
296 local = gprs_ns2_ip_bind_sockaddr(bind);
297 if (!osmo_sockaddr_cmp(sockaddr, local))
298 return bind;
299 }
300
301 return NULL;
302}
303
Harald Welte5bef2cc2020-09-18 22:33:24 +0200304/*! Bind to an IPv4/IPv6 address
305 * \param[in] nsi NS Instance in which to create the NSVC
306 * \param[in] local the local address to bind to
307 * \param[in] dscp the DSCP/TOS bits used for transmitted data
Alexander Couzensc80a8742021-02-03 11:27:52 +0100308 * \param[out] result pointer to the created bind or if a bind with the name exists return the bind.
309 * \return 0 on success; negative on error. -EALREADY returned in case a bind with the name exists */
Alexander Couzens6a161492020-07-12 13:45:50 +0200310int gprs_ns2_ip_bind(struct gprs_ns2_inst *nsi,
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100311 const char *name,
Vadim Yanitskiya07f25e2020-10-09 21:47:01 +0700312 const struct osmo_sockaddr *local,
Alexander Couzens6a161492020-07-12 13:45:50 +0200313 int dscp,
314 struct gprs_ns2_vc_bind **result)
315{
Alexander Couzens6090b1d2020-10-11 18:41:37 +0200316 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6a161492020-07-12 13:45:50 +0200317 struct priv_bind *priv;
318 int rc;
319
Harald Weltec3aa8f92021-01-31 11:41:34 +0100320 if (local->u.sa.sa_family != AF_INET && local->u.sa.sa_family != AF_INET6)
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100321 return -EINVAL;
322
Alexander Couzens6090b1d2020-10-11 18:41:37 +0200323 bind = gprs_ns2_ip_bind_by_sockaddr(nsi, local);
324 if (bind) {
Alexander Couzensc80a8742021-02-03 11:27:52 +0100325 if (result)
326 *result = bind;
Alexander Couzens6090b1d2020-10-11 18:41:37 +0200327 return -EBUSY;
328 }
329
Harald Weltec3aa8f92021-01-31 11:41:34 +0100330 rc = ns2_bind_alloc(nsi, name, &bind);
331 if (rc < 0)
332 return rc;
Alexander Couzens6a161492020-07-12 13:45:50 +0200333
334 bind->driver = &vc_driver_ip;
Alexander Couzensaac90162020-11-19 02:44:04 +0100335 bind->ll = GPRS_NS2_LL_UDP;
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100336 /* expect 100 mbit at least.
337 * TODO: ask the network layer about the speed. But would require
338 * notification on change. */
339 bind->transfer_capability = 100;
Alexander Couzens6a161492020-07-12 13:45:50 +0200340 bind->send_vc = nsip_vc_sendmsg;
341 bind->free_vc = free_vc;
Alexander Couzens22f34712020-10-02 02:34:39 +0200342 bind->dump_vty = dump_vty;
Alexander Couzens6a161492020-07-12 13:45:50 +0200343
344 priv = bind->priv = talloc_zero(bind, struct priv_bind);
345 if (!priv) {
Harald Weltec3aa8f92021-01-31 11:41:34 +0100346 gprs_ns2_free_bind(bind);
Harald Weltebdfb8b92021-01-31 11:44:57 +0100347 return -ENOMEM;
Alexander Couzens6a161492020-07-12 13:45:50 +0200348 }
349 priv->fd.cb = nsip_fd_cb;
350 priv->fd.data = bind;
351 priv->addr = *local;
Alexander Couzens6a161492020-07-12 13:45:50 +0200352
Alexander Couzens6a161492020-07-12 13:45:50 +0200353 rc = osmo_sock_init_osa_ofd(&priv->fd, SOCK_DGRAM, IPPROTO_UDP,
354 local, NULL,
355 OSMO_SOCK_F_BIND);
356 if (rc < 0) {
Harald Weltec3aa8f92021-01-31 11:41:34 +0100357 gprs_ns2_free_bind(bind);
Alexander Couzens6a161492020-07-12 13:45:50 +0200358 return rc;
359 }
360
361 if (dscp > 0) {
362 priv->dscp = dscp;
363
364 rc = setsockopt(priv->fd.fd, IPPROTO_IP, IP_TOS,
365 &dscp, sizeof(dscp));
366 if (rc < 0)
Harald Weltef2949742021-01-20 14:54:14 +0100367 LOGBIND(bind, LOGL_ERROR, "Failed to set the DSCP to %d with ret(%d) errno(%d)\n",
Alexander Couzens6a161492020-07-12 13:45:50 +0200368 dscp, rc, errno);
369 }
370
Alexander Couzens4f1128f2021-01-20 17:42:48 +0100371 /* IPv4: max fragmented payload can be (13 bit) * 8 byte => 65535.
372 * IPv6: max payload can be 65535 (RFC 2460).
373 * UDP header = 8 byte */
374 bind->mtu = 65535 - 8;
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 Couzens8dfc24c2021-01-25 16:09:23 +0100386struct gprs_ns2_vc *ns2_ip_bind_connect(struct gprs_ns2_vc_bind *bind,
387 struct gprs_ns2_nse *nse,
388 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;
Harald Welte603f4042020-11-29 17:39:19 +0100393 char *sockaddr_str;
394 char idbuf[64];
Alexander Couzens6a161492020-07-12 13:45:50 +0200395
Alexander Couzens55bc8692021-01-18 18:39:57 +0100396 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
397
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100398 vc_mode = ns2_dialect_to_vc_mode(nse->dialect);
Alexander Couzensd923cff2020-12-01 01:03:52 +0100399 if ((int) vc_mode == -1) {
Harald Weltef2949742021-01-20 14:54:14 +0100400 LOGNSE(nse, LOGL_ERROR, "Can not derive vc mode from dialect %d. Maybe libosmocore is too old.\n",
401 nse->dialect);
Alexander Couzensd923cff2020-12-01 01:03:52 +0100402 return NULL;
403 }
404
Alexander Couzens7bb39e32021-02-16 23:06:53 +0100405 /* duplicate */
406 if (gprs_ns2_nsvc_by_sockaddr_bind(bind, remote))
407 return NULL;
408
Harald Welte603f4042020-11-29 17:39:19 +0100409 sockaddr_str = (char *)osmo_sockaddr_to_str(remote);
410 osmo_identifier_sanitize_buf(sockaddr_str, NULL, '_');
411 snprintf(idbuf, sizeof(idbuf), "%s-NSE%05u-remote-%s", gprs_ns2_lltype_str(nse->ll),
412 nse->nsei, sockaddr_str);
413 nsvc = ns2_vc_alloc(bind, nse, true, vc_mode, idbuf);
Alexander Couzensc06aa712020-11-18 23:56:45 +0100414 if (!nsvc)
415 return NULL;
416
Alexander Couzens6a161492020-07-12 13:45:50 +0200417 nsvc->priv = talloc_zero(bind, struct priv_vc);
418 if (!nsvc->priv) {
419 gprs_ns2_free_nsvc(nsvc);
420 return NULL;
421 }
422
423 priv = nsvc->priv;
424 priv->remote = *remote;
425
Alexander Couzens6a161492020-07-12 13:45:50 +0200426 return nsvc;
427}
428
Alexander Couzens979f5f52020-10-11 21:01:48 +0200429/*! Return the socket address of the local peer of a NS-VC.
430 * \param[in] nsvc NS-VC whose local peer we want to know
431 * \return address of the local peer; NULL in case of error */
432const struct osmo_sockaddr *gprs_ns2_ip_vc_local(const struct gprs_ns2_vc *nsvc)
433{
434 struct priv_bind *priv;
435
Alexander Couzens979f5f52020-10-11 21:01:48 +0200436 if (nsvc->bind->driver != &vc_driver_ip)
437 return NULL;
438
439 priv = nsvc->bind->priv;
440 return &priv->addr;
441}
442
Harald Welte5bef2cc2020-09-18 22:33:24 +0200443/*! Return the socket address of the remote peer of a NS-VC.
444 * \param[in] nsvc NS-VC whose remote peer we want to know
445 * \return address of the remote peer; NULL in case of error */
Alexander Couzensd33512b2020-10-11 21:42:11 +0200446const struct osmo_sockaddr *gprs_ns2_ip_vc_remote(const struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +0200447{
448 struct priv_vc *priv;
449
Alexander Couzensaac90162020-11-19 02:44:04 +0100450 if (nsvc->bind->driver != &vc_driver_ip)
Alexander Couzens6a161492020-07-12 13:45:50 +0200451 return NULL;
452
453 priv = nsvc->priv;
454 return &priv->remote;
455}
456
Alexander Couzensd420ea92020-10-12 01:11:05 +0200457/*! Compare the NS-VC with the given parameter
458 * \param[in] nsvc NS-VC to compare with
459 * \param[in] local The local address
460 * \param[in] remote The remote address
461 * \param[in] nsvci NS-VCI will only be used if the NS-VC in BLOCKRESET mode otherwise NS-VCI isn't applicable.
462 * \return true if the NS-VC has the same properties as given
463 */
464bool gprs_ns2_ip_vc_equal(const struct gprs_ns2_vc *nsvc,
465 const struct osmo_sockaddr *local,
466 const struct osmo_sockaddr *remote,
467 uint16_t nsvci)
468{
469 struct priv_vc *vpriv;
470 struct priv_bind *bpriv;
471
Alexander Couzensaac90162020-11-19 02:44:04 +0100472 if (nsvc->bind->driver != &vc_driver_ip)
Alexander Couzensd420ea92020-10-12 01:11:05 +0200473 return false;
474
475 vpriv = nsvc->priv;
476 bpriv = nsvc->bind->priv;
477
478 if (osmo_sockaddr_cmp(local, &bpriv->addr))
479 return false;
480
481 if (osmo_sockaddr_cmp(remote, &vpriv->remote))
482 return false;
483
Alexander Couzens138b96f2021-01-25 16:23:29 +0100484 if (nsvc->mode == GPRS_NS2_VC_MODE_BLOCKRESET)
Alexander Couzensd420ea92020-10-12 01:11:05 +0200485 if (nsvc->nsvci != nsvci)
486 return false;
487
488 return true;
489}
490
Harald Welte5bef2cc2020-09-18 22:33:24 +0200491/*! Return the locally bound socket address of the bind.
492 * \param[in] bind The bind whose local address we want to know
493 * \return address of the local bind */
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200494const struct osmo_sockaddr *gprs_ns2_ip_bind_sockaddr(struct gprs_ns2_vc_bind *bind)
Alexander Couzens6a161492020-07-12 13:45:50 +0200495{
496 struct priv_bind *priv;
Alexander Couzens55bc8692021-01-18 18:39:57 +0100497 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
Alexander Couzens6a161492020-07-12 13:45:50 +0200498
499 priv = bind->priv;
500 return &priv->addr;
501}
502
Harald Welte5bef2cc2020-09-18 22:33:24 +0200503/*! Is the given bind an IP bind? */
Alexander Couzens6a161492020-07-12 13:45:50 +0200504int gprs_ns2_is_ip_bind(struct gprs_ns2_vc_bind *bind)
505{
506 return (bind->driver == &vc_driver_ip);
507}
508
Harald Welte5bef2cc2020-09-18 22:33:24 +0200509/*! Set the DSCP (TOS) bit value of the given bind. */
Alexander Couzens6a161492020-07-12 13:45:50 +0200510int gprs_ns2_ip_bind_set_dscp(struct gprs_ns2_vc_bind *bind, int dscp)
511{
512 struct priv_bind *priv;
513 int rc = 0;
514
Alexander Couzens55bc8692021-01-18 18:39:57 +0100515 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
Alexander Couzens6a161492020-07-12 13:45:50 +0200516 priv = bind->priv;
517
518 if (dscp != priv->dscp) {
519 priv->dscp = dscp;
520
521 rc = setsockopt(priv->fd.fd, IPPROTO_IP, IP_TOS,
522 &dscp, sizeof(dscp));
Harald Weltef2949742021-01-20 14:54:14 +0100523 if (rc < 0) {
524 LOGBIND(bind, LOGL_ERROR, "Failed to set the DSCP to %d with ret(%d) errno(%d)\n",
525 dscp, rc, errno);
526 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200527 }
528
529 return rc;
530}
Alexander Couzense769f522020-12-07 07:37:07 +0100531
532/*! Count UDP binds compatible with remote */
533int ns2_ip_count_bind(struct gprs_ns2_inst *nsi, struct osmo_sockaddr *remote)
534{
535 struct gprs_ns2_vc_bind *bind;
536 const struct osmo_sockaddr *sa;
537 int count = 0;
538
539 llist_for_each_entry(bind, &nsi->binding, list) {
540 if (!gprs_ns2_is_ip_bind(bind))
541 continue;
542
543 sa = gprs_ns2_ip_bind_sockaddr(bind);
544 if (!sa)
545 continue;
546
547 if (sa->u.sa.sa_family == remote->u.sa.sa_family)
548 count++;
549 }
550
551 return count;
552}
553
554/* return the matching bind by index */
555struct gprs_ns2_vc_bind *ns2_ip_get_bind_by_index(struct gprs_ns2_inst *nsi,
556 struct osmo_sockaddr *remote,
557 int index)
558{
559 struct gprs_ns2_vc_bind *bind;
560 const struct osmo_sockaddr *sa;
561 int i = 0;
562
563 llist_for_each_entry(bind, &nsi->binding, list) {
564 if (!gprs_ns2_is_ip_bind(bind))
565 continue;
566
567 sa = gprs_ns2_ip_bind_sockaddr(bind);
568 if (!sa)
569 continue;
570
571 if (sa->u.sa.sa_family == remote->u.sa.sa_family) {
572 if (index == i)
573 return bind;
574 i++;
575 }
576 }
577
578 return NULL;
579}
Alexander Couzensc4704762021-02-08 23:13:12 +0100580
581/*! set the signalling and data weight for this bind
582 * \param[in] bind
583 * \param[in] signalling the signalling weight
584 * \param[in] data the data weight
585 */
586void gprs_ns2_ip_bind_set_sns_weight(struct gprs_ns2_vc_bind *bind, uint8_t signalling, uint8_t data)
587{
588 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
589 bind->sns_sig_weight = signalling;
590 bind->sns_data_weight = data;
591 ns2_sns_update_weights(bind);
592}