blob: 07c8d46a9ccfed09a0d4dd3a19f554c2564df08a [file] [log] [blame]
Alexander Couzens841817e2020-11-19 00:41:29 +01001/*! \file gprs_ns2_fr.c
2 * NS-over-FR-over-GRE 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) 2009-2010,2014,2017 by Harald Welte <laforge@gnumonks.org>
8 * (C) 2020 sysmocom - s.f.m.c. GmbH
9 * Author: Alexander Couzens <lynxis@fe80.eu>
10 *
11 * All Rights Reserved
12 *
13 * SPDX-License-Identifier: GPL-2.0+
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 *
28 */
29
30#include <errno.h>
31#include <string.h>
32#include <unistd.h>
33
34#include <sys/socket.h>
35#include <netinet/in.h>
36#include <netinet/ip.h>
37#include <netinet/ip6.h>
38#include <arpa/inet.h>
39#include <net/if.h>
40
41#include <sys/ioctl.h>
42#include <netpacket/packet.h>
43#include <linux/if_ether.h>
44#include <linux/hdlc.h>
45#include <linux/if.h>
46
47#include <osmocom/gprs/frame_relay.h>
48#include <osmocom/core/byteswap.h>
49#include <osmocom/core/logging.h>
50#include <osmocom/core/msgb.h>
51#include <osmocom/core/select.h>
52#include <osmocom/core/socket.h>
53#include <osmocom/core/talloc.h>
54#include <osmocom/gprs/gprs_ns2.h>
55
56#include "common_vty.h"
57#include "gprs_ns2_internal.h"
58
59#define GRE_PTYPE_FR 0x6559
60#define GRE_PTYPE_IPv4 0x0800
61#define GRE_PTYPE_IPv6 0x86dd
62#define GRE_PTYPE_KAR 0x0000 /* keepalive response */
63
64#ifndef IPPROTO_GRE
65# define IPPROTO_GRE 47
66#endif
67
68struct gre_hdr {
69 uint16_t flags;
70 uint16_t ptype;
71} __attribute__ ((packed));
72
73static void free_bind(struct gprs_ns2_vc_bind *bind);
74static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg);
75
76struct gprs_ns2_vc_driver vc_driver_fr = {
77 .name = "GB frame relay",
78 .free_bind = free_bind,
79};
80
81struct priv_bind {
82 struct osmo_fd fd;
83 char netif[IF_NAMESIZE];
84 struct osmo_fr_link *link;
85};
86
87struct priv_vc {
88 struct osmo_sockaddr remote;
89 uint16_t dlci;
90 struct osmo_fr_dlc *dlc;
91};
92
93static void free_vc(struct gprs_ns2_vc *nsvc)
94{
95 OSMO_ASSERT(nsvc);
96
97 if (!nsvc->priv)
98 return;
99
100 talloc_free(nsvc->priv);
101 nsvc->priv = NULL;
102}
103
104static void dump_vty(const struct gprs_ns2_vc_bind *bind, struct vty *vty, bool _stats)
105{
106 struct priv_bind *priv;
107 struct gprs_ns2_vc *nsvc;
Harald Welte48bd76c2020-12-01 16:53:06 +0100108 struct osmo_fr_link *fr_link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100109
110 if (!bind)
111 return;
112
113 priv = bind->priv;
Harald Welte48bd76c2020-12-01 16:53:06 +0100114 fr_link = priv->link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100115
Harald Welte48bd76c2020-12-01 16:53:06 +0100116 vty_out(vty, "FR bind: %s, role: %s%s", priv->netif,
117 osmo_fr_role_str(fr_link->role), VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +0100118
119 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
120 vty_out(vty, " %s%s", gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
121 }
122
123 priv = bind->priv;
124}
125
126/*! clean up all private driver state. Should be only called by gprs_ns2_free_bind() */
127static void free_bind(struct gprs_ns2_vc_bind *bind)
128{
129 struct priv_bind *priv;
130
131 if (!bind)
132 return;
133
134 priv = bind->priv;
135
136 OSMO_ASSERT(llist_empty(&bind->nsvc));
137
138 osmo_fr_link_free(priv->link);
139 osmo_fd_close(&priv->fd);
140 talloc_free(priv);
141}
142
143static struct priv_vc *fr_alloc_vc(struct gprs_ns2_vc_bind *bind,
144 struct gprs_ns2_vc *nsvc,
145 uint16_t dlci)
146{
147 struct priv_bind *privb = bind->priv;
148 struct priv_vc *priv = talloc_zero(bind, struct priv_vc);
149 if (!priv)
150 return NULL;
151
152 nsvc->priv = priv;
153 priv->dlci = dlci;
154 priv->dlc = osmo_fr_dlc_alloc(privb->link, dlci);
155 if (!priv->dlc) {
156 nsvc->priv = NULL;
157 talloc_free(priv);
158 return NULL;
159 }
160
161 priv->dlc->rx_cb_data = nsvc;
162 priv->dlc->rx_cb = fr_dlci_rx_cb;
163
164 return priv;
165}
166
167int gprs_ns2_find_vc_by_dlci(struct gprs_ns2_vc_bind *bind,
168 uint16_t dlci,
169 struct gprs_ns2_vc **result)
170{
171 struct gprs_ns2_vc *nsvc;
172 struct priv_vc *vcpriv;
173
174 if (!result)
175 return -EINVAL;
176
177 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
178 vcpriv = nsvc->priv;
179 if (vcpriv->dlci != dlci) {
180 *result = nsvc;
181 return 0;
182 }
183 }
184
185 return 1;
186}
187
188/* PDU from the network interface towards the fr layer (upwards) */
189static int handle_netif_read(struct osmo_fd *bfd)
190{
191 struct gprs_ns2_vc_bind *bind = bfd->data;
192 struct priv_bind *priv = bind->priv;
193 struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "Gb/NS/FR/GRE Rx");
194 int rc = 0;
195
196 if (!msg)
197 return -ENOMEM;
198
199 rc = read(bfd->fd, msg->data, NS_ALLOC_SIZE);
200 if (rc < 0) {
201 LOGP(DLNS, LOGL_ERROR, "recv error %s during NS-FR-GRE recv\n",
202 strerror(errno));
203 goto out_err;
204 } else if (rc == 0) {
205 goto out_err;
206 }
207
208 msgb_put(msg, rc);
209 msg->dst = priv->link;
210 return osmo_fr_rx(msg);
211
212out_err:
213 msgb_free(msg);
214 return rc;
215}
216
217/* PDU from the frame relay towards the NS-VC (upwards) */
218static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg)
219{
220 int rc;
221 struct gprs_ns2_vc *nsvc = cb_data;
222
223 rc = ns2_recv_vc(nsvc, msg);
224
225 return rc;
226}
227
228static int handle_netif_write(struct osmo_fd *bfd)
229{
230 /* FIXME */
231 return -EIO;
232}
233
234static int fr_fd_cb(struct osmo_fd *bfd, unsigned int what)
235{
236 int rc = 0;
237
238 if (what & OSMO_FD_READ)
239 rc = handle_netif_read(bfd);
240 if (what & OSMO_FD_WRITE)
241 rc = handle_netif_write(bfd);
242
243 return rc;
244}
245
246/*! determine if given bind is for FR-GRE encapsulation. */
247int gprs_ns2_is_fr_bind(struct gprs_ns2_vc_bind *bind)
248{
249 return (bind->driver == &vc_driver_fr);
250}
251
252/* PDU from the NS-VC towards the frame relay layer (downwards) */
253static int fr_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
254{
255 struct priv_vc *vcpriv = nsvc->priv;
256
257 msg->dst = vcpriv->dlc;
258 return osmo_fr_tx_dlc(msg);
259}
260
261/* PDU from the frame relay layer towards the network interface (downwards) */
262int fr_tx_cb(void *data, struct msgb *msg)
263{
264 struct gprs_ns2_vc_bind *bind = data;
265 struct priv_bind *priv = bind->priv;
266 int rc;
267
268 /* FIXME half writes */
269 rc = write(priv->fd.fd, msg->data, msg->len);
270 msgb_free(msg);
271
272 return rc;
273}
274
275static int devname2ifindex(const char *ifname)
276{
277 struct ifreq ifr;
278 int sk, rc;
279
280 sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
281 if (sk < 0)
282 return sk;
283
284
285 memset(&ifr, 0, sizeof(ifr));
286 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
287 ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0;
288
289 rc = ioctl(sk, SIOCGIFINDEX, &ifr);
290 close(sk);
291 if (rc < 0)
292 return rc;
293
294 return ifr.ifr_ifindex;
295}
296
297static int open_socket(const char *ifname)
298{
299 struct sockaddr_ll addr;
300 int ifindex;
301 int fd, rc, on = 1;
302
303 ifindex = devname2ifindex(ifname);
304 if (ifindex < 0) {
305 LOGP(DLNS, LOGL_ERROR, "Can not get interface index for interface %s\n", ifname);
306 return ifindex;
307 }
308
309 memset(&addr, 0, sizeof(addr));
310 addr.sll_family = AF_PACKET;
311 addr.sll_protocol = htons(ETH_P_ALL);
312 addr.sll_ifindex = ifindex;
313
314 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
315 if (fd < 0) {
316 LOGP(DLNS, LOGL_ERROR, "Can not get socket for interface %s. Are you root or have CAP_RAW_SOCKET?\n", ifname);
317 return fd;
318 }
319
320 if (ioctl(fd, FIONBIO, (unsigned char *)&on) < 0) {
321 LOGP(DLGLOBAL, LOGL_ERROR,
322 "cannot set this socket unblocking: %s\n",
323 strerror(errno));
324 close(fd);
Harald Welteb6b82da2020-11-26 09:30:37 +0100325 return -EINVAL;
Alexander Couzens841817e2020-11-19 00:41:29 +0100326 }
327
328 rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
329 if (rc < 0) {
330 LOGP(DLNS, LOGL_ERROR, "Can not bind for interface %s\n", ifname);
331 close(fd);
332 return rc;
333 }
334
335 return fd;
336}
337
338/*! Create a new bind for NS over FR.
339 * \param[in] nsi NS instance in which to create the bind
340 * \param[in] netif Network interface to bind to
341 * \param[in] fr_network
342 * \param[in] fr_role
343 * \param[out] result pointer to created bind
344 * \return 0 on success; negative on error */
345int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi,
346 const char *netif,
347 struct osmo_fr_network *fr_network,
348 enum osmo_fr_role fr_role,
349 struct gprs_ns2_vc_bind **result)
350{
351 struct gprs_ns2_vc_bind *bind = talloc_zero(nsi, struct gprs_ns2_vc_bind);
352 struct priv_bind *priv;
353 struct osmo_fr_link *fr_link;
354 int rc = 0;
355
356 if (!bind)
357 return -ENOSPC;
358
359 bind->driver = &vc_driver_fr;
Alexander Couzensaac90162020-11-19 02:44:04 +0100360 bind->ll = GPRS_NS2_LL_FR;
Alexander Couzens841817e2020-11-19 00:41:29 +0100361 bind->send_vc = fr_vc_sendmsg;
362 bind->free_vc = free_vc;
363 bind->dump_vty = dump_vty;
364 bind->nsi = nsi;
365 priv = bind->priv = talloc_zero(bind, struct priv_bind);
366 if (!priv) {
367 rc = -ENOSPC;
368 goto err_bind;
369 }
370
371 priv->fd.cb = fr_fd_cb;
372 priv->fd.data = bind;
373 if (strlen(netif) > IF_NAMESIZE) {
374 rc = -EINVAL;
375 goto err_priv;
376 }
377 strncpy(priv->netif, netif, sizeof(priv->netif));
378
379 ns2_vty_bind_apply(bind);
380 if (result)
381 *result = bind;
382
383 /* FIXME: move fd handling into socket.c */
384 fr_link = osmo_fr_link_alloc(fr_network, fr_role, netif);
385 if (!fr_link) {
386 rc = -EINVAL;
387 goto err_priv;
388 }
389
390 fr_link->tx_cb = fr_tx_cb;
391 fr_link->tx_cb_data = bind;
392 priv->link = fr_link;
393 priv->fd.fd = rc = open_socket(netif);
394 if (rc < 0)
395 goto err_fr;
396
397 priv->fd.when = OSMO_FD_READ;
398 rc = osmo_fd_register(&priv->fd);
399 if (rc < 0)
400 goto err_fd;
401
402 INIT_LLIST_HEAD(&bind->nsvc);
403 llist_add(&bind->list, &nsi->binding);
404
405 return rc;
406
407err_fd:
408 close(priv->fd.fd);
409err_fr:
410 osmo_fr_link_free(fr_link);
411err_priv:
412 talloc_free(priv);
413err_bind:
414 talloc_free(bind);
415
416 return rc;
417}
418
419/*! Return the network interface of the bind
420 * \param[in] bind The bind
421 * \return the network interface
422 */
423const char *gprs_ns2_fr_bind_netif(struct gprs_ns2_vc_bind *bind)
424{
425 struct priv_bind *priv;
426
427 if (bind->driver != &vc_driver_fr)
428 return NULL;
429
430 priv = bind->priv;
431 return priv->netif;
432}
433
434/*! Find NS bind for a given network interface
435 * \param[in] nsi NS instance
436 * \param[in] netif the network interface to search for
437 * \return the bind or NULL if not found
438 */
439struct gprs_ns2_vc_bind *gprs_ns2_fr_bind_by_netif(
440 struct gprs_ns2_inst *nsi,
441 const char *netif)
442{
443 struct gprs_ns2_vc_bind *bind;
444 const char *_netif;
445
446 OSMO_ASSERT(nsi);
447 OSMO_ASSERT(netif);
448
449 llist_for_each_entry(bind, &nsi->binding, list) {
450 if (!gprs_ns2_is_fr_bind(bind))
451 continue;
452
453 _netif = gprs_ns2_fr_bind_netif(bind);
454 if (!strncmp(_netif, netif, IF_NAMESIZE))
455 return bind;
456 }
457
458 return NULL;
459}
460
461/*! Create, connect and activate a new FR-based NS-VC
462 * \param[in] bind bind in which the new NS-VC is to be created
463 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
464 * \param[in] dlci Data Link connection identifier
465 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
466struct gprs_ns2_vc *gprs_ns2_fr_connect(struct gprs_ns2_vc_bind *bind,
467 uint16_t nsei,
468 uint16_t nsvci,
469 uint16_t dlci)
470{
471 bool created_nse = false;
472 struct gprs_ns2_vc *nsvc = NULL;
473 struct priv_vc *priv = NULL;
474 struct gprs_ns2_nse *nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei);
475 if (!nse) {
Alexander Couzensaac90162020-11-19 02:44:04 +0100476 nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_FR);
Alexander Couzens841817e2020-11-19 00:41:29 +0100477 if (!nse)
478 return NULL;
479 created_nse = true;
480 }
481
482 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
483 if (nsvc) {
484 goto err_nse;
485 }
486
487 nsvc = ns2_vc_alloc(bind, nse, true);
488 if (!nsvc)
489 goto err_nse;
490
491 nsvc->priv = priv = fr_alloc_vc(bind, nsvc, dlci);
492 if (!priv)
493 goto err;
494
495 nsvc->nsvci = nsvci;
496 nsvc->nsvci_is_valid = true;
Alexander Couzens841817e2020-11-19 00:41:29 +0100497
498 gprs_ns2_vc_fsm_start(nsvc);
499
500 return nsvc;
501
502err:
503 gprs_ns2_free_nsvc(nsvc);
504err_nse:
505 if (created_nse)
506 gprs_ns2_free_nse(nse);
507
508 return NULL;
509}
510
511/*! Return the nsvc by dlci.
512 * \param[in] bind
513 * \param[in] dlci Data Link connection identifier
514 * \return the nsvc or NULL if not found
515 */
516struct gprs_ns2_vc *gprs_ns2_fr_nsvc_by_dlci(struct gprs_ns2_vc_bind *bind,
517 uint16_t dlci)
518{
519 struct gprs_ns2_vc *nsvc;
520 struct priv_vc *vcpriv;
521
522 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
523 vcpriv = nsvc->priv;
524
525 if (dlci == vcpriv->dlci)
526 return nsvc;
527 }
528
529 return NULL;
530}
531
532/*! Return the dlci of the nsvc
533 * \param[in] nsvc
534 * \return the dlci or 0 on error. 0 is not a valid dlci.
535 */
536uint16_t gprs_ns2_fr_nsvc_dlci(struct gprs_ns2_vc *nsvc)
537{
538 struct priv_vc *vcpriv;
539
540 if (!nsvc->bind)
541 return 0;
542
543 if (nsvc->bind->driver != &vc_driver_fr)
544 return 0;
545
546 vcpriv = nsvc->priv;
547 return vcpriv->dlci;
548}