blob: c774e11cd9ae39e11e6b5ade64f6f85570ecd481 [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>
Alexander Couzens841817e2020-11-19 00:41:29 +010045
46#include <osmocom/gprs/frame_relay.h>
47#include <osmocom/core/byteswap.h>
48#include <osmocom/core/logging.h>
49#include <osmocom/core/msgb.h>
50#include <osmocom/core/select.h>
51#include <osmocom/core/socket.h>
52#include <osmocom/core/talloc.h>
53#include <osmocom/gprs/gprs_ns2.h>
54
Pau Espin Pedrold41800c2020-12-07 13:35:24 +010055#ifdef ENABLE_LIBMNL
56#include <osmocom/core/mnl.h>
57#endif
58
Harald Welte56f08a32020-12-01 23:07:32 +010059#include "config.h"
Alexander Couzens841817e2020-11-19 00:41:29 +010060#include "common_vty.h"
61#include "gprs_ns2_internal.h"
62
63#define GRE_PTYPE_FR 0x6559
64#define GRE_PTYPE_IPv4 0x0800
65#define GRE_PTYPE_IPv6 0x86dd
66#define GRE_PTYPE_KAR 0x0000 /* keepalive response */
67
68#ifndef IPPROTO_GRE
69# define IPPROTO_GRE 47
70#endif
71
72struct gre_hdr {
73 uint16_t flags;
74 uint16_t ptype;
75} __attribute__ ((packed));
76
77static void free_bind(struct gprs_ns2_vc_bind *bind);
78static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg);
79
80struct gprs_ns2_vc_driver vc_driver_fr = {
81 .name = "GB frame relay",
82 .free_bind = free_bind,
83};
84
85struct priv_bind {
86 struct osmo_fd fd;
87 char netif[IF_NAMESIZE];
88 struct osmo_fr_link *link;
Harald Welte56f08a32020-12-01 23:07:32 +010089 bool if_running;
Alexander Couzens841817e2020-11-19 00:41:29 +010090};
91
92struct priv_vc {
93 struct osmo_sockaddr remote;
94 uint16_t dlci;
95 struct osmo_fr_dlc *dlc;
96};
97
98static void free_vc(struct gprs_ns2_vc *nsvc)
99{
100 OSMO_ASSERT(nsvc);
101
102 if (!nsvc->priv)
103 return;
104
105 talloc_free(nsvc->priv);
106 nsvc->priv = NULL;
107}
108
109static void dump_vty(const struct gprs_ns2_vc_bind *bind, struct vty *vty, bool _stats)
110{
111 struct priv_bind *priv;
112 struct gprs_ns2_vc *nsvc;
Harald Welte48bd76c2020-12-01 16:53:06 +0100113 struct osmo_fr_link *fr_link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100114
115 if (!bind)
116 return;
117
118 priv = bind->priv;
Harald Welte48bd76c2020-12-01 16:53:06 +0100119 fr_link = priv->link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100120
Harald Welte56f08a32020-12-01 23:07:32 +0100121 vty_out(vty, "FR bind: %s, role: %s, link: %s%s", priv->netif,
122 osmo_fr_role_str(fr_link->role), priv->if_running ? "UP" : "DOWN", VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +0100123
124 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
Harald Welte96ec84a2020-12-01 17:56:05 +0100125 vty_out(vty, " NSVCI %05u: %s%s", nsvc->nsvci, gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +0100126 }
127
128 priv = bind->priv;
129}
130
131/*! clean up all private driver state. Should be only called by gprs_ns2_free_bind() */
132static void free_bind(struct gprs_ns2_vc_bind *bind)
133{
134 struct priv_bind *priv;
135
136 if (!bind)
137 return;
138
139 priv = bind->priv;
140
141 OSMO_ASSERT(llist_empty(&bind->nsvc));
142
143 osmo_fr_link_free(priv->link);
144 osmo_fd_close(&priv->fd);
145 talloc_free(priv);
146}
147
148static struct priv_vc *fr_alloc_vc(struct gprs_ns2_vc_bind *bind,
149 struct gprs_ns2_vc *nsvc,
150 uint16_t dlci)
151{
152 struct priv_bind *privb = bind->priv;
153 struct priv_vc *priv = talloc_zero(bind, struct priv_vc);
154 if (!priv)
155 return NULL;
156
157 nsvc->priv = priv;
158 priv->dlci = dlci;
159 priv->dlc = osmo_fr_dlc_alloc(privb->link, dlci);
160 if (!priv->dlc) {
161 nsvc->priv = NULL;
162 talloc_free(priv);
163 return NULL;
164 }
165
166 priv->dlc->rx_cb_data = nsvc;
167 priv->dlc->rx_cb = fr_dlci_rx_cb;
168
169 return priv;
170}
171
172int gprs_ns2_find_vc_by_dlci(struct gprs_ns2_vc_bind *bind,
173 uint16_t dlci,
174 struct gprs_ns2_vc **result)
175{
176 struct gprs_ns2_vc *nsvc;
177 struct priv_vc *vcpriv;
178
179 if (!result)
180 return -EINVAL;
181
182 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
183 vcpriv = nsvc->priv;
184 if (vcpriv->dlci != dlci) {
185 *result = nsvc;
186 return 0;
187 }
188 }
189
190 return 1;
191}
192
193/* PDU from the network interface towards the fr layer (upwards) */
194static int handle_netif_read(struct osmo_fd *bfd)
195{
196 struct gprs_ns2_vc_bind *bind = bfd->data;
197 struct priv_bind *priv = bind->priv;
198 struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "Gb/NS/FR/GRE Rx");
199 int rc = 0;
200
201 if (!msg)
202 return -ENOMEM;
203
204 rc = read(bfd->fd, msg->data, NS_ALLOC_SIZE);
205 if (rc < 0) {
206 LOGP(DLNS, LOGL_ERROR, "recv error %s during NS-FR-GRE recv\n",
207 strerror(errno));
208 goto out_err;
209 } else if (rc == 0) {
210 goto out_err;
211 }
212
213 msgb_put(msg, rc);
214 msg->dst = priv->link;
215 return osmo_fr_rx(msg);
216
217out_err:
218 msgb_free(msg);
219 return rc;
220}
221
222/* PDU from the frame relay towards the NS-VC (upwards) */
223static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg)
224{
225 int rc;
226 struct gprs_ns2_vc *nsvc = cb_data;
227
228 rc = ns2_recv_vc(nsvc, msg);
229
230 return rc;
231}
232
233static int handle_netif_write(struct osmo_fd *bfd)
234{
235 /* FIXME */
236 return -EIO;
237}
238
239static int fr_fd_cb(struct osmo_fd *bfd, unsigned int what)
240{
241 int rc = 0;
242
243 if (what & OSMO_FD_READ)
244 rc = handle_netif_read(bfd);
245 if (what & OSMO_FD_WRITE)
246 rc = handle_netif_write(bfd);
247
248 return rc;
249}
250
251/*! determine if given bind is for FR-GRE encapsulation. */
252int gprs_ns2_is_fr_bind(struct gprs_ns2_vc_bind *bind)
253{
254 return (bind->driver == &vc_driver_fr);
255}
256
257/* PDU from the NS-VC towards the frame relay layer (downwards) */
258static int fr_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
259{
260 struct priv_vc *vcpriv = nsvc->priv;
261
262 msg->dst = vcpriv->dlc;
263 return osmo_fr_tx_dlc(msg);
264}
265
266/* PDU from the frame relay layer towards the network interface (downwards) */
267int fr_tx_cb(void *data, struct msgb *msg)
268{
269 struct gprs_ns2_vc_bind *bind = data;
270 struct priv_bind *priv = bind->priv;
271 int rc;
272
273 /* FIXME half writes */
274 rc = write(priv->fd.fd, msg->data, msg->len);
275 msgb_free(msg);
276
277 return rc;
278}
279
280static int devname2ifindex(const char *ifname)
281{
282 struct ifreq ifr;
283 int sk, rc;
284
285 sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
286 if (sk < 0)
287 return sk;
288
289
290 memset(&ifr, 0, sizeof(ifr));
291 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
292 ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0;
293
294 rc = ioctl(sk, SIOCGIFINDEX, &ifr);
295 close(sk);
296 if (rc < 0)
297 return rc;
298
299 return ifr.ifr_ifindex;
300}
301
302static int open_socket(const char *ifname)
303{
304 struct sockaddr_ll addr;
305 int ifindex;
Harald Welte4ed0f4e2020-12-10 21:50:32 +0100306 int fd, rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100307
308 ifindex = devname2ifindex(ifname);
309 if (ifindex < 0) {
310 LOGP(DLNS, LOGL_ERROR, "Can not get interface index for interface %s\n", ifname);
311 return ifindex;
312 }
313
314 memset(&addr, 0, sizeof(addr));
315 addr.sll_family = AF_PACKET;
316 addr.sll_protocol = htons(ETH_P_ALL);
317 addr.sll_ifindex = ifindex;
318
319 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
320 if (fd < 0) {
321 LOGP(DLNS, LOGL_ERROR, "Can not get socket for interface %s. Are you root or have CAP_RAW_SOCKET?\n", ifname);
322 return fd;
323 }
324
Alexander Couzens841817e2020-11-19 00:41:29 +0100325 rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
326 if (rc < 0) {
327 LOGP(DLNS, LOGL_ERROR, "Can not bind for interface %s\n", ifname);
328 close(fd);
329 return rc;
330 }
331
332 return fd;
333}
334
Harald Welte56f08a32020-12-01 23:07:32 +0100335#ifdef ENABLE_LIBMNL
336
337#include <osmocom/core/mnl.h>
Harald Welte56f08a32020-12-01 23:07:32 +0100338#include <linux/if_link.h>
339#include <linux/rtnetlink.h>
340
341#ifndef ARPHRD_FRAD
342#define ARPHRD_FRAD 770
343#endif
344
345/* validate the netlink attributes */
346static int data_attr_cb(const struct nlattr *attr, void *data)
347{
348 const struct nlattr **tb = data;
349 int type = mnl_attr_get_type(attr);
350
351 if (mnl_attr_type_valid(attr, IFLA_MAX) < 0)
352 return MNL_CB_OK;
353
354 switch (type) {
355 case IFLA_MTU:
356 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
357 return MNL_CB_ERROR;
358 break;
359 case IFLA_IFNAME:
360 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
361 return MNL_CB_ERROR;
362 break;
363 }
364 tb[type] = attr;
365 return MNL_CB_OK;
366}
367
368/* find the bind for the netdev (if any) */
369static struct gprs_ns2_vc_bind *bind4netdev(struct gprs_ns2_inst *nsi, const char *ifname)
370{
371 struct gprs_ns2_vc_bind *bind;
372
373 llist_for_each_entry(bind, &nsi->binding, list) {
374 struct priv_bind *bpriv = bind->priv;
375 if (!strcmp(bpriv->netif, ifname))
376 return bind;
377 }
378
379 return NULL;
380}
381
382/* handle a single netlink message received via libmnl */
383static int linkmon_mnl_cb(const struct nlmsghdr *nlh, void *data)
384{
385 struct osmo_mnl *omnl = data;
386 struct gprs_ns2_vc_bind *bind;
387 struct nlattr *tb[IFLA_MAX+1] = {};
388 struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh);
389 struct gprs_ns2_inst *nsi;
390 const char *ifname;
391 bool if_running;
392
393 OSMO_ASSERT(omnl);
394 OSMO_ASSERT(ifm);
395
396 nsi = omnl->priv;
397
398 if (ifm->ifi_type != ARPHRD_FRAD)
399 return MNL_CB_OK;
400
401 mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, tb);
402
403 if (!tb[IFLA_IFNAME])
404 return MNL_CB_OK;
405 ifname = mnl_attr_get_str(tb[IFLA_IFNAME]);
406 if_running = !!(ifm->ifi_flags & IFF_RUNNING);
407
408 bind = bind4netdev(nsi, ifname);
409 if (bind) {
410 struct priv_bind *bpriv = bind->priv;
411 if (bpriv->if_running != if_running) {
412 /* update running state */
413 LOGP(DLNS, LOGL_NOTICE, "FR net-device '%s': Physical link state changed: %s\n",
414 ifname, if_running ? "UP" : "DOWN");
415 bpriv->if_running = if_running;
416 }
417 }
418
419 return MNL_CB_OK;
420}
421
422/* trigger one initial dump of all link information */
423static void linkmon_initial_dump(struct osmo_mnl *omnl)
424{
425 char buf[MNL_SOCKET_BUFFER_SIZE];
426 struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
427 struct rtgenmsg *rt;
428
429 nlh->nlmsg_type = RTM_GETLINK;
430 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
431 nlh->nlmsg_seq = time(NULL);
432 rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
433 rt->rtgen_family = AF_PACKET;
434
435 if (mnl_socket_sendto(omnl->mnls, nlh, nlh->nlmsg_len) < 0) {
436 LOGP(DLNS, LOGL_ERROR, "linkmon: Cannot send rtnetlink message: %s\n", strerror(errno));
437 }
438
439 /* the response[s] will be handled just like the events */
440}
441#endif /* LIBMNL */
442
443
Alexander Couzens841817e2020-11-19 00:41:29 +0100444/*! Create a new bind for NS over FR.
445 * \param[in] nsi NS instance in which to create the bind
446 * \param[in] netif Network interface to bind to
447 * \param[in] fr_network
448 * \param[in] fr_role
449 * \param[out] result pointer to created bind
450 * \return 0 on success; negative on error */
451int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi,
452 const char *netif,
453 struct osmo_fr_network *fr_network,
454 enum osmo_fr_role fr_role,
455 struct gprs_ns2_vc_bind **result)
456{
457 struct gprs_ns2_vc_bind *bind = talloc_zero(nsi, struct gprs_ns2_vc_bind);
458 struct priv_bind *priv;
459 struct osmo_fr_link *fr_link;
460 int rc = 0;
461
462 if (!bind)
463 return -ENOSPC;
464
465 bind->driver = &vc_driver_fr;
Alexander Couzensaac90162020-11-19 02:44:04 +0100466 bind->ll = GPRS_NS2_LL_FR;
Alexander Couzens841817e2020-11-19 00:41:29 +0100467 bind->send_vc = fr_vc_sendmsg;
468 bind->free_vc = free_vc;
469 bind->dump_vty = dump_vty;
470 bind->nsi = nsi;
471 priv = bind->priv = talloc_zero(bind, struct priv_bind);
472 if (!priv) {
473 rc = -ENOSPC;
474 goto err_bind;
475 }
476
477 priv->fd.cb = fr_fd_cb;
478 priv->fd.data = bind;
479 if (strlen(netif) > IF_NAMESIZE) {
480 rc = -EINVAL;
481 goto err_priv;
482 }
483 strncpy(priv->netif, netif, sizeof(priv->netif));
484
485 ns2_vty_bind_apply(bind);
486 if (result)
487 *result = bind;
488
489 /* FIXME: move fd handling into socket.c */
490 fr_link = osmo_fr_link_alloc(fr_network, fr_role, netif);
491 if (!fr_link) {
492 rc = -EINVAL;
493 goto err_priv;
494 }
495
496 fr_link->tx_cb = fr_tx_cb;
497 fr_link->tx_cb_data = bind;
498 priv->link = fr_link;
499 priv->fd.fd = rc = open_socket(netif);
500 if (rc < 0)
501 goto err_fr;
502
503 priv->fd.when = OSMO_FD_READ;
504 rc = osmo_fd_register(&priv->fd);
505 if (rc < 0)
506 goto err_fd;
507
508 INIT_LLIST_HEAD(&bind->nsvc);
509 llist_add(&bind->list, &nsi->binding);
510
Harald Welte56f08a32020-12-01 23:07:32 +0100511#ifdef ENABLE_LIBMNL
512 if (!nsi->linkmon_mnl)
513 nsi->linkmon_mnl = osmo_mnl_init(nsi, NETLINK_ROUTE, RTMGRP_LINK, linkmon_mnl_cb, nsi);
514
515 /* we get a new full dump after every bind. which is a bit excessive. But that's just once
516 * at start-up, so we can get away with it */
517 if (nsi->linkmon_mnl)
518 linkmon_initial_dump(nsi->linkmon_mnl);
519#endif
520
Alexander Couzens841817e2020-11-19 00:41:29 +0100521 return rc;
522
523err_fd:
524 close(priv->fd.fd);
525err_fr:
526 osmo_fr_link_free(fr_link);
527err_priv:
528 talloc_free(priv);
529err_bind:
530 talloc_free(bind);
531
532 return rc;
533}
534
535/*! Return the network interface of the bind
536 * \param[in] bind The bind
537 * \return the network interface
538 */
539const char *gprs_ns2_fr_bind_netif(struct gprs_ns2_vc_bind *bind)
540{
541 struct priv_bind *priv;
542
543 if (bind->driver != &vc_driver_fr)
544 return NULL;
545
546 priv = bind->priv;
547 return priv->netif;
548}
549
550/*! Find NS bind for a given network interface
551 * \param[in] nsi NS instance
552 * \param[in] netif the network interface to search for
553 * \return the bind or NULL if not found
554 */
555struct gprs_ns2_vc_bind *gprs_ns2_fr_bind_by_netif(
556 struct gprs_ns2_inst *nsi,
557 const char *netif)
558{
559 struct gprs_ns2_vc_bind *bind;
560 const char *_netif;
561
562 OSMO_ASSERT(nsi);
563 OSMO_ASSERT(netif);
564
565 llist_for_each_entry(bind, &nsi->binding, list) {
566 if (!gprs_ns2_is_fr_bind(bind))
567 continue;
568
569 _netif = gprs_ns2_fr_bind_netif(bind);
570 if (!strncmp(_netif, netif, IF_NAMESIZE))
571 return bind;
572 }
573
574 return NULL;
575}
576
577/*! Create, connect and activate a new FR-based NS-VC
578 * \param[in] bind bind in which the new NS-VC is to be created
579 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
580 * \param[in] dlci Data Link connection identifier
581 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
582struct gprs_ns2_vc *gprs_ns2_fr_connect(struct gprs_ns2_vc_bind *bind,
583 uint16_t nsei,
584 uint16_t nsvci,
585 uint16_t dlci)
586{
587 bool created_nse = false;
588 struct gprs_ns2_vc *nsvc = NULL;
589 struct priv_vc *priv = NULL;
590 struct gprs_ns2_nse *nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei);
591 if (!nse) {
Alexander Couzensaac90162020-11-19 02:44:04 +0100592 nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_FR);
Alexander Couzens841817e2020-11-19 00:41:29 +0100593 if (!nse)
594 return NULL;
595 created_nse = true;
596 }
597
598 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
599 if (nsvc) {
600 goto err_nse;
601 }
602
603 nsvc = ns2_vc_alloc(bind, nse, true);
604 if (!nsvc)
605 goto err_nse;
606
607 nsvc->priv = priv = fr_alloc_vc(bind, nsvc, dlci);
608 if (!priv)
609 goto err;
610
611 nsvc->nsvci = nsvci;
612 nsvc->nsvci_is_valid = true;
Alexander Couzens841817e2020-11-19 00:41:29 +0100613
614 gprs_ns2_vc_fsm_start(nsvc);
615
616 return nsvc;
617
618err:
619 gprs_ns2_free_nsvc(nsvc);
620err_nse:
621 if (created_nse)
622 gprs_ns2_free_nse(nse);
623
624 return NULL;
625}
626
627/*! Return the nsvc by dlci.
628 * \param[in] bind
629 * \param[in] dlci Data Link connection identifier
630 * \return the nsvc or NULL if not found
631 */
632struct gprs_ns2_vc *gprs_ns2_fr_nsvc_by_dlci(struct gprs_ns2_vc_bind *bind,
633 uint16_t dlci)
634{
635 struct gprs_ns2_vc *nsvc;
636 struct priv_vc *vcpriv;
637
638 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
639 vcpriv = nsvc->priv;
640
641 if (dlci == vcpriv->dlci)
642 return nsvc;
643 }
644
645 return NULL;
646}
647
648/*! Return the dlci of the nsvc
649 * \param[in] nsvc
650 * \return the dlci or 0 on error. 0 is not a valid dlci.
651 */
652uint16_t gprs_ns2_fr_nsvc_dlci(struct gprs_ns2_vc *nsvc)
653{
654 struct priv_vc *vcpriv;
655
656 if (!nsvc->bind)
657 return 0;
658
659 if (nsvc->bind->driver != &vc_driver_fr)
660 return 0;
661
662 vcpriv = nsvc->priv;
663 return vcpriv->dlci;
664}