blob: 2a335c1169ce7ec2f00c0369d2e179d0051f77c0 [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 Couzens22f34712020-10-02 02:34:39 +0200107 vty_out(vty, " %lu NS-VC: %s", nsvcs, VTY_NEWLINE);
108
109 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
Harald Welte96ec84a2020-12-01 17:56:05 +0100110 vty_out(vty, " NSVCI %05u: %s%s", nsvc->nsvci, gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens22f34712020-10-02 02:34:39 +0200111 }
112}
113
114
Harald Welte5bef2cc2020-09-18 22:33:24 +0200115/*! Find a NS-VC by its remote socket address.
116 * \param[in] bind in which to search
117 * \param[in] saddr remote peer socket adddress to search
Alexander Couzens38b19e82020-09-23 23:56:37 +0200118 * \returns NS-VC matching sockaddr; NULL if none found */
Vadim Yanitskiya07f25e2020-10-09 21:47:01 +0700119struct gprs_ns2_vc *gprs_ns2_nsvc_by_sockaddr_bind(struct gprs_ns2_vc_bind *bind,
120 const struct osmo_sockaddr *saddr)
Alexander Couzens6a161492020-07-12 13:45:50 +0200121{
122 struct gprs_ns2_vc *nsvc;
123 struct priv_vc *vcpriv;
124
Alexander Couzens55bc8692021-01-18 18:39:57 +0100125 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
126
Alexander Couzens6a161492020-07-12 13:45:50 +0200127 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
128 vcpriv = nsvc->priv;
129 if (vcpriv->remote.u.sa.sa_family != saddr->u.sa.sa_family)
130 continue;
131 if (osmo_sockaddr_cmp(&vcpriv->remote, saddr))
132 continue;
133
Alexander Couzens38b19e82020-09-23 23:56:37 +0200134 return nsvc;
Alexander Couzens6a161492020-07-12 13:45:50 +0200135 }
136
Alexander Couzens38b19e82020-09-23 23:56:37 +0200137 return NULL;
Alexander Couzens6a161492020-07-12 13:45:50 +0200138}
139
140static inline int nsip_sendmsg(struct gprs_ns2_vc_bind *bind,
141 struct msgb *msg,
142 struct osmo_sockaddr *dest)
143{
144 int rc;
145 struct priv_bind *priv = bind->priv;
146
147 rc = sendto(priv->fd.fd, msg->data, msg->len, 0,
148 &dest->u.sa, sizeof(*dest));
149
150 msgb_free(msg);
151
152 return rc;
153}
154
Harald Welte5bef2cc2020-09-18 22:33:24 +0200155/*! send the msg and free it afterwards.
156 * \param nsvc NS-VC on which the message shall be sent
157 * \param msg message to be sent
158 * \return number of bytes transmitted; negative on error */
Alexander Couzens6a161492020-07-12 13:45:50 +0200159static int nsip_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
160{
161 int rc;
162 struct gprs_ns2_vc_bind *bind = nsvc->bind;
163 struct priv_vc *priv = nsvc->priv;
164
165 rc = nsip_sendmsg(bind, msg, &priv->remote);
166
167 return rc;
168}
169
170/* Read a single NS-over-IP message */
171static struct msgb *read_nsip_msg(struct osmo_fd *bfd, int *error,
172 struct osmo_sockaddr *saddr)
173{
174 struct msgb *msg = gprs_ns2_msgb_alloc();
175 int ret = 0;
176 socklen_t saddr_len = sizeof(*saddr);
177
178 if (!msg) {
179 *error = -ENOMEM;
180 return NULL;
181 }
182
183 ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE - NS_ALLOC_HEADROOM, 0,
184 &saddr->u.sa, &saddr_len);
185 if (ret < 0) {
186 LOGP(DLNS, LOGL_ERROR, "recv error %s during NSIP recvfrom %s\n",
187 strerror(errno), osmo_sock_get_name2(bfd->fd));
188 msgb_free(msg);
189 *error = ret;
190 return NULL;
191 } else if (ret == 0) {
192 msgb_free(msg);
193 *error = ret;
194 return NULL;
195 }
196
197 msg->l2h = msg->data;
198 msgb_put(msg, ret);
199
200 return msg;
201}
202
203static struct priv_vc *ns2_driver_alloc_vc(struct gprs_ns2_vc_bind *bind, struct gprs_ns2_vc *nsvc, struct osmo_sockaddr *remote)
204{
205 struct priv_vc *priv = talloc_zero(bind, struct priv_vc);
206 if (!priv)
207 return NULL;
208
209 nsvc->priv = priv;
210 priv->remote = *remote;
211
212 return priv;
213}
214
215static int handle_nsip_read(struct osmo_fd *bfd)
216{
Alexander Couzenscce88282020-10-26 00:25:50 +0100217 int rc = 0;
Alexander Couzens6a161492020-07-12 13:45:50 +0200218 int error = 0;
219 struct gprs_ns2_vc_bind *bind = bfd->data;
220 struct osmo_sockaddr saddr;
221 struct gprs_ns2_vc *nsvc;
222 struct msgb *msg = read_nsip_msg(bfd, &error, &saddr);
223 struct msgb *reject;
224
225 if (!msg)
226 return -EINVAL;
227
228 /* check if a vc is available */
Alexander Couzens38b19e82020-09-23 23:56:37 +0200229 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &saddr);
230 if (!nsvc) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200231 /* VC not found */
232 rc = ns2_create_vc(bind, msg, "newconnection", &reject, &nsvc);
233 switch (rc) {
234 case GPRS_NS2_CS_FOUND:
Alexander Couzens6a161492020-07-12 13:45:50 +0200235 break;
236 case GPRS_NS2_CS_ERROR:
237 case GPRS_NS2_CS_SKIPPED:
238 rc = 0;
Alexander Couzens13010122020-09-24 00:54:51 +0200239 goto out;
Alexander Couzens6a161492020-07-12 13:45:50 +0200240 case GPRS_NS2_CS_REJECTED:
241 /* nsip_sendmsg will free reject */
Alexander Couzens772ca612020-09-24 16:19:02 +0200242 rc = nsip_sendmsg(bind, reject, &saddr);
243 goto out;
Alexander Couzens6a161492020-07-12 13:45:50 +0200244 case GPRS_NS2_CS_CREATED:
245 ns2_driver_alloc_vc(bind, nsvc, &saddr);
246 gprs_ns2_vc_fsm_start(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200247 break;
248 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200249 }
250
Alexander Couzenscce88282020-10-26 00:25:50 +0100251 return ns2_recv_vc(nsvc, msg);
252
Alexander Couzens13010122020-09-24 00:54:51 +0200253out:
Alexander Couzens6a161492020-07-12 13:45:50 +0200254 msgb_free(msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200255 return rc;
256}
257
258static int handle_nsip_write(struct osmo_fd *bfd)
259{
260 /* FIXME: actually send the data here instead of nsip_sendmsg() */
261 return -EIO;
262}
263
264static int nsip_fd_cb(struct osmo_fd *bfd, unsigned int what)
265{
266 int rc = 0;
267
268 if (what & OSMO_FD_READ)
269 rc = handle_nsip_read(bfd);
270 if (what & OSMO_FD_WRITE)
271 rc = handle_nsip_write(bfd);
272
273 return rc;
274}
275
Alexander Couzens4f608452020-10-11 18:41:24 +0200276/*! Find NS bind for a given socket address
277 * \param[in] nsi NS instance
278 * \param[in] sockaddr socket address to search for
279 * \return
280 */
281struct gprs_ns2_vc_bind *gprs_ns2_ip_bind_by_sockaddr(struct gprs_ns2_inst *nsi,
282 const struct osmo_sockaddr *sockaddr)
283{
284 struct gprs_ns2_vc_bind *bind;
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200285 const struct osmo_sockaddr *local;
Alexander Couzens4f608452020-10-11 18:41:24 +0200286
287 OSMO_ASSERT(nsi);
288 OSMO_ASSERT(sockaddr);
289
290 llist_for_each_entry(bind, &nsi->binding, list) {
291 if (!gprs_ns2_is_ip_bind(bind))
292 continue;
293
294 local = gprs_ns2_ip_bind_sockaddr(bind);
295 if (!osmo_sockaddr_cmp(sockaddr, local))
296 return bind;
297 }
298
299 return NULL;
300}
301
Harald Welte5bef2cc2020-09-18 22:33:24 +0200302/*! Bind to an IPv4/IPv6 address
303 * \param[in] nsi NS Instance in which to create the NSVC
304 * \param[in] local the local address to bind to
305 * \param[in] dscp the DSCP/TOS bits used for transmitted data
306 * \param[out] result if set, returns the bind object
307 * \return 0 on success; negative in case of error */
Alexander Couzens6a161492020-07-12 13:45:50 +0200308int gprs_ns2_ip_bind(struct gprs_ns2_inst *nsi,
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100309 const char *name,
Vadim Yanitskiya07f25e2020-10-09 21:47:01 +0700310 const struct osmo_sockaddr *local,
Alexander Couzens6a161492020-07-12 13:45:50 +0200311 int dscp,
312 struct gprs_ns2_vc_bind **result)
313{
Alexander Couzens6090b1d2020-10-11 18:41:37 +0200314 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6a161492020-07-12 13:45:50 +0200315 struct priv_bind *priv;
316 int rc;
317
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100318 if (!name)
319 return -EINVAL;
320
321 if (gprs_ns2_bind_by_name(nsi, name))
322 return -EALREADY;
323
Alexander Couzens6090b1d2020-10-11 18:41:37 +0200324 bind = gprs_ns2_ip_bind_by_sockaddr(nsi, local);
325 if (bind) {
326 *result = bind;
327 return -EBUSY;
328 }
329
330 bind = talloc_zero(nsi, struct gprs_ns2_vc_bind);
Alexander Couzens6a161492020-07-12 13:45:50 +0200331 if (!bind)
332 return -ENOSPC;
333
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100334 bind->name = talloc_strdup(bind, name);
335 if (!bind->name) {
336 talloc_free(bind);
337 return -ENOSPC;
338 }
339
Alexander Couzens6a161492020-07-12 13:45:50 +0200340 if (local->u.sa.sa_family != AF_INET && local->u.sa.sa_family != AF_INET6) {
341 talloc_free(bind);
342 return -EINVAL;
343 }
344
345 bind->driver = &vc_driver_ip;
Alexander Couzensaac90162020-11-19 02:44:04 +0100346 bind->ll = GPRS_NS2_LL_UDP;
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100347 /* expect 100 mbit at least.
348 * TODO: ask the network layer about the speed. But would require
349 * notification on change. */
350 bind->transfer_capability = 100;
Alexander Couzens6a161492020-07-12 13:45:50 +0200351 bind->send_vc = nsip_vc_sendmsg;
352 bind->free_vc = free_vc;
Alexander Couzens22f34712020-10-02 02:34:39 +0200353 bind->dump_vty = dump_vty;
Alexander Couzens6a161492020-07-12 13:45:50 +0200354 bind->nsi = nsi;
355
356 priv = bind->priv = talloc_zero(bind, struct priv_bind);
357 if (!priv) {
358 talloc_free(bind);
359 return -ENOSPC;
360 }
361 priv->fd.cb = nsip_fd_cb;
362 priv->fd.data = bind;
363 priv->addr = *local;
364 INIT_LLIST_HEAD(&bind->nsvc);
365
Alexander Couzens6a161492020-07-12 13:45:50 +0200366 rc = osmo_sock_init_osa_ofd(&priv->fd, SOCK_DGRAM, IPPROTO_UDP,
367 local, NULL,
368 OSMO_SOCK_F_BIND);
369 if (rc < 0) {
370 talloc_free(priv);
371 talloc_free(bind);
372 return rc;
373 }
374
375 if (dscp > 0) {
376 priv->dscp = dscp;
377
378 rc = setsockopt(priv->fd.fd, IPPROTO_IP, IP_TOS,
379 &dscp, sizeof(dscp));
380 if (rc < 0)
381 LOGP(DLNS, LOGL_ERROR,
382 "Failed to set the DSCP to %d with ret(%d) errno(%d)\n",
383 dscp, rc, errno);
384 }
385
Pau Espin Pedrolaa83d412020-10-09 14:20:13 +0200386 llist_add(&bind->list, &nsi->binding);
Alexander Couzens6a161492020-07-12 13:45:50 +0200387 if (result)
388 *result = bind;
389
390 return 0;
391}
392
Harald Welte5bef2cc2020-09-18 22:33:24 +0200393/*! Create new NS-VC to a given remote address
394 * \param[in] bind the bind we want to connect
395 * \param[in] nse NS entity to be used for the new NS-VC
396 * \param[in] remote remote address to connect to
397 * \return pointer to newly-allocated and connected NS-VC; NULL on error */
Alexander Couzens6a161492020-07-12 13:45:50 +0200398struct gprs_ns2_vc *gprs_ns2_ip_bind_connect(struct gprs_ns2_vc_bind *bind,
399 struct gprs_ns2_nse *nse,
Vadim Yanitskiya07f25e2020-10-09 21:47:01 +0700400 const struct osmo_sockaddr *remote)
Alexander Couzens6a161492020-07-12 13:45:50 +0200401{
402 struct gprs_ns2_vc *nsvc;
403 struct priv_vc *priv;
Alexander Couzensd923cff2020-12-01 01:03:52 +0100404 enum gprs_ns2_vc_mode vc_mode;
Harald Welte603f4042020-11-29 17:39:19 +0100405 char *sockaddr_str;
406 char idbuf[64];
Alexander Couzens6a161492020-07-12 13:45:50 +0200407
Alexander Couzens55bc8692021-01-18 18:39:57 +0100408 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
409
Alexander Couzensd923cff2020-12-01 01:03:52 +0100410 vc_mode = gprs_ns2_dialect_to_vc_mode(nse->dialect);
411 if ((int) vc_mode == -1) {
412 LOGP(DLNS, LOGL_ERROR, "Can not derive vc mode from dialect %d. Maybe libosmocore is too old.\n",
413 nse->dialect);
414 return NULL;
415 }
416
Harald Welte603f4042020-11-29 17:39:19 +0100417 sockaddr_str = (char *)osmo_sockaddr_to_str(remote);
418 osmo_identifier_sanitize_buf(sockaddr_str, NULL, '_');
419 snprintf(idbuf, sizeof(idbuf), "%s-NSE%05u-remote-%s", gprs_ns2_lltype_str(nse->ll),
420 nse->nsei, sockaddr_str);
421 nsvc = ns2_vc_alloc(bind, nse, true, vc_mode, idbuf);
Alexander Couzensc06aa712020-11-18 23:56:45 +0100422 if (!nsvc)
423 return NULL;
424
Alexander Couzens6a161492020-07-12 13:45:50 +0200425 nsvc->priv = talloc_zero(bind, struct priv_vc);
426 if (!nsvc->priv) {
427 gprs_ns2_free_nsvc(nsvc);
428 return NULL;
429 }
430
431 priv = nsvc->priv;
432 priv->remote = *remote;
433
Alexander Couzens6a161492020-07-12 13:45:50 +0200434 return nsvc;
435}
436
Alexander Couzens979f5f52020-10-11 21:01:48 +0200437/*! Return the socket address of the local peer of a NS-VC.
438 * \param[in] nsvc NS-VC whose local peer we want to know
439 * \return address of the local peer; NULL in case of error */
440const struct osmo_sockaddr *gprs_ns2_ip_vc_local(const struct gprs_ns2_vc *nsvc)
441{
442 struct priv_bind *priv;
443
Alexander Couzens979f5f52020-10-11 21:01:48 +0200444 if (nsvc->bind->driver != &vc_driver_ip)
445 return NULL;
446
447 priv = nsvc->bind->priv;
448 return &priv->addr;
449}
450
Harald Welte5bef2cc2020-09-18 22:33:24 +0200451/*! Return the socket address of the remote peer of a NS-VC.
452 * \param[in] nsvc NS-VC whose remote peer we want to know
453 * \return address of the remote peer; NULL in case of error */
Alexander Couzensd33512b2020-10-11 21:42:11 +0200454const struct osmo_sockaddr *gprs_ns2_ip_vc_remote(const struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +0200455{
456 struct priv_vc *priv;
457
Alexander Couzensaac90162020-11-19 02:44:04 +0100458 if (nsvc->bind->driver != &vc_driver_ip)
Alexander Couzens6a161492020-07-12 13:45:50 +0200459 return NULL;
460
461 priv = nsvc->priv;
462 return &priv->remote;
463}
464
Alexander Couzensd420ea92020-10-12 01:11:05 +0200465/*! Compare the NS-VC with the given parameter
466 * \param[in] nsvc NS-VC to compare with
467 * \param[in] local The local address
468 * \param[in] remote The remote address
469 * \param[in] nsvci NS-VCI will only be used if the NS-VC in BLOCKRESET mode otherwise NS-VCI isn't applicable.
470 * \return true if the NS-VC has the same properties as given
471 */
472bool gprs_ns2_ip_vc_equal(const struct gprs_ns2_vc *nsvc,
473 const struct osmo_sockaddr *local,
474 const struct osmo_sockaddr *remote,
475 uint16_t nsvci)
476{
477 struct priv_vc *vpriv;
478 struct priv_bind *bpriv;
479
Alexander Couzensaac90162020-11-19 02:44:04 +0100480 if (nsvc->bind->driver != &vc_driver_ip)
Alexander Couzensd420ea92020-10-12 01:11:05 +0200481 return false;
482
483 vpriv = nsvc->priv;
484 bpriv = nsvc->bind->priv;
485
486 if (osmo_sockaddr_cmp(local, &bpriv->addr))
487 return false;
488
489 if (osmo_sockaddr_cmp(remote, &vpriv->remote))
490 return false;
491
492 if (nsvc->mode == NS2_VC_MODE_BLOCKRESET)
493 if (nsvc->nsvci != nsvci)
494 return false;
495
496 return true;
497}
498
Harald Welte5bef2cc2020-09-18 22:33:24 +0200499/*! Return the locally bound socket address of the bind.
500 * \param[in] bind The bind whose local address we want to know
501 * \return address of the local bind */
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200502const struct osmo_sockaddr *gprs_ns2_ip_bind_sockaddr(struct gprs_ns2_vc_bind *bind)
Alexander Couzens6a161492020-07-12 13:45:50 +0200503{
504 struct priv_bind *priv;
Alexander Couzens55bc8692021-01-18 18:39:57 +0100505 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
Alexander Couzens6a161492020-07-12 13:45:50 +0200506
507 priv = bind->priv;
508 return &priv->addr;
509}
510
Harald Welte5bef2cc2020-09-18 22:33:24 +0200511/*! Is the given bind an IP bind? */
Alexander Couzens6a161492020-07-12 13:45:50 +0200512int gprs_ns2_is_ip_bind(struct gprs_ns2_vc_bind *bind)
513{
514 return (bind->driver == &vc_driver_ip);
515}
516
Harald Welte5bef2cc2020-09-18 22:33:24 +0200517/*! Set the DSCP (TOS) bit value of the given bind. */
Alexander Couzens6a161492020-07-12 13:45:50 +0200518int gprs_ns2_ip_bind_set_dscp(struct gprs_ns2_vc_bind *bind, int dscp)
519{
520 struct priv_bind *priv;
521 int rc = 0;
522
Alexander Couzens55bc8692021-01-18 18:39:57 +0100523 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
Alexander Couzens6a161492020-07-12 13:45:50 +0200524 priv = bind->priv;
525
526 if (dscp != priv->dscp) {
527 priv->dscp = dscp;
528
529 rc = setsockopt(priv->fd.fd, IPPROTO_IP, IP_TOS,
530 &dscp, sizeof(dscp));
531 if (rc < 0)
532 LOGP(DLNS, LOGL_ERROR,
533 "Failed to set the DSCP to %d with ret(%d) errno(%d)\n",
534 dscp, rc, errno);
535 }
536
537 return rc;
538}
Alexander Couzense769f522020-12-07 07:37:07 +0100539
540/*! Count UDP binds compatible with remote */
541int ns2_ip_count_bind(struct gprs_ns2_inst *nsi, struct osmo_sockaddr *remote)
542{
543 struct gprs_ns2_vc_bind *bind;
544 const struct osmo_sockaddr *sa;
545 int count = 0;
546
547 llist_for_each_entry(bind, &nsi->binding, list) {
548 if (!gprs_ns2_is_ip_bind(bind))
549 continue;
550
551 sa = gprs_ns2_ip_bind_sockaddr(bind);
552 if (!sa)
553 continue;
554
555 if (sa->u.sa.sa_family == remote->u.sa.sa_family)
556 count++;
557 }
558
559 return count;
560}
561
562/* return the matching bind by index */
563struct gprs_ns2_vc_bind *ns2_ip_get_bind_by_index(struct gprs_ns2_inst *nsi,
564 struct osmo_sockaddr *remote,
565 int index)
566{
567 struct gprs_ns2_vc_bind *bind;
568 const struct osmo_sockaddr *sa;
569 int i = 0;
570
571 llist_for_each_entry(bind, &nsi->binding, list) {
572 if (!gprs_ns2_is_ip_bind(bind))
573 continue;
574
575 sa = gprs_ns2_ip_bind_sockaddr(bind);
576 if (!sa)
577 continue;
578
579 if (sa->u.sa.sa_family == remote->u.sa.sa_family) {
580 if (index == i)
581 return bind;
582 i++;
583 }
584 }
585
586 return NULL;
587}