blob: 2f55f2a78ccc22de7a96f192ca48a647d0a7eb6e [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
Harald Welte5bef2cc2020-09-18 22:33:24 +020081/*! Find a NS-VC by its remote socket address.
82 * \param[in] bind in which to search
83 * \param[in] saddr remote peer socket adddress to search
Alexander Couzens38b19e82020-09-23 23:56:37 +020084 * \returns NS-VC matching sockaddr; NULL if none found */
85struct gprs_ns2_vc *gprs_ns2_nsvc_by_sockaddr_bind(struct gprs_ns2_vc_bind *bind, struct osmo_sockaddr *saddr)
Alexander Couzens6a161492020-07-12 13:45:50 +020086{
87 struct gprs_ns2_vc *nsvc;
88 struct priv_vc *vcpriv;
89
Alexander Couzens6a161492020-07-12 13:45:50 +020090 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
91 vcpriv = nsvc->priv;
92 if (vcpriv->remote.u.sa.sa_family != saddr->u.sa.sa_family)
93 continue;
94 if (osmo_sockaddr_cmp(&vcpriv->remote, saddr))
95 continue;
96
Alexander Couzens38b19e82020-09-23 23:56:37 +020097 return nsvc;
Alexander Couzens6a161492020-07-12 13:45:50 +020098 }
99
Alexander Couzens38b19e82020-09-23 23:56:37 +0200100 return NULL;
Alexander Couzens6a161492020-07-12 13:45:50 +0200101}
102
103static inline int nsip_sendmsg(struct gprs_ns2_vc_bind *bind,
104 struct msgb *msg,
105 struct osmo_sockaddr *dest)
106{
107 int rc;
108 struct priv_bind *priv = bind->priv;
109
110 rc = sendto(priv->fd.fd, msg->data, msg->len, 0,
111 &dest->u.sa, sizeof(*dest));
112
113 msgb_free(msg);
114
115 return rc;
116}
117
Harald Welte5bef2cc2020-09-18 22:33:24 +0200118/*! send the msg and free it afterwards.
119 * \param nsvc NS-VC on which the message shall be sent
120 * \param msg message to be sent
121 * \return number of bytes transmitted; negative on error */
Alexander Couzens6a161492020-07-12 13:45:50 +0200122static int nsip_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
123{
124 int rc;
125 struct gprs_ns2_vc_bind *bind = nsvc->bind;
126 struct priv_vc *priv = nsvc->priv;
127
128 rc = nsip_sendmsg(bind, msg, &priv->remote);
129
130 return rc;
131}
132
133/* Read a single NS-over-IP message */
134static struct msgb *read_nsip_msg(struct osmo_fd *bfd, int *error,
135 struct osmo_sockaddr *saddr)
136{
137 struct msgb *msg = gprs_ns2_msgb_alloc();
138 int ret = 0;
139 socklen_t saddr_len = sizeof(*saddr);
140
141 if (!msg) {
142 *error = -ENOMEM;
143 return NULL;
144 }
145
146 ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE - NS_ALLOC_HEADROOM, 0,
147 &saddr->u.sa, &saddr_len);
148 if (ret < 0) {
149 LOGP(DLNS, LOGL_ERROR, "recv error %s during NSIP recvfrom %s\n",
150 strerror(errno), osmo_sock_get_name2(bfd->fd));
151 msgb_free(msg);
152 *error = ret;
153 return NULL;
154 } else if (ret == 0) {
155 msgb_free(msg);
156 *error = ret;
157 return NULL;
158 }
159
160 msg->l2h = msg->data;
161 msgb_put(msg, ret);
162
163 return msg;
164}
165
166static struct priv_vc *ns2_driver_alloc_vc(struct gprs_ns2_vc_bind *bind, struct gprs_ns2_vc *nsvc, struct osmo_sockaddr *remote)
167{
168 struct priv_vc *priv = talloc_zero(bind, struct priv_vc);
169 if (!priv)
170 return NULL;
171
172 nsvc->priv = priv;
173 priv->remote = *remote;
174
175 return priv;
176}
177
178static int handle_nsip_read(struct osmo_fd *bfd)
179{
180 int rc;
181 int error = 0;
182 struct gprs_ns2_vc_bind *bind = bfd->data;
183 struct osmo_sockaddr saddr;
184 struct gprs_ns2_vc *nsvc;
185 struct msgb *msg = read_nsip_msg(bfd, &error, &saddr);
186 struct msgb *reject;
187
188 if (!msg)
189 return -EINVAL;
190
191 /* check if a vc is available */
Alexander Couzens38b19e82020-09-23 23:56:37 +0200192 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &saddr);
193 if (!nsvc) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200194 /* VC not found */
195 rc = ns2_create_vc(bind, msg, "newconnection", &reject, &nsvc);
196 switch (rc) {
197 case GPRS_NS2_CS_FOUND:
Alexander Couzensffd49d02020-09-24 00:47:17 +0200198 rc = ns2_recv_vc(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200199 break;
200 case GPRS_NS2_CS_ERROR:
201 case GPRS_NS2_CS_SKIPPED:
202 rc = 0;
203 break;
204 case GPRS_NS2_CS_REJECTED:
205 /* nsip_sendmsg will free reject */
206 nsip_sendmsg(bind, reject, &saddr);
207 return 0;
208 case GPRS_NS2_CS_CREATED:
209 ns2_driver_alloc_vc(bind, nsvc, &saddr);
210 gprs_ns2_vc_fsm_start(nsvc);
Alexander Couzensffd49d02020-09-24 00:47:17 +0200211 rc = ns2_recv_vc(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200212 break;
213 }
214 } else {
215 /* VC found */
Alexander Couzensffd49d02020-09-24 00:47:17 +0200216 rc = ns2_recv_vc(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200217 }
218
219 msgb_free(msg);
220
221 return rc;
222}
223
224static int handle_nsip_write(struct osmo_fd *bfd)
225{
226 /* FIXME: actually send the data here instead of nsip_sendmsg() */
227 return -EIO;
228}
229
230static int nsip_fd_cb(struct osmo_fd *bfd, unsigned int what)
231{
232 int rc = 0;
233
234 if (what & OSMO_FD_READ)
235 rc = handle_nsip_read(bfd);
236 if (what & OSMO_FD_WRITE)
237 rc = handle_nsip_write(bfd);
238
239 return rc;
240}
241
Harald Welte5bef2cc2020-09-18 22:33:24 +0200242/*! Bind to an IPv4/IPv6 address
243 * \param[in] nsi NS Instance in which to create the NSVC
244 * \param[in] local the local address to bind to
245 * \param[in] dscp the DSCP/TOS bits used for transmitted data
246 * \param[out] result if set, returns the bind object
247 * \return 0 on success; negative in case of error */
Alexander Couzens6a161492020-07-12 13:45:50 +0200248int gprs_ns2_ip_bind(struct gprs_ns2_inst *nsi,
249 struct osmo_sockaddr *local,
250 int dscp,
251 struct gprs_ns2_vc_bind **result)
252{
253 struct gprs_ns2_vc_bind *bind = talloc_zero(nsi, struct gprs_ns2_vc_bind);
254 struct priv_bind *priv;
255 int rc;
256
257 if (!bind)
258 return -ENOSPC;
259
260 if (local->u.sa.sa_family != AF_INET && local->u.sa.sa_family != AF_INET6) {
261 talloc_free(bind);
262 return -EINVAL;
263 }
264
265 bind->driver = &vc_driver_ip;
266 bind->send_vc = nsip_vc_sendmsg;
267 bind->free_vc = free_vc;
268 bind->nsi = nsi;
269
270 priv = bind->priv = talloc_zero(bind, struct priv_bind);
271 if (!priv) {
272 talloc_free(bind);
273 return -ENOSPC;
274 }
275 priv->fd.cb = nsip_fd_cb;
276 priv->fd.data = bind;
277 priv->addr = *local;
278 INIT_LLIST_HEAD(&bind->nsvc);
279
280 llist_add(&bind->list, &nsi->binding);
281
282 rc = osmo_sock_init_osa_ofd(&priv->fd, SOCK_DGRAM, IPPROTO_UDP,
283 local, NULL,
284 OSMO_SOCK_F_BIND);
285 if (rc < 0) {
286 talloc_free(priv);
287 talloc_free(bind);
288 return rc;
289 }
290
291 if (dscp > 0) {
292 priv->dscp = dscp;
293
294 rc = setsockopt(priv->fd.fd, IPPROTO_IP, IP_TOS,
295 &dscp, sizeof(dscp));
296 if (rc < 0)
297 LOGP(DLNS, LOGL_ERROR,
298 "Failed to set the DSCP to %d with ret(%d) errno(%d)\n",
299 dscp, rc, errno);
300 }
301
302 ns2_vty_bind_apply(bind);
303
304 if (result)
305 *result = bind;
306
307 return 0;
308}
309
Harald Welte5bef2cc2020-09-18 22:33:24 +0200310/*! Create new NS-VC to a given remote address
311 * \param[in] bind the bind we want to connect
312 * \param[in] nse NS entity to be used for the new NS-VC
313 * \param[in] remote remote address to connect to
314 * \return pointer to newly-allocated and connected NS-VC; NULL on error */
Alexander Couzens6a161492020-07-12 13:45:50 +0200315struct gprs_ns2_vc *gprs_ns2_ip_bind_connect(struct gprs_ns2_vc_bind *bind,
316 struct gprs_ns2_nse *nse,
317 struct osmo_sockaddr *remote)
318{
319 struct gprs_ns2_vc *nsvc;
320 struct priv_vc *priv;
321
322 nsvc = ns2_vc_alloc(bind, nse, true);
323 nsvc->priv = talloc_zero(bind, struct priv_vc);
324 if (!nsvc->priv) {
325 gprs_ns2_free_nsvc(nsvc);
326 return NULL;
327 }
328
329 priv = nsvc->priv;
330 priv->remote = *remote;
331
332 nsvc->ll = GPRS_NS_LL_UDP;
333
334 return nsvc;
335}
336
Harald Welte5bef2cc2020-09-18 22:33:24 +0200337/*! Return the socket address of the remote peer of a NS-VC.
338 * \param[in] nsvc NS-VC whose remote peer we want to know
339 * \return address of the remote peer; NULL in case of error */
Alexander Couzens6a161492020-07-12 13:45:50 +0200340struct osmo_sockaddr *gprs_ns2_ip_vc_sockaddr(struct gprs_ns2_vc *nsvc)
341{
342 struct priv_vc *priv;
343
344 if (nsvc->ll != GPRS_NS_LL_UDP)
345 return NULL;
346
347 priv = nsvc->priv;
348 return &priv->remote;
349}
350
Harald Welte5bef2cc2020-09-18 22:33:24 +0200351/*! Return the locally bound socket address of the bind.
352 * \param[in] bind The bind whose local address we want to know
353 * \return address of the local bind */
Alexander Couzens6a161492020-07-12 13:45:50 +0200354struct osmo_sockaddr *gprs_ns2_ip_bind_sockaddr(struct gprs_ns2_vc_bind *bind)
355{
356 struct priv_bind *priv;
357
358 priv = bind->priv;
359 return &priv->addr;
360}
361
Harald Welte5bef2cc2020-09-18 22:33:24 +0200362/*! Is the given bind an IP bind? */
Alexander Couzens6a161492020-07-12 13:45:50 +0200363int gprs_ns2_is_ip_bind(struct gprs_ns2_vc_bind *bind)
364{
365 return (bind->driver == &vc_driver_ip);
366}
367
Harald Welte5bef2cc2020-09-18 22:33:24 +0200368/*! Set the DSCP (TOS) bit value of the given bind. */
Alexander Couzens6a161492020-07-12 13:45:50 +0200369int gprs_ns2_ip_bind_set_dscp(struct gprs_ns2_vc_bind *bind, int dscp)
370{
371 struct priv_bind *priv;
372 int rc = 0;
373
374 priv = bind->priv;
375
376 if (dscp != priv->dscp) {
377 priv->dscp = dscp;
378
379 rc = setsockopt(priv->fd.fd, IPPROTO_IP, IP_TOS,
380 &dscp, sizeof(dscp));
381 if (rc < 0)
382 LOGP(DLNS, LOGL_ERROR,
383 "Failed to set the DSCP to %d with ret(%d) errno(%d)\n",
384 dscp, rc, errno);
385 }
386
387 return rc;
388}