blob: 1037b1978aa3036911f300fd5b366a7b36399279 [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{
76 if (!nsvc->priv)
77 return;
78
Alexander Couzens55bc8692021-01-18 18:39:57 +010079 OSMO_ASSERT(gprs_ns2_is_ip_bind(nsvc->bind));
Alexander Couzens6a161492020-07-12 13:45:50 +020080 talloc_free(nsvc->priv);
81 nsvc->priv = NULL;
82}
83
Alexander Couzens22f34712020-10-02 02:34:39 +020084static void dump_vty(const struct gprs_ns2_vc_bind *bind,
85 struct vty *vty, bool _stats)
86{
87 struct priv_bind *priv;
88 struct gprs_ns2_vc *nsvc;
89 struct osmo_sockaddr_str sockstr = {};
90 unsigned long nsvcs = 0;
91
92 if (!bind)
93 return;
94
95 priv = bind->priv;
96 if (osmo_sockaddr_str_from_sockaddr(&sockstr, &priv->addr.u.sas))
97 strcpy(sockstr.ip, "invalid");
98
99 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
100 nsvcs++;
101 }
102
Harald Welte1e72df02020-12-01 18:20:25 +0100103 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 +0200104 vty_out(vty, " %lu NS-VC: %s", nsvcs, VTY_NEWLINE);
105
106 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
Harald Welte96ec84a2020-12-01 17:56:05 +0100107 vty_out(vty, " NSVCI %05u: %s%s", nsvc->nsvci, gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens22f34712020-10-02 02:34:39 +0200108 }
109}
110
111
Harald Welte5bef2cc2020-09-18 22:33:24 +0200112/*! Find a NS-VC by its remote socket address.
113 * \param[in] bind in which to search
114 * \param[in] saddr remote peer socket adddress to search
Alexander Couzens38b19e82020-09-23 23:56:37 +0200115 * \returns NS-VC matching sockaddr; NULL if none found */
Vadim Yanitskiya07f25e2020-10-09 21:47:01 +0700116struct gprs_ns2_vc *gprs_ns2_nsvc_by_sockaddr_bind(struct gprs_ns2_vc_bind *bind,
117 const struct osmo_sockaddr *saddr)
Alexander Couzens6a161492020-07-12 13:45:50 +0200118{
119 struct gprs_ns2_vc *nsvc;
120 struct priv_vc *vcpriv;
121
Alexander Couzens55bc8692021-01-18 18:39:57 +0100122 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
123
Alexander Couzens6a161492020-07-12 13:45:50 +0200124 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
125 vcpriv = nsvc->priv;
126 if (vcpriv->remote.u.sa.sa_family != saddr->u.sa.sa_family)
127 continue;
128 if (osmo_sockaddr_cmp(&vcpriv->remote, saddr))
129 continue;
130
Alexander Couzens38b19e82020-09-23 23:56:37 +0200131 return nsvc;
Alexander Couzens6a161492020-07-12 13:45:50 +0200132 }
133
Alexander Couzens38b19e82020-09-23 23:56:37 +0200134 return NULL;
Alexander Couzens6a161492020-07-12 13:45:50 +0200135}
136
137static inline int nsip_sendmsg(struct gprs_ns2_vc_bind *bind,
138 struct msgb *msg,
139 struct osmo_sockaddr *dest)
140{
141 int rc;
142 struct priv_bind *priv = bind->priv;
143
144 rc = sendto(priv->fd.fd, msg->data, msg->len, 0,
145 &dest->u.sa, sizeof(*dest));
146
147 msgb_free(msg);
148
149 return rc;
150}
151
Harald Welte5bef2cc2020-09-18 22:33:24 +0200152/*! send the msg and free it afterwards.
153 * \param nsvc NS-VC on which the message shall be sent
154 * \param msg message to be sent
155 * \return number of bytes transmitted; negative on error */
Alexander Couzens6a161492020-07-12 13:45:50 +0200156static int nsip_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
157{
158 int rc;
159 struct gprs_ns2_vc_bind *bind = nsvc->bind;
160 struct priv_vc *priv = nsvc->priv;
161
162 rc = nsip_sendmsg(bind, msg, &priv->remote);
163
164 return rc;
165}
166
167/* Read a single NS-over-IP message */
168static struct msgb *read_nsip_msg(struct osmo_fd *bfd, int *error,
169 struct osmo_sockaddr *saddr)
170{
171 struct msgb *msg = gprs_ns2_msgb_alloc();
172 int ret = 0;
173 socklen_t saddr_len = sizeof(*saddr);
174
175 if (!msg) {
176 *error = -ENOMEM;
177 return NULL;
178 }
179
180 ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE - NS_ALLOC_HEADROOM, 0,
181 &saddr->u.sa, &saddr_len);
182 if (ret < 0) {
183 LOGP(DLNS, LOGL_ERROR, "recv error %s during NSIP recvfrom %s\n",
184 strerror(errno), osmo_sock_get_name2(bfd->fd));
185 msgb_free(msg);
186 *error = ret;
187 return NULL;
188 } else if (ret == 0) {
189 msgb_free(msg);
190 *error = ret;
191 return NULL;
192 }
193
194 msg->l2h = msg->data;
195 msgb_put(msg, ret);
196
197 return msg;
198}
199
200static struct priv_vc *ns2_driver_alloc_vc(struct gprs_ns2_vc_bind *bind, struct gprs_ns2_vc *nsvc, struct osmo_sockaddr *remote)
201{
202 struct priv_vc *priv = talloc_zero(bind, struct priv_vc);
203 if (!priv)
204 return NULL;
205
206 nsvc->priv = priv;
207 priv->remote = *remote;
208
209 return priv;
210}
211
212static int handle_nsip_read(struct osmo_fd *bfd)
213{
Alexander Couzenscce88282020-10-26 00:25:50 +0100214 int rc = 0;
Alexander Couzens6a161492020-07-12 13:45:50 +0200215 int error = 0;
216 struct gprs_ns2_vc_bind *bind = bfd->data;
217 struct osmo_sockaddr saddr;
218 struct gprs_ns2_vc *nsvc;
219 struct msgb *msg = read_nsip_msg(bfd, &error, &saddr);
220 struct msgb *reject;
221
222 if (!msg)
223 return -EINVAL;
224
225 /* check if a vc is available */
Alexander Couzens38b19e82020-09-23 23:56:37 +0200226 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &saddr);
227 if (!nsvc) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200228 /* VC not found */
229 rc = ns2_create_vc(bind, msg, "newconnection", &reject, &nsvc);
230 switch (rc) {
231 case GPRS_NS2_CS_FOUND:
Alexander Couzens6a161492020-07-12 13:45:50 +0200232 break;
233 case GPRS_NS2_CS_ERROR:
234 case GPRS_NS2_CS_SKIPPED:
235 rc = 0;
Alexander Couzens13010122020-09-24 00:54:51 +0200236 goto out;
Alexander Couzens6a161492020-07-12 13:45:50 +0200237 case GPRS_NS2_CS_REJECTED:
238 /* nsip_sendmsg will free reject */
Alexander Couzens772ca612020-09-24 16:19:02 +0200239 rc = nsip_sendmsg(bind, reject, &saddr);
240 goto out;
Alexander Couzens6a161492020-07-12 13:45:50 +0200241 case GPRS_NS2_CS_CREATED:
242 ns2_driver_alloc_vc(bind, nsvc, &saddr);
243 gprs_ns2_vc_fsm_start(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200244 break;
245 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200246 }
247
Alexander Couzenscce88282020-10-26 00:25:50 +0100248 return ns2_recv_vc(nsvc, msg);
249
Alexander Couzens13010122020-09-24 00:54:51 +0200250out:
Alexander Couzens6a161492020-07-12 13:45:50 +0200251 msgb_free(msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200252 return rc;
253}
254
255static int handle_nsip_write(struct osmo_fd *bfd)
256{
257 /* FIXME: actually send the data here instead of nsip_sendmsg() */
258 return -EIO;
259}
260
261static int nsip_fd_cb(struct osmo_fd *bfd, unsigned int what)
262{
263 int rc = 0;
264
265 if (what & OSMO_FD_READ)
266 rc = handle_nsip_read(bfd);
267 if (what & OSMO_FD_WRITE)
268 rc = handle_nsip_write(bfd);
269
270 return rc;
271}
272
Alexander Couzens4f608452020-10-11 18:41:24 +0200273/*! Find NS bind for a given socket address
274 * \param[in] nsi NS instance
275 * \param[in] sockaddr socket address to search for
276 * \return
277 */
278struct gprs_ns2_vc_bind *gprs_ns2_ip_bind_by_sockaddr(struct gprs_ns2_inst *nsi,
279 const struct osmo_sockaddr *sockaddr)
280{
281 struct gprs_ns2_vc_bind *bind;
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200282 const struct osmo_sockaddr *local;
Alexander Couzens4f608452020-10-11 18:41:24 +0200283
284 OSMO_ASSERT(nsi);
285 OSMO_ASSERT(sockaddr);
286
287 llist_for_each_entry(bind, &nsi->binding, list) {
288 if (!gprs_ns2_is_ip_bind(bind))
289 continue;
290
291 local = gprs_ns2_ip_bind_sockaddr(bind);
292 if (!osmo_sockaddr_cmp(sockaddr, local))
293 return bind;
294 }
295
296 return NULL;
297}
298
Harald Welte5bef2cc2020-09-18 22:33:24 +0200299/*! Bind to an IPv4/IPv6 address
300 * \param[in] nsi NS Instance in which to create the NSVC
301 * \param[in] local the local address to bind to
302 * \param[in] dscp the DSCP/TOS bits used for transmitted data
303 * \param[out] result if set, returns the bind object
304 * \return 0 on success; negative in case of error */
Alexander Couzens6a161492020-07-12 13:45:50 +0200305int gprs_ns2_ip_bind(struct gprs_ns2_inst *nsi,
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100306 const char *name,
Vadim Yanitskiya07f25e2020-10-09 21:47:01 +0700307 const struct osmo_sockaddr *local,
Alexander Couzens6a161492020-07-12 13:45:50 +0200308 int dscp,
309 struct gprs_ns2_vc_bind **result)
310{
Alexander Couzens6090b1d2020-10-11 18:41:37 +0200311 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6a161492020-07-12 13:45:50 +0200312 struct priv_bind *priv;
313 int rc;
314
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100315 if (!name)
316 return -EINVAL;
317
318 if (gprs_ns2_bind_by_name(nsi, name))
319 return -EALREADY;
320
Alexander Couzens6090b1d2020-10-11 18:41:37 +0200321 bind = gprs_ns2_ip_bind_by_sockaddr(nsi, local);
322 if (bind) {
323 *result = bind;
324 return -EBUSY;
325 }
326
327 bind = talloc_zero(nsi, struct gprs_ns2_vc_bind);
Alexander Couzens6a161492020-07-12 13:45:50 +0200328 if (!bind)
329 return -ENOSPC;
330
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100331 bind->name = talloc_strdup(bind, name);
332 if (!bind->name) {
333 talloc_free(bind);
334 return -ENOSPC;
335 }
336
Alexander Couzens6a161492020-07-12 13:45:50 +0200337 if (local->u.sa.sa_family != AF_INET && local->u.sa.sa_family != AF_INET6) {
338 talloc_free(bind);
339 return -EINVAL;
340 }
341
342 bind->driver = &vc_driver_ip;
Alexander Couzensaac90162020-11-19 02:44:04 +0100343 bind->ll = GPRS_NS2_LL_UDP;
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100344 /* expect 100 mbit at least.
345 * TODO: ask the network layer about the speed. But would require
346 * notification on change. */
347 bind->transfer_capability = 100;
Alexander Couzens6a161492020-07-12 13:45:50 +0200348 bind->send_vc = nsip_vc_sendmsg;
349 bind->free_vc = free_vc;
Alexander Couzens22f34712020-10-02 02:34:39 +0200350 bind->dump_vty = dump_vty;
Alexander Couzens6a161492020-07-12 13:45:50 +0200351 bind->nsi = nsi;
352
353 priv = bind->priv = talloc_zero(bind, struct priv_bind);
354 if (!priv) {
355 talloc_free(bind);
356 return -ENOSPC;
357 }
358 priv->fd.cb = nsip_fd_cb;
359 priv->fd.data = bind;
360 priv->addr = *local;
361 INIT_LLIST_HEAD(&bind->nsvc);
362
Alexander Couzens6a161492020-07-12 13:45:50 +0200363 rc = osmo_sock_init_osa_ofd(&priv->fd, SOCK_DGRAM, IPPROTO_UDP,
364 local, NULL,
365 OSMO_SOCK_F_BIND);
366 if (rc < 0) {
367 talloc_free(priv);
368 talloc_free(bind);
369 return rc;
370 }
371
372 if (dscp > 0) {
373 priv->dscp = dscp;
374
375 rc = setsockopt(priv->fd.fd, IPPROTO_IP, IP_TOS,
376 &dscp, sizeof(dscp));
377 if (rc < 0)
378 LOGP(DLNS, LOGL_ERROR,
379 "Failed to set the DSCP to %d with ret(%d) errno(%d)\n",
380 dscp, rc, errno);
381 }
382
Pau Espin Pedrolaa83d412020-10-09 14:20:13 +0200383 llist_add(&bind->list, &nsi->binding);
Alexander Couzens6a161492020-07-12 13:45:50 +0200384 if (result)
385 *result = bind;
386
387 return 0;
388}
389
Harald Welte5bef2cc2020-09-18 22:33:24 +0200390/*! Create new NS-VC to a given remote address
391 * \param[in] bind the bind we want to connect
392 * \param[in] nse NS entity to be used for the new NS-VC
393 * \param[in] remote remote address to connect to
394 * \return pointer to newly-allocated and connected NS-VC; NULL on error */
Alexander Couzens6a161492020-07-12 13:45:50 +0200395struct gprs_ns2_vc *gprs_ns2_ip_bind_connect(struct gprs_ns2_vc_bind *bind,
396 struct gprs_ns2_nse *nse,
Vadim Yanitskiya07f25e2020-10-09 21:47:01 +0700397 const struct osmo_sockaddr *remote)
Alexander Couzens6a161492020-07-12 13:45:50 +0200398{
399 struct gprs_ns2_vc *nsvc;
400 struct priv_vc *priv;
Alexander Couzensd923cff2020-12-01 01:03:52 +0100401 enum gprs_ns2_vc_mode vc_mode;
Harald Welte603f4042020-11-29 17:39:19 +0100402 char *sockaddr_str;
403 char idbuf[64];
Alexander Couzens6a161492020-07-12 13:45:50 +0200404
Alexander Couzens55bc8692021-01-18 18:39:57 +0100405 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
406
Alexander Couzensd923cff2020-12-01 01:03:52 +0100407 vc_mode = gprs_ns2_dialect_to_vc_mode(nse->dialect);
408 if ((int) vc_mode == -1) {
409 LOGP(DLNS, LOGL_ERROR, "Can not derive vc mode from dialect %d. Maybe libosmocore is too old.\n",
410 nse->dialect);
411 return NULL;
412 }
413
Harald Welte603f4042020-11-29 17:39:19 +0100414 sockaddr_str = (char *)osmo_sockaddr_to_str(remote);
415 osmo_identifier_sanitize_buf(sockaddr_str, NULL, '_');
416 snprintf(idbuf, sizeof(idbuf), "%s-NSE%05u-remote-%s", gprs_ns2_lltype_str(nse->ll),
417 nse->nsei, sockaddr_str);
418 nsvc = ns2_vc_alloc(bind, nse, true, vc_mode, idbuf);
Alexander Couzensc06aa712020-11-18 23:56:45 +0100419 if (!nsvc)
420 return NULL;
421
Alexander Couzens6a161492020-07-12 13:45:50 +0200422 nsvc->priv = talloc_zero(bind, struct priv_vc);
423 if (!nsvc->priv) {
424 gprs_ns2_free_nsvc(nsvc);
425 return NULL;
426 }
427
428 priv = nsvc->priv;
429 priv->remote = *remote;
430
Alexander Couzens6a161492020-07-12 13:45:50 +0200431 return nsvc;
432}
433
Alexander Couzens979f5f52020-10-11 21:01:48 +0200434/*! Return the socket address of the local peer of a NS-VC.
435 * \param[in] nsvc NS-VC whose local peer we want to know
436 * \return address of the local peer; NULL in case of error */
437const struct osmo_sockaddr *gprs_ns2_ip_vc_local(const struct gprs_ns2_vc *nsvc)
438{
439 struct priv_bind *priv;
440
Alexander Couzens979f5f52020-10-11 21:01:48 +0200441 if (nsvc->bind->driver != &vc_driver_ip)
442 return NULL;
443
444 priv = nsvc->bind->priv;
445 return &priv->addr;
446}
447
Harald Welte5bef2cc2020-09-18 22:33:24 +0200448/*! Return the socket address of the remote peer of a NS-VC.
449 * \param[in] nsvc NS-VC whose remote peer we want to know
450 * \return address of the remote peer; NULL in case of error */
Alexander Couzensd33512b2020-10-11 21:42:11 +0200451const struct osmo_sockaddr *gprs_ns2_ip_vc_remote(const struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +0200452{
453 struct priv_vc *priv;
454
Alexander Couzensaac90162020-11-19 02:44:04 +0100455 if (nsvc->bind->driver != &vc_driver_ip)
Alexander Couzens6a161492020-07-12 13:45:50 +0200456 return NULL;
457
458 priv = nsvc->priv;
459 return &priv->remote;
460}
461
Alexander Couzensd420ea92020-10-12 01:11:05 +0200462/*! Compare the NS-VC with the given parameter
463 * \param[in] nsvc NS-VC to compare with
464 * \param[in] local The local address
465 * \param[in] remote The remote address
466 * \param[in] nsvci NS-VCI will only be used if the NS-VC in BLOCKRESET mode otherwise NS-VCI isn't applicable.
467 * \return true if the NS-VC has the same properties as given
468 */
469bool gprs_ns2_ip_vc_equal(const struct gprs_ns2_vc *nsvc,
470 const struct osmo_sockaddr *local,
471 const struct osmo_sockaddr *remote,
472 uint16_t nsvci)
473{
474 struct priv_vc *vpriv;
475 struct priv_bind *bpriv;
476
Alexander Couzensaac90162020-11-19 02:44:04 +0100477 if (nsvc->bind->driver != &vc_driver_ip)
Alexander Couzensd420ea92020-10-12 01:11:05 +0200478 return false;
479
480 vpriv = nsvc->priv;
481 bpriv = nsvc->bind->priv;
482
483 if (osmo_sockaddr_cmp(local, &bpriv->addr))
484 return false;
485
486 if (osmo_sockaddr_cmp(remote, &vpriv->remote))
487 return false;
488
489 if (nsvc->mode == NS2_VC_MODE_BLOCKRESET)
490 if (nsvc->nsvci != nsvci)
491 return false;
492
493 return true;
494}
495
Harald Welte5bef2cc2020-09-18 22:33:24 +0200496/*! Return the locally bound socket address of the bind.
497 * \param[in] bind The bind whose local address we want to know
498 * \return address of the local bind */
Alexander Couzens9a4cf272020-10-11 20:48:04 +0200499const struct osmo_sockaddr *gprs_ns2_ip_bind_sockaddr(struct gprs_ns2_vc_bind *bind)
Alexander Couzens6a161492020-07-12 13:45:50 +0200500{
501 struct priv_bind *priv;
Alexander Couzens55bc8692021-01-18 18:39:57 +0100502 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
Alexander Couzens6a161492020-07-12 13:45:50 +0200503
504 priv = bind->priv;
505 return &priv->addr;
506}
507
Harald Welte5bef2cc2020-09-18 22:33:24 +0200508/*! Is the given bind an IP bind? */
Alexander Couzens6a161492020-07-12 13:45:50 +0200509int gprs_ns2_is_ip_bind(struct gprs_ns2_vc_bind *bind)
510{
511 return (bind->driver == &vc_driver_ip);
512}
513
Harald Welte5bef2cc2020-09-18 22:33:24 +0200514/*! Set the DSCP (TOS) bit value of the given bind. */
Alexander Couzens6a161492020-07-12 13:45:50 +0200515int gprs_ns2_ip_bind_set_dscp(struct gprs_ns2_vc_bind *bind, int dscp)
516{
517 struct priv_bind *priv;
518 int rc = 0;
519
Alexander Couzens55bc8692021-01-18 18:39:57 +0100520 OSMO_ASSERT(gprs_ns2_is_ip_bind(bind));
Alexander Couzens6a161492020-07-12 13:45:50 +0200521 priv = bind->priv;
522
523 if (dscp != priv->dscp) {
524 priv->dscp = dscp;
525
526 rc = setsockopt(priv->fd.fd, IPPROTO_IP, IP_TOS,
527 &dscp, sizeof(dscp));
528 if (rc < 0)
529 LOGP(DLNS, LOGL_ERROR,
530 "Failed to set the DSCP to %d with ret(%d) errno(%d)\n",
531 dscp, rc, errno);
532 }
533
534 return rc;
535}
Alexander Couzense769f522020-12-07 07:37:07 +0100536
537/*! Count UDP binds compatible with remote */
538int ns2_ip_count_bind(struct gprs_ns2_inst *nsi, struct osmo_sockaddr *remote)
539{
540 struct gprs_ns2_vc_bind *bind;
541 const struct osmo_sockaddr *sa;
542 int count = 0;
543
544 llist_for_each_entry(bind, &nsi->binding, list) {
545 if (!gprs_ns2_is_ip_bind(bind))
546 continue;
547
548 sa = gprs_ns2_ip_bind_sockaddr(bind);
549 if (!sa)
550 continue;
551
552 if (sa->u.sa.sa_family == remote->u.sa.sa_family)
553 count++;
554 }
555
556 return count;
557}
558
559/* return the matching bind by index */
560struct gprs_ns2_vc_bind *ns2_ip_get_bind_by_index(struct gprs_ns2_inst *nsi,
561 struct osmo_sockaddr *remote,
562 int index)
563{
564 struct gprs_ns2_vc_bind *bind;
565 const struct osmo_sockaddr *sa;
566 int i = 0;
567
568 llist_for_each_entry(bind, &nsi->binding, list) {
569 if (!gprs_ns2_is_ip_bind(bind))
570 continue;
571
572 sa = gprs_ns2_ip_bind_sockaddr(bind);
573 if (!sa)
574 continue;
575
576 if (sa->u.sa.sa_family == remote->u.sa.sa_family) {
577 if (index == i)
578 return bind;
579 i++;
580 }
581 }
582
583 return NULL;
584}