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