blob: 096e150aa05e3b22eacbfdceb9676afc934fd90d [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>
Alexander Couzens5c96f5d2020-12-17 04:45:03 +010039#include <linux/if.h>
Alexander Couzens841817e2020-11-19 00:41:29 +010040
41#include <sys/ioctl.h>
42#include <netpacket/packet.h>
43#include <linux/if_ether.h>
44#include <linux/hdlc.h>
Alexander Couzens5c96f5d2020-12-17 04:45:03 +010045#include <linux/hdlc/ioctl.h>
46#include <linux/sockios.h>
Alexander Couzens841817e2020-11-19 00:41:29 +010047
48#include <osmocom/gprs/frame_relay.h>
49#include <osmocom/core/byteswap.h>
50#include <osmocom/core/logging.h>
51#include <osmocom/core/msgb.h>
52#include <osmocom/core/select.h>
53#include <osmocom/core/socket.h>
54#include <osmocom/core/talloc.h>
Alexander Couzens60021a42020-12-17 02:48:22 +010055#include <osmocom/core/write_queue.h>
Alexander Couzens841817e2020-11-19 00:41:29 +010056#include <osmocom/gprs/gprs_ns2.h>
57
Pau Espin Pedrold41800c2020-12-07 13:35:24 +010058#ifdef ENABLE_LIBMNL
59#include <osmocom/core/mnl.h>
60#endif
61
Harald Welte56f08a32020-12-01 23:07:32 +010062#include "config.h"
Alexander Couzens841817e2020-11-19 00:41:29 +010063#include "common_vty.h"
64#include "gprs_ns2_internal.h"
65
66#define GRE_PTYPE_FR 0x6559
67#define GRE_PTYPE_IPv4 0x0800
68#define GRE_PTYPE_IPv6 0x86dd
69#define GRE_PTYPE_KAR 0x0000 /* keepalive response */
70
71#ifndef IPPROTO_GRE
72# define IPPROTO_GRE 47
73#endif
74
75struct gre_hdr {
76 uint16_t flags;
77 uint16_t ptype;
78} __attribute__ ((packed));
79
80static void free_bind(struct gprs_ns2_vc_bind *bind);
81static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg);
82
83struct gprs_ns2_vc_driver vc_driver_fr = {
84 .name = "GB frame relay",
85 .free_bind = free_bind,
86};
87
88struct priv_bind {
Alexander Couzens5c96f5d2020-12-17 04:45:03 +010089 char netif[IFNAMSIZ];
Alexander Couzens841817e2020-11-19 00:41:29 +010090 struct osmo_fr_link *link;
Alexander Couzens60021a42020-12-17 02:48:22 +010091 struct osmo_wqueue wqueue;
Harald Welte41b188b2020-12-10 22:00:23 +010092 int ifindex;
Harald Welte56f08a32020-12-01 23:07:32 +010093 bool if_running;
Alexander Couzens841817e2020-11-19 00:41:29 +010094};
95
96struct priv_vc {
97 struct osmo_sockaddr remote;
98 uint16_t dlci;
99 struct osmo_fr_dlc *dlc;
100};
101
102static void free_vc(struct gprs_ns2_vc *nsvc)
103{
Alexander Couzensea377242021-01-17 16:51:55 +0100104 if (!nsvc)
105 return;
Alexander Couzens841817e2020-11-19 00:41:29 +0100106
107 if (!nsvc->priv)
108 return;
109
Alexander Couzens55bc8692021-01-18 18:39:57 +0100110 OSMO_ASSERT(gprs_ns2_is_fr_bind(nsvc->bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100111 talloc_free(nsvc->priv);
112 nsvc->priv = NULL;
113}
114
115static void dump_vty(const struct gprs_ns2_vc_bind *bind, struct vty *vty, bool _stats)
116{
117 struct priv_bind *priv;
118 struct gprs_ns2_vc *nsvc;
Harald Welte48bd76c2020-12-01 16:53:06 +0100119 struct osmo_fr_link *fr_link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100120
121 if (!bind)
122 return;
123
124 priv = bind->priv;
Harald Welte48bd76c2020-12-01 16:53:06 +0100125 fr_link = priv->link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100126
Harald Welte56f08a32020-12-01 23:07:32 +0100127 vty_out(vty, "FR bind: %s, role: %s, link: %s%s", priv->netif,
128 osmo_fr_role_str(fr_link->role), priv->if_running ? "UP" : "DOWN", VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +0100129
130 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
Harald Welte96ec84a2020-12-01 17:56:05 +0100131 vty_out(vty, " NSVCI %05u: %s%s", nsvc->nsvci, gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +0100132 }
133
134 priv = bind->priv;
135}
136
137/*! clean up all private driver state. Should be only called by gprs_ns2_free_bind() */
138static void free_bind(struct gprs_ns2_vc_bind *bind)
139{
140 struct priv_bind *priv;
141
Alexander Couzens55bc8692021-01-18 18:39:57 +0100142 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100143 if (!bind)
144 return;
145
146 priv = bind->priv;
147
148 OSMO_ASSERT(llist_empty(&bind->nsvc));
149
150 osmo_fr_link_free(priv->link);
Alexander Couzens60021a42020-12-17 02:48:22 +0100151 osmo_fd_close(&priv->wqueue.bfd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100152 talloc_free(priv);
153}
154
155static struct priv_vc *fr_alloc_vc(struct gprs_ns2_vc_bind *bind,
156 struct gprs_ns2_vc *nsvc,
157 uint16_t dlci)
158{
159 struct priv_bind *privb = bind->priv;
160 struct priv_vc *priv = talloc_zero(bind, struct priv_vc);
161 if (!priv)
162 return NULL;
163
Alexander Couzens55bc8692021-01-18 18:39:57 +0100164 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100165 nsvc->priv = priv;
166 priv->dlci = dlci;
167 priv->dlc = osmo_fr_dlc_alloc(privb->link, dlci);
168 if (!priv->dlc) {
169 nsvc->priv = NULL;
170 talloc_free(priv);
171 return NULL;
172 }
173
174 priv->dlc->rx_cb_data = nsvc;
175 priv->dlc->rx_cb = fr_dlci_rx_cb;
176
177 return priv;
178}
179
180int gprs_ns2_find_vc_by_dlci(struct gprs_ns2_vc_bind *bind,
181 uint16_t dlci,
182 struct gprs_ns2_vc **result)
183{
184 struct gprs_ns2_vc *nsvc;
185 struct priv_vc *vcpriv;
186
Alexander Couzens55bc8692021-01-18 18:39:57 +0100187 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100188 if (!result)
189 return -EINVAL;
190
191 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
192 vcpriv = nsvc->priv;
193 if (vcpriv->dlci != dlci) {
194 *result = nsvc;
195 return 0;
196 }
197 }
198
199 return 1;
200}
201
202/* PDU from the network interface towards the fr layer (upwards) */
203static int handle_netif_read(struct osmo_fd *bfd)
204{
205 struct gprs_ns2_vc_bind *bind = bfd->data;
206 struct priv_bind *priv = bind->priv;
207 struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "Gb/NS/FR/GRE Rx");
Harald Welte41b188b2020-12-10 22:00:23 +0100208 struct sockaddr_ll sll;
209 socklen_t sll_len = sizeof(sll);
Alexander Couzens841817e2020-11-19 00:41:29 +0100210 int rc = 0;
211
212 if (!msg)
213 return -ENOMEM;
214
Harald Welte41b188b2020-12-10 22:00:23 +0100215 rc = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0, (struct sockaddr *)&sll, &sll_len);
Alexander Couzens841817e2020-11-19 00:41:29 +0100216 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100217 LOGBIND(bind, LOGL_ERROR, "recv error %s during NS-FR-GRE recv\n", strerror(errno));
Alexander Couzens841817e2020-11-19 00:41:29 +0100218 goto out_err;
219 } else if (rc == 0) {
220 goto out_err;
221 }
222
Harald Welte41b188b2020-12-10 22:00:23 +0100223 /* ignore any packets that we might have received for a different interface, between
224 * the socket() and the bind() call */
225 if (sll.sll_ifindex != priv->ifindex)
226 goto out_err;
227
Alexander Couzens841817e2020-11-19 00:41:29 +0100228 msgb_put(msg, rc);
229 msg->dst = priv->link;
230 return osmo_fr_rx(msg);
231
232out_err:
233 msgb_free(msg);
234 return rc;
235}
236
237/* PDU from the frame relay towards the NS-VC (upwards) */
238static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg)
239{
240 int rc;
241 struct gprs_ns2_vc *nsvc = cb_data;
242
243 rc = ns2_recv_vc(nsvc, msg);
244
245 return rc;
246}
247
Alexander Couzens60021a42020-12-17 02:48:22 +0100248static int handle_netif_write(struct osmo_fd *ofd, struct msgb *msg)
Alexander Couzens841817e2020-11-19 00:41:29 +0100249{
Harald Weltef0073d72021-01-30 11:41:13 +0100250 struct gprs_ns2_vc_bind *bind = ofd->data;
251 int rc;
252
253 rc = write(ofd->fd, msgb_data(msg), msgb_length(msg));
Harald Welte335c5502021-01-30 11:36:20 +0100254 /* write_queue expects a "-errno" type return value in case of failure */
Harald Weltef0073d72021-01-30 11:41:13 +0100255 if (rc == -1) {
256 LOGBIND(bind, LOGL_ERROR, "error during write to AF_PACKET: %s\n", strerror(errno));
Harald Welte335c5502021-01-30 11:36:20 +0100257 return -errno;
Harald Weltef0073d72021-01-30 11:41:13 +0100258 } else
Harald Welte335c5502021-01-30 11:36:20 +0100259 return rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100260}
261
262/*! determine if given bind is for FR-GRE encapsulation. */
263int gprs_ns2_is_fr_bind(struct gprs_ns2_vc_bind *bind)
264{
265 return (bind->driver == &vc_driver_fr);
266}
267
268/* PDU from the NS-VC towards the frame relay layer (downwards) */
269static int fr_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
270{
271 struct priv_vc *vcpriv = nsvc->priv;
272
273 msg->dst = vcpriv->dlc;
274 return osmo_fr_tx_dlc(msg);
275}
276
277/* PDU from the frame relay layer towards the network interface (downwards) */
278int fr_tx_cb(void *data, struct msgb *msg)
279{
280 struct gprs_ns2_vc_bind *bind = data;
281 struct priv_bind *priv = bind->priv;
Alexander Couzens841817e2020-11-19 00:41:29 +0100282
Alexander Couzens60021a42020-12-17 02:48:22 +0100283 if (osmo_wqueue_enqueue(&priv->wqueue, msg)) {
Harald Weltef2949742021-01-20 14:54:14 +0100284 LOGBIND(bind, LOGL_ERROR, "frame relay %s: failed to enqueue message\n", priv->netif);
Alexander Couzens60021a42020-12-17 02:48:22 +0100285 msgb_free(msg);
286 return -EINVAL;
287 }
Alexander Couzens841817e2020-11-19 00:41:29 +0100288
Alexander Couzens60021a42020-12-17 02:48:22 +0100289 return 0;
Alexander Couzens841817e2020-11-19 00:41:29 +0100290}
291
292static int devname2ifindex(const char *ifname)
293{
294 struct ifreq ifr;
295 int sk, rc;
296
297 sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
298 if (sk < 0)
299 return sk;
300
301
302 memset(&ifr, 0, sizeof(ifr));
Neels Hofmeyr475a0ac2020-12-17 18:10:34 +0100303 OSMO_STRLCPY_ARRAY(ifr.ifr_name, ifname);
Alexander Couzens841817e2020-11-19 00:41:29 +0100304
305 rc = ioctl(sk, SIOCGIFINDEX, &ifr);
306 close(sk);
307 if (rc < 0)
308 return rc;
309
310 return ifr.ifr_ifindex;
311}
312
Harald Weltef2949742021-01-20 14:54:14 +0100313static int open_socket(int ifindex, const struct gprs_ns2_vc_bind *nsbind)
Alexander Couzens841817e2020-11-19 00:41:29 +0100314{
315 struct sockaddr_ll addr;
Harald Welte4ed0f4e2020-12-10 21:50:32 +0100316 int fd, rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100317
Alexander Couzens841817e2020-11-19 00:41:29 +0100318 memset(&addr, 0, sizeof(addr));
319 addr.sll_family = AF_PACKET;
320 addr.sll_protocol = htons(ETH_P_ALL);
321 addr.sll_ifindex = ifindex;
322
Harald Welte5bea72e2020-12-10 22:06:21 +0100323 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_HDLC));
Alexander Couzens841817e2020-11-19 00:41:29 +0100324 if (fd < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100325 LOGBIND(nsbind, LOGL_ERROR, "Can not create AF_PACKET socket. Are you root or have CAP_NET_RAW?\n");
Alexander Couzens841817e2020-11-19 00:41:29 +0100326 return fd;
327 }
328
Harald Welte41b188b2020-12-10 22:00:23 +0100329 /* there's a race condition between the above syscall and the bind() call below,
330 * causing other packets to be received in between */
331
Alexander Couzens841817e2020-11-19 00:41:29 +0100332 rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
333 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100334 LOGBIND(nsbind, LOGL_ERROR, "Can not bind AF_PACKET socket to ifindex %d\n", ifindex);
Alexander Couzens841817e2020-11-19 00:41:29 +0100335 close(fd);
336 return rc;
337 }
338
339 return fd;
340}
341
Harald Welte56f08a32020-12-01 23:07:32 +0100342#ifdef ENABLE_LIBMNL
343
344#include <osmocom/core/mnl.h>
Harald Welte56f08a32020-12-01 23:07:32 +0100345#include <linux/if_link.h>
346#include <linux/rtnetlink.h>
347
348#ifndef ARPHRD_FRAD
349#define ARPHRD_FRAD 770
350#endif
351
352/* validate the netlink attributes */
353static int data_attr_cb(const struct nlattr *attr, void *data)
354{
355 const struct nlattr **tb = data;
356 int type = mnl_attr_get_type(attr);
357
358 if (mnl_attr_type_valid(attr, IFLA_MAX) < 0)
359 return MNL_CB_OK;
360
361 switch (type) {
362 case IFLA_MTU:
363 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
364 return MNL_CB_ERROR;
365 break;
366 case IFLA_IFNAME:
367 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
368 return MNL_CB_ERROR;
369 break;
370 }
371 tb[type] = attr;
372 return MNL_CB_OK;
373}
374
375/* find the bind for the netdev (if any) */
376static struct gprs_ns2_vc_bind *bind4netdev(struct gprs_ns2_inst *nsi, const char *ifname)
377{
378 struct gprs_ns2_vc_bind *bind;
379
380 llist_for_each_entry(bind, &nsi->binding, list) {
381 struct priv_bind *bpriv = bind->priv;
382 if (!strcmp(bpriv->netif, ifname))
383 return bind;
384 }
385
386 return NULL;
387}
388
389/* handle a single netlink message received via libmnl */
390static int linkmon_mnl_cb(const struct nlmsghdr *nlh, void *data)
391{
392 struct osmo_mnl *omnl = data;
393 struct gprs_ns2_vc_bind *bind;
394 struct nlattr *tb[IFLA_MAX+1] = {};
395 struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh);
396 struct gprs_ns2_inst *nsi;
397 const char *ifname;
398 bool if_running;
399
400 OSMO_ASSERT(omnl);
401 OSMO_ASSERT(ifm);
402
403 nsi = omnl->priv;
404
405 if (ifm->ifi_type != ARPHRD_FRAD)
406 return MNL_CB_OK;
407
408 mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, tb);
409
410 if (!tb[IFLA_IFNAME])
411 return MNL_CB_OK;
412 ifname = mnl_attr_get_str(tb[IFLA_IFNAME]);
413 if_running = !!(ifm->ifi_flags & IFF_RUNNING);
414
415 bind = bind4netdev(nsi, ifname);
416 if (bind) {
417 struct priv_bind *bpriv = bind->priv;
418 if (bpriv->if_running != if_running) {
419 /* update running state */
Harald Weltef2949742021-01-20 14:54:14 +0100420 LOGBIND(bind, LOGL_NOTICE, "FR net-device '%s': Physical link state changed: %s\n",
421 ifname, if_running ? "UP" : "DOWN");
Harald Welte56f08a32020-12-01 23:07:32 +0100422 bpriv->if_running = if_running;
423 }
424 }
425
426 return MNL_CB_OK;
427}
428
429/* trigger one initial dump of all link information */
430static void linkmon_initial_dump(struct osmo_mnl *omnl)
431{
432 char buf[MNL_SOCKET_BUFFER_SIZE];
433 struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
434 struct rtgenmsg *rt;
435
436 nlh->nlmsg_type = RTM_GETLINK;
437 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
438 nlh->nlmsg_seq = time(NULL);
439 rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
440 rt->rtgen_family = AF_PACKET;
441
442 if (mnl_socket_sendto(omnl->mnls, nlh, nlh->nlmsg_len) < 0) {
443 LOGP(DLNS, LOGL_ERROR, "linkmon: Cannot send rtnetlink message: %s\n", strerror(errno));
444 }
445
446 /* the response[s] will be handled just like the events */
447}
448#endif /* LIBMNL */
449
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100450static int set_ifupdown(const char *netif, bool up)
451{
452 int sock, rc;
453 struct ifreq req;
454
455 sock = socket(AF_INET, SOCK_DGRAM, 0);
456 if (sock < 0)
457 return sock;
458
459 memset(&req, 0, sizeof req);
Harald Welte7f01b682020-12-21 12:39:38 +0100460 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100461
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100462 rc = ioctl(sock, SIOCGIFFLAGS, &req);
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100463 if (rc < 0) {
464 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100465 return rc;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100466 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100467
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100468 if ((req.ifr_flags & IFF_UP) == up) {
469 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100470 return 0;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100471 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100472
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100473 if (up)
474 req.ifr_flags |= IFF_UP;
475
476 rc = ioctl(sock, SIOCSIFFLAGS, &req);
477 close(sock);
478 return rc;
479}
480
Harald Weltef2949742021-01-20 14:54:14 +0100481static int setup_device(const char *netif, const struct gprs_ns2_vc_bind *bind)
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100482{
483 int sock, rc;
484 char buffer[128];
485 fr_proto *fr = (void*)buffer;
486 struct ifreq req;
487
488 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
489 if (sock < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100490 LOGBIND(bind, LOGL_ERROR, "%s: Unable to create socket: %s\n",
491 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100492 return sock;
493 }
494
495 memset(&req, 0, sizeof(struct ifreq));
496 memset(&buffer, 0, sizeof(buffer));
Harald Welteb8de1882020-12-21 12:40:45 +0100497 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100498 req.ifr_settings.ifs_ifsu.sync = (void*)buffer;
499 req.ifr_settings.size = sizeof(buffer);
500 req.ifr_settings.type = IF_GET_PROTO;
501
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100502 /* EINVAL is returned when no protocol has been set */
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100503 rc = ioctl(sock, SIOCWANDEV, &req);
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100504 if (rc < 0 && errno != EINVAL) {
Harald Weltef2949742021-01-20 14:54:14 +0100505 LOGBIND(bind, LOGL_ERROR, "%s: Unable to get FR protocol information: %s\n",
506 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100507 goto err;
508 }
509
510 /* check if the device is good */
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100511 if (rc == 0 && req.ifr_settings.type == IF_PROTO_FR && fr->lmi == LMI_NONE) {
Harald Weltef2949742021-01-20 14:54:14 +0100512 LOGBIND(bind, LOGL_NOTICE, "%s: has correct frame relay mode and lmi\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100513 goto ifup;
514 }
515
516 /* modify the device to match */
517 rc = set_ifupdown(netif, false);
518 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100519 LOGBIND(bind, LOGL_ERROR, "Unable to bring down the device %s: %s\n",
520 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100521 goto err;
522 }
523
524 memset(&req, 0, sizeof(struct ifreq));
525 memset(fr, 0, sizeof(fr_proto));
Harald Welteb8de1882020-12-21 12:40:45 +0100526 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100527 req.ifr_settings.type = IF_PROTO_FR;
528 req.ifr_settings.size = sizeof(fr_proto);
529 req.ifr_settings.ifs_ifsu.fr = fr;
530 fr->lmi = LMI_NONE;
531 /* even those settings aren't used, they must be in the range */
532 /* polling verification timer*/
533 fr->t391 = 10;
534 /* link integrity verification polling timer */
535 fr->t392 = 15;
536 /* full status polling counter*/
537 fr->n391 = 6;
538 /* error threshold */
539 fr->n392 = 3;
540 /* monitored events count */
541 fr->n393 = 4;
542
Harald Weltef2949742021-01-20 14:54:14 +0100543 LOGBIND(bind, LOGL_INFO, "%s: Setting frame relay related parameters\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100544 rc = ioctl(sock, SIOCWANDEV, &req);
545 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100546 LOGBIND(bind, LOGL_ERROR, "%s: Unable to set FR protocol on information: %s\n",
547 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100548 goto err;
549 }
550
551ifup:
552 rc = set_ifupdown(netif, true);
553 if (rc)
Harald Weltef2949742021-01-20 14:54:14 +0100554 LOGBIND(bind, LOGL_ERROR, "Unable to bring up the device %s: %s\n",
555 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100556err:
557 close(sock);
558 return rc;
559}
Harald Welte56f08a32020-12-01 23:07:32 +0100560
Alexander Couzens841817e2020-11-19 00:41:29 +0100561/*! Create a new bind for NS over FR.
562 * \param[in] nsi NS instance in which to create the bind
563 * \param[in] netif Network interface to bind to
564 * \param[in] fr_network
565 * \param[in] fr_role
566 * \param[out] result pointer to created bind
567 * \return 0 on success; negative on error */
568int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi,
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100569 const char *name,
Alexander Couzens841817e2020-11-19 00:41:29 +0100570 const char *netif,
571 struct osmo_fr_network *fr_network,
572 enum osmo_fr_role fr_role,
573 struct gprs_ns2_vc_bind **result)
574{
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100575 struct gprs_ns2_vc_bind *bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100576 struct priv_bind *priv;
577 struct osmo_fr_link *fr_link;
578 int rc = 0;
579
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100580 if (!name)
581 return -EINVAL;
582
583 if (gprs_ns2_bind_by_name(nsi, name))
584 return -EALREADY;
585
586 bind = talloc_zero(nsi, struct gprs_ns2_vc_bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100587 if (!bind)
588 return -ENOSPC;
589
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100590 bind->name = talloc_strdup(bind, name);
591 if (!bind->name) {
592 rc = -ENOSPC;
593 goto err_bind;
594 }
595
Alexander Couzens841817e2020-11-19 00:41:29 +0100596 bind->driver = &vc_driver_fr;
Alexander Couzensaac90162020-11-19 02:44:04 +0100597 bind->ll = GPRS_NS2_LL_FR;
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100598 /* 2 mbit */
599 bind->transfer_capability = 2;
Alexander Couzens841817e2020-11-19 00:41:29 +0100600 bind->send_vc = fr_vc_sendmsg;
601 bind->free_vc = free_vc;
602 bind->dump_vty = dump_vty;
603 bind->nsi = nsi;
604 priv = bind->priv = talloc_zero(bind, struct priv_bind);
605 if (!priv) {
606 rc = -ENOSPC;
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100607 goto err_name;
Alexander Couzens841817e2020-11-19 00:41:29 +0100608 }
609
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100610 if (strlen(netif) > IFNAMSIZ) {
Alexander Couzens841817e2020-11-19 00:41:29 +0100611 rc = -EINVAL;
612 goto err_priv;
613 }
Neels Hofmeyr8fef7612020-12-17 18:19:19 +0100614 OSMO_STRLCPY_ARRAY(priv->netif, netif);
Alexander Couzens841817e2020-11-19 00:41:29 +0100615
Alexander Couzens841817e2020-11-19 00:41:29 +0100616 if (result)
617 *result = bind;
618
619 /* FIXME: move fd handling into socket.c */
620 fr_link = osmo_fr_link_alloc(fr_network, fr_role, netif);
621 if (!fr_link) {
622 rc = -EINVAL;
623 goto err_priv;
624 }
625
626 fr_link->tx_cb = fr_tx_cb;
627 fr_link->tx_cb_data = bind;
628 priv->link = fr_link;
Harald Welte41b188b2020-12-10 22:00:23 +0100629
Alexander Couzens6f89c772020-12-17 03:06:39 +0100630 priv->ifindex = rc = devname2ifindex(netif);
631 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100632 LOGBIND(bind, LOGL_ERROR, "Can not get interface index for interface %s\n", netif);
Harald Welte41b188b2020-12-10 22:00:23 +0100633 goto err_fr;
634 }
635
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100636 /* set protocol frame relay and lmi */
Harald Weltef2949742021-01-20 14:54:14 +0100637 rc = setup_device(priv->netif, bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100638 if(rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100639 LOGBIND(bind, LOGL_ERROR, "Failed to setup the interface %s for frame relay and lmi\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100640 goto err_fr;
641 }
642
Harald Weltef2949742021-01-20 14:54:14 +0100643 rc = open_socket(priv->ifindex, bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100644 if (rc < 0)
645 goto err_fr;
Alexander Couzens60021a42020-12-17 02:48:22 +0100646 osmo_wqueue_init(&priv->wqueue, 10);
647 priv->wqueue.write_cb = handle_netif_write;
648 priv->wqueue.read_cb = handle_netif_read;
649 osmo_fd_setup(&priv->wqueue.bfd, rc, OSMO_FD_READ, osmo_wqueue_bfd_cb, bind, 0);
650 rc = osmo_fd_register(&priv->wqueue.bfd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100651 if (rc < 0)
652 goto err_fd;
653
654 INIT_LLIST_HEAD(&bind->nsvc);
655 llist_add(&bind->list, &nsi->binding);
656
Harald Welte56f08a32020-12-01 23:07:32 +0100657#ifdef ENABLE_LIBMNL
658 if (!nsi->linkmon_mnl)
659 nsi->linkmon_mnl = osmo_mnl_init(nsi, NETLINK_ROUTE, RTMGRP_LINK, linkmon_mnl_cb, nsi);
660
661 /* we get a new full dump after every bind. which is a bit excessive. But that's just once
662 * at start-up, so we can get away with it */
663 if (nsi->linkmon_mnl)
664 linkmon_initial_dump(nsi->linkmon_mnl);
665#endif
666
Alexander Couzens841817e2020-11-19 00:41:29 +0100667 return rc;
668
669err_fd:
Alexander Couzens60021a42020-12-17 02:48:22 +0100670 close(priv->wqueue.bfd.fd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100671err_fr:
672 osmo_fr_link_free(fr_link);
673err_priv:
674 talloc_free(priv);
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100675err_name:
676 talloc_free((char *)bind->name);
Alexander Couzens841817e2020-11-19 00:41:29 +0100677err_bind:
678 talloc_free(bind);
679
680 return rc;
681}
682
Alexander Couzensc782cec2020-12-10 04:10:25 +0100683/*! Return the frame relay role of a bind
684 * \param[in] bind The bind
685 * \return the frame relay role or -EINVAL if bind is not frame relay
686 */
687enum osmo_fr_role gprs_ns2_fr_bind_role(struct gprs_ns2_vc_bind *bind)
688{
689 struct priv_bind *priv;
690
691 if (bind->driver != &vc_driver_fr)
692 return -EINVAL;
693
694 priv = bind->priv;
695 return priv->link->role;
696}
697
Alexander Couzens841817e2020-11-19 00:41:29 +0100698/*! Return the network interface of the bind
699 * \param[in] bind The bind
700 * \return the network interface
701 */
702const char *gprs_ns2_fr_bind_netif(struct gprs_ns2_vc_bind *bind)
703{
704 struct priv_bind *priv;
705
706 if (bind->driver != &vc_driver_fr)
707 return NULL;
708
709 priv = bind->priv;
710 return priv->netif;
711}
712
713/*! Find NS bind for a given network interface
714 * \param[in] nsi NS instance
715 * \param[in] netif the network interface to search for
716 * \return the bind or NULL if not found
717 */
718struct gprs_ns2_vc_bind *gprs_ns2_fr_bind_by_netif(
719 struct gprs_ns2_inst *nsi,
720 const char *netif)
721{
722 struct gprs_ns2_vc_bind *bind;
723 const char *_netif;
724
725 OSMO_ASSERT(nsi);
726 OSMO_ASSERT(netif);
727
728 llist_for_each_entry(bind, &nsi->binding, list) {
729 if (!gprs_ns2_is_fr_bind(bind))
730 continue;
731
732 _netif = gprs_ns2_fr_bind_netif(bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100733 if (!strncmp(_netif, netif, IFNAMSIZ))
Alexander Couzens841817e2020-11-19 00:41:29 +0100734 return bind;
735 }
736
737 return NULL;
738}
739
740/*! Create, connect and activate a new FR-based NS-VC
741 * \param[in] bind bind in which the new NS-VC is to be created
742 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
743 * \param[in] dlci Data Link connection identifier
744 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
745struct gprs_ns2_vc *gprs_ns2_fr_connect(struct gprs_ns2_vc_bind *bind,
Alexander Couzensebcbd722020-12-03 06:11:39 +0100746 struct gprs_ns2_nse *nse,
747 uint16_t nsvci,
748 uint16_t dlci)
749{
750 struct gprs_ns2_vc *nsvc = NULL;
751 struct priv_vc *priv = NULL;
Harald Welte603f4042020-11-29 17:39:19 +0100752 struct priv_bind *bpriv = bind->priv;
753 char idbuf[64];
Alexander Couzensebcbd722020-12-03 06:11:39 +0100754
Alexander Couzens55bc8692021-01-18 18:39:57 +0100755 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzensebcbd722020-12-03 06:11:39 +0100756 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
757 if (nsvc) {
758 goto err;
759 }
760
Harald Welte603f4042020-11-29 17:39:19 +0100761 snprintf(idbuf, sizeof(idbuf), "%s-%s-DLCI%u-NSE%05u-NSVC%05u", gprs_ns2_lltype_str(nse->ll),
762 bpriv->netif, dlci, nse->nsei, nsvci);
Alexander Couzens138b96f2021-01-25 16:23:29 +0100763 nsvc = ns2_vc_alloc(bind, nse, true, GPRS_NS2_VC_MODE_BLOCKRESET, idbuf);
Alexander Couzensebcbd722020-12-03 06:11:39 +0100764 if (!nsvc)
765 goto err;
766
767 nsvc->priv = priv = fr_alloc_vc(bind, nsvc, dlci);
768 if (!priv)
769 goto err;
770
771 nsvc->nsvci = nsvci;
772 nsvc->nsvci_is_valid = true;
773
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100774 ns2_vc_fsm_start(nsvc);
Alexander Couzensebcbd722020-12-03 06:11:39 +0100775
776 return nsvc;
777
778err:
779 gprs_ns2_free_nsvc(nsvc);
780 return NULL;
781}
782
783
784/*! Create, connect and activate a new FR-based NS-VC
785 * \param[in] bind bind in which the new NS-VC is to be created
786 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
787 * \param[in] dlci Data Link connection identifier
788 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
789struct gprs_ns2_vc *gprs_ns2_fr_connect2(struct gprs_ns2_vc_bind *bind,
Alexander Couzens841817e2020-11-19 00:41:29 +0100790 uint16_t nsei,
791 uint16_t nsvci,
792 uint16_t dlci)
793{
794 bool created_nse = false;
795 struct gprs_ns2_vc *nsvc = NULL;
Alexander Couzens55bc8692021-01-18 18:39:57 +0100796 struct gprs_ns2_nse *nse;
797
798 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
799 nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei);
Alexander Couzens841817e2020-11-19 00:41:29 +0100800 if (!nse) {
Alexander Couzens138b96f2021-01-25 16:23:29 +0100801 nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_FR, GPRS_NS2_DIALECT_STATIC_RESETBLOCK);
Alexander Couzens841817e2020-11-19 00:41:29 +0100802 if (!nse)
803 return NULL;
804 created_nse = true;
805 }
806
Harald Welte509047b2021-01-17 19:55:51 +0100807 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
Alexander Couzens841817e2020-11-19 00:41:29 +0100808 if (!nsvc)
809 goto err_nse;
810
Alexander Couzens841817e2020-11-19 00:41:29 +0100811 return nsvc;
812
Alexander Couzens841817e2020-11-19 00:41:29 +0100813err_nse:
814 if (created_nse)
815 gprs_ns2_free_nse(nse);
816
817 return NULL;
818}
819
820/*! Return the nsvc by dlci.
821 * \param[in] bind
822 * \param[in] dlci Data Link connection identifier
823 * \return the nsvc or NULL if not found
824 */
825struct gprs_ns2_vc *gprs_ns2_fr_nsvc_by_dlci(struct gprs_ns2_vc_bind *bind,
826 uint16_t dlci)
827{
828 struct gprs_ns2_vc *nsvc;
829 struct priv_vc *vcpriv;
830
Alexander Couzens55bc8692021-01-18 18:39:57 +0100831 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100832 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
833 vcpriv = nsvc->priv;
834
835 if (dlci == vcpriv->dlci)
836 return nsvc;
837 }
838
839 return NULL;
840}
841
842/*! Return the dlci of the nsvc
843 * \param[in] nsvc
844 * \return the dlci or 0 on error. 0 is not a valid dlci.
845 */
Alexander Couzens22c26e02020-12-10 04:10:07 +0100846uint16_t gprs_ns2_fr_nsvc_dlci(const struct gprs_ns2_vc *nsvc)
Alexander Couzens841817e2020-11-19 00:41:29 +0100847{
848 struct priv_vc *vcpriv;
849
850 if (!nsvc->bind)
851 return 0;
852
853 if (nsvc->bind->driver != &vc_driver_fr)
854 return 0;
855
856 vcpriv = nsvc->priv;
857 return vcpriv->dlci;
858}