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