blob: 4bd9ff1154fd9e7a275074cd60e442e2135e9655 [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
Harald Welted06128d2021-01-30 21:17:21 +01007/* (C) 2009-2021 by Harald Welte <laforge@gnumonks.org>
Alexander Couzens841817e2020-11-19 00:41:29 +01008 * (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>
Harald Welted06128d2021-01-30 21:17:21 +010054#include <osmocom/core/timer.h>
Alexander Couzens841817e2020-11-19 00:41:29 +010055#include <osmocom/core/talloc.h>
56#include <osmocom/gprs/gprs_ns2.h>
Harald Welted06128d2021-01-30 21:17:21 +010057#include <osmocom/gprs/protocol/gsm_08_16.h>
58#include <osmocom/gprs/protocol/gsm_08_18.h>
Alexander Couzens841817e2020-11-19 00:41:29 +010059
Pau Espin Pedrold41800c2020-12-07 13:35:24 +010060#ifdef ENABLE_LIBMNL
61#include <osmocom/core/mnl.h>
62#endif
63
Harald Welte56f08a32020-12-01 23:07:32 +010064#include "config.h"
Alexander Couzens841817e2020-11-19 00:41:29 +010065#include "common_vty.h"
66#include "gprs_ns2_internal.h"
67
68#define GRE_PTYPE_FR 0x6559
69#define GRE_PTYPE_IPv4 0x0800
70#define GRE_PTYPE_IPv6 0x86dd
71#define GRE_PTYPE_KAR 0x0000 /* keepalive response */
72
73#ifndef IPPROTO_GRE
74# define IPPROTO_GRE 47
75#endif
76
Harald Welted06128d2021-01-30 21:17:21 +010077#define E1_LINERATE 2048000
78#define E1_SLOTS_TOTAL 32
79#define E1_SLOTS_USED 31
80/* usable bitrate of the E1 superchannel with 31 of 32 timeslots */
81#define SUPERCHANNEL_LINERATE (E1_LINERATE*E1_SLOTS_USED)/E1_SLOTS_TOTAL
82/* nanoseconds per bit (504) */
83#define BIT_DURATION_NS (1000000000 / SUPERCHANNEL_LINERATE)
84
Alexander Couzens841817e2020-11-19 00:41:29 +010085struct gre_hdr {
86 uint16_t flags;
87 uint16_t ptype;
88} __attribute__ ((packed));
89
90static void free_bind(struct gprs_ns2_vc_bind *bind);
91static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg);
92
93struct gprs_ns2_vc_driver vc_driver_fr = {
94 .name = "GB frame relay",
95 .free_bind = free_bind,
96};
97
98struct priv_bind {
Alexander Couzens5c96f5d2020-12-17 04:45:03 +010099 char netif[IFNAMSIZ];
Alexander Couzens841817e2020-11-19 00:41:29 +0100100 struct osmo_fr_link *link;
Harald Welte41b188b2020-12-10 22:00:23 +0100101 int ifindex;
Harald Welte56f08a32020-12-01 23:07:32 +0100102 bool if_running;
Harald Welted06128d2021-01-30 21:17:21 +0100103 /* backlog queue for AF_PACKET / ENOBUFS handling (see OS#4993) */
104 struct {
105 /* file-descriptor for AF_PACKET socket */
106 struct osmo_fd ofd;
107 /* list of msgb (backlog) */
108 struct llist_head list;
109 /* timer to trigger next attempt of AF_PACKET write */
110 struct osmo_timer_list timer;
111 /* re-try after that many micro-seconds */
112 uint32_t retry_us;
113 } backlog;
Alexander Couzens841817e2020-11-19 00:41:29 +0100114};
115
116struct priv_vc {
117 struct osmo_sockaddr remote;
118 uint16_t dlci;
119 struct osmo_fr_dlc *dlc;
120};
121
122static void free_vc(struct gprs_ns2_vc *nsvc)
123{
Alexander Couzensea377242021-01-17 16:51:55 +0100124 if (!nsvc)
125 return;
Alexander Couzens841817e2020-11-19 00:41:29 +0100126
127 if (!nsvc->priv)
128 return;
129
Alexander Couzens55bc8692021-01-18 18:39:57 +0100130 OSMO_ASSERT(gprs_ns2_is_fr_bind(nsvc->bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100131 talloc_free(nsvc->priv);
132 nsvc->priv = NULL;
133}
134
135static void dump_vty(const struct gprs_ns2_vc_bind *bind, struct vty *vty, bool _stats)
136{
137 struct priv_bind *priv;
138 struct gprs_ns2_vc *nsvc;
Harald Welte48bd76c2020-12-01 16:53:06 +0100139 struct osmo_fr_link *fr_link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100140
141 if (!bind)
142 return;
143
144 priv = bind->priv;
Harald Welte48bd76c2020-12-01 16:53:06 +0100145 fr_link = priv->link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100146
Harald Welte56f08a32020-12-01 23:07:32 +0100147 vty_out(vty, "FR bind: %s, role: %s, link: %s%s", priv->netif,
148 osmo_fr_role_str(fr_link->role), priv->if_running ? "UP" : "DOWN", VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +0100149
150 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
Harald Welte96ec84a2020-12-01 17:56:05 +0100151 vty_out(vty, " NSVCI %05u: %s%s", nsvc->nsvci, gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +0100152 }
153
154 priv = bind->priv;
155}
156
157/*! clean up all private driver state. Should be only called by gprs_ns2_free_bind() */
158static void free_bind(struct gprs_ns2_vc_bind *bind)
159{
160 struct priv_bind *priv;
Harald Welted06128d2021-01-30 21:17:21 +0100161 struct msgb *msg, *msg2;
Alexander Couzens841817e2020-11-19 00:41:29 +0100162
Alexander Couzens55bc8692021-01-18 18:39:57 +0100163 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100164 if (!bind)
165 return;
166
167 priv = bind->priv;
168
169 OSMO_ASSERT(llist_empty(&bind->nsvc));
170
Harald Welted06128d2021-01-30 21:17:21 +0100171 osmo_timer_del(&priv->backlog.timer);
172 llist_for_each_entry_safe(msg, msg2, &priv->backlog.list, list) {
173 msgb_free(msg);
174 }
175
Alexander Couzens841817e2020-11-19 00:41:29 +0100176 osmo_fr_link_free(priv->link);
Harald Welted06128d2021-01-30 21:17:21 +0100177 osmo_fd_close(&priv->backlog.ofd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100178 talloc_free(priv);
179}
180
181static struct priv_vc *fr_alloc_vc(struct gprs_ns2_vc_bind *bind,
182 struct gprs_ns2_vc *nsvc,
183 uint16_t dlci)
184{
185 struct priv_bind *privb = bind->priv;
186 struct priv_vc *priv = talloc_zero(bind, struct priv_vc);
187 if (!priv)
188 return NULL;
189
Alexander Couzens55bc8692021-01-18 18:39:57 +0100190 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100191 nsvc->priv = priv;
192 priv->dlci = dlci;
193 priv->dlc = osmo_fr_dlc_alloc(privb->link, dlci);
194 if (!priv->dlc) {
195 nsvc->priv = NULL;
196 talloc_free(priv);
197 return NULL;
198 }
199
200 priv->dlc->rx_cb_data = nsvc;
201 priv->dlc->rx_cb = fr_dlci_rx_cb;
202
203 return priv;
204}
205
206int gprs_ns2_find_vc_by_dlci(struct gprs_ns2_vc_bind *bind,
207 uint16_t dlci,
208 struct gprs_ns2_vc **result)
209{
210 struct gprs_ns2_vc *nsvc;
211 struct priv_vc *vcpriv;
212
Alexander Couzens55bc8692021-01-18 18:39:57 +0100213 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100214 if (!result)
215 return -EINVAL;
216
217 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
218 vcpriv = nsvc->priv;
219 if (vcpriv->dlci != dlci) {
220 *result = nsvc;
221 return 0;
222 }
223 }
224
225 return 1;
226}
227
228/* PDU from the network interface towards the fr layer (upwards) */
Harald Welted06128d2021-01-30 21:17:21 +0100229static int fr_netif_ofd_cb(struct osmo_fd *bfd, uint32_t what)
Alexander Couzens841817e2020-11-19 00:41:29 +0100230{
231 struct gprs_ns2_vc_bind *bind = bfd->data;
232 struct priv_bind *priv = bind->priv;
Harald Welted06128d2021-01-30 21:17:21 +0100233 struct msgb *msg;
Harald Welte41b188b2020-12-10 22:00:23 +0100234 struct sockaddr_ll sll;
235 socklen_t sll_len = sizeof(sll);
Alexander Couzens841817e2020-11-19 00:41:29 +0100236 int rc = 0;
237
Harald Welted06128d2021-01-30 21:17:21 +0100238 /* we only handle read here. write to AF_PACKET sockets cannot be triggered
239 * by select or poll, see OS#4995 */
240 if (!(what & OSMO_FD_READ))
241 return 0;
242
243 msg = msgb_alloc(NS_ALLOC_SIZE, "Gb/NS/FR/GRE Rx");
Alexander Couzens841817e2020-11-19 00:41:29 +0100244 if (!msg)
245 return -ENOMEM;
246
Harald Welte41b188b2020-12-10 22:00:23 +0100247 rc = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0, (struct sockaddr *)&sll, &sll_len);
Alexander Couzens841817e2020-11-19 00:41:29 +0100248 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100249 LOGBIND(bind, LOGL_ERROR, "recv error %s during NS-FR-GRE recv\n", strerror(errno));
Alexander Couzens841817e2020-11-19 00:41:29 +0100250 goto out_err;
251 } else if (rc == 0) {
252 goto out_err;
253 }
254
Harald Welte41b188b2020-12-10 22:00:23 +0100255 /* ignore any packets that we might have received for a different interface, between
256 * the socket() and the bind() call */
257 if (sll.sll_ifindex != priv->ifindex)
258 goto out_err;
259
Alexander Couzens841817e2020-11-19 00:41:29 +0100260 msgb_put(msg, rc);
261 msg->dst = priv->link;
262 return osmo_fr_rx(msg);
263
264out_err:
265 msgb_free(msg);
266 return rc;
267}
268
269/* PDU from the frame relay towards the NS-VC (upwards) */
270static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg)
271{
272 int rc;
273 struct gprs_ns2_vc *nsvc = cb_data;
274
275 rc = ns2_recv_vc(nsvc, msg);
276
277 return rc;
278}
279
Harald Welted06128d2021-01-30 21:17:21 +0100280static int fr_netif_write_one(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
Alexander Couzens841817e2020-11-19 00:41:29 +0100281{
Harald Welted06128d2021-01-30 21:17:21 +0100282 struct priv_bind *priv = bind->priv;
283 unsigned int len = msgb_length(msg);
Harald Weltef0073d72021-01-30 11:41:13 +0100284 int rc;
285
Harald Welted06128d2021-01-30 21:17:21 +0100286 /* estimate the retry time based on the data rate it takes to transmit */
287 priv->backlog.retry_us = (BIT_DURATION_NS * 8 * len) / 1000;
288
289 rc = write(priv->backlog.ofd.fd, msgb_data(msg), len);
290 if (rc == len) {
291 msgb_free(msg);
292 return 0;
293 } else if (rc < 0) {
294 /* don't free, the caller might want to re-transmit */
295 switch (errno) {
296 case EAGAIN:
297 case ENOBUFS:
298 return -errno;
299 default:
300 LOGBIND(bind, LOGL_ERROR, "error during write to AF_PACKET: %s\n", strerror(errno));
301 return -errno;
302 }
303 } else {
304 /* short write */
305 LOGBIND(bind, LOGL_ERROR, "short write on AF_PACKET: %d < %d\n", rc, len);
306 msgb_free(msg);
307 return 0;
308 }
Alexander Couzens841817e2020-11-19 00:41:29 +0100309}
310
311/*! determine if given bind is for FR-GRE encapsulation. */
312int gprs_ns2_is_fr_bind(struct gprs_ns2_vc_bind *bind)
313{
314 return (bind->driver == &vc_driver_fr);
315}
316
317/* PDU from the NS-VC towards the frame relay layer (downwards) */
318static int fr_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
319{
320 struct priv_vc *vcpriv = nsvc->priv;
321
322 msg->dst = vcpriv->dlc;
323 return osmo_fr_tx_dlc(msg);
324}
325
Harald Welted06128d2021-01-30 21:17:21 +0100326static void enqueue_at_head(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
327{
328 struct priv_bind *priv = bind->priv;
329 llist_add(&msg->list, &priv->backlog.list);
330 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
331}
332
333static void enqueue_at_tail(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
334{
335 struct priv_bind *priv = bind->priv;
336 llist_add_tail(&msg->list, &priv->backlog.list);
337 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
338}
339
340#define LMI_Q933A_DLCI 0
341
342/* enqueue to backlog (LMI, signaling) or drop (userdata msg) */
343static void backlog_enqueue_or_free(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
344{
345 uint8_t dlci = msg->data[0];
346 uint8_t ns_pdu_type;
347 uint16_t bvci;
348
349 if (msgb_length(msg) < 1)
350 goto out_free;
351
352 /* we want to enqueue only Q.933 LMI traffic or NS signaling; NOT user traffic */
353 switch (dlci) {
354 case LMI_Q933A_DLCI:
355 /* enqueue Q.933 LMI at head of queue */
356 enqueue_at_head(bind, msg);
357 return;
358 default:
359 if (msgb_length(msg) < 3)
360 break;
361 ns_pdu_type = msg->data[2];
362 switch (ns_pdu_type) {
363 case NS_PDUT_UNITDATA:
364 if (msgb_length(msg) < 6)
365 break;
366 bvci = osmo_load16be(msg->data + 4);
367 /* enqueue BVCI=0 traffic at tail of queue */
368 if (bvci == BVCI_SIGNALLING) {
369 enqueue_at_tail(bind, msg);
370 return;
371 }
372 break;
373 default:
374 /* enqueue NS signaling traffic at head of queue */
375 enqueue_at_head(bind, msg);
376 return;
377 }
378 break;
379 }
380
381out_free:
382 /* drop everything that is not LMI, NS-signaling or BVCI-0 */
383 msgb_free(msg);
384}
385
386static void fr_backlog_timer_cb(void *data)
387{
388 struct gprs_ns2_vc_bind *bind = data;
389 struct priv_bind *priv = bind->priv;
390 int i, rc;
391
392 /* attempt to send up to 10 messages in every timer */
393 for (i = 0; i < 10; i++) {
394 struct msgb *msg = msgb_dequeue(&priv->backlog.list);
395 if (!msg)
396 break;
397
398 rc = fr_netif_write_one(bind, msg);
399 if (rc < 0) {
400 /* re-add at head of list */
401 llist_add(&msg->list, &priv->backlog.list);
402 break;
403 }
404 }
405
406 /* re-start timer if we still have data in the queue */
407 if (!llist_empty(&priv->backlog.list))
408 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
409}
410
Alexander Couzens841817e2020-11-19 00:41:29 +0100411/* PDU from the frame relay layer towards the network interface (downwards) */
412int fr_tx_cb(void *data, struct msgb *msg)
413{
414 struct gprs_ns2_vc_bind *bind = data;
415 struct priv_bind *priv = bind->priv;
Harald Welted06128d2021-01-30 21:17:21 +0100416 int rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100417
Harald Welted06128d2021-01-30 21:17:21 +0100418 if (llist_empty(&priv->backlog.list)) {
419 /* attempt to transmit right now */
420 rc = fr_netif_write_one(bind, msg);
421 if (rc < 0) {
422 /* enqueue to backlog in case it fails */
423 backlog_enqueue_or_free(bind, msg);
424 }
425 } else {
426 /* enqueue to backlog */
427 backlog_enqueue_or_free(bind, msg);
Alexander Couzens60021a42020-12-17 02:48:22 +0100428 }
Alexander Couzens841817e2020-11-19 00:41:29 +0100429
Alexander Couzens60021a42020-12-17 02:48:22 +0100430 return 0;
Alexander Couzens841817e2020-11-19 00:41:29 +0100431}
432
433static int devname2ifindex(const char *ifname)
434{
435 struct ifreq ifr;
436 int sk, rc;
437
438 sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
439 if (sk < 0)
440 return sk;
441
442
443 memset(&ifr, 0, sizeof(ifr));
Neels Hofmeyr475a0ac2020-12-17 18:10:34 +0100444 OSMO_STRLCPY_ARRAY(ifr.ifr_name, ifname);
Alexander Couzens841817e2020-11-19 00:41:29 +0100445
446 rc = ioctl(sk, SIOCGIFINDEX, &ifr);
447 close(sk);
448 if (rc < 0)
449 return rc;
450
451 return ifr.ifr_ifindex;
452}
453
Harald Weltef2949742021-01-20 14:54:14 +0100454static int open_socket(int ifindex, const struct gprs_ns2_vc_bind *nsbind)
Alexander Couzens841817e2020-11-19 00:41:29 +0100455{
456 struct sockaddr_ll addr;
Harald Welte4ed0f4e2020-12-10 21:50:32 +0100457 int fd, rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100458
Alexander Couzens841817e2020-11-19 00:41:29 +0100459 memset(&addr, 0, sizeof(addr));
460 addr.sll_family = AF_PACKET;
461 addr.sll_protocol = htons(ETH_P_ALL);
462 addr.sll_ifindex = ifindex;
463
Harald Welte5bea72e2020-12-10 22:06:21 +0100464 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_HDLC));
Alexander Couzens841817e2020-11-19 00:41:29 +0100465 if (fd < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100466 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 +0100467 return fd;
468 }
469
Harald Welte41b188b2020-12-10 22:00:23 +0100470 /* there's a race condition between the above syscall and the bind() call below,
471 * causing other packets to be received in between */
472
Alexander Couzens841817e2020-11-19 00:41:29 +0100473 rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
474 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100475 LOGBIND(nsbind, LOGL_ERROR, "Can not bind AF_PACKET socket to ifindex %d\n", ifindex);
Alexander Couzens841817e2020-11-19 00:41:29 +0100476 close(fd);
477 return rc;
478 }
479
480 return fd;
481}
482
Harald Welte56f08a32020-12-01 23:07:32 +0100483#ifdef ENABLE_LIBMNL
484
485#include <osmocom/core/mnl.h>
Harald Welte56f08a32020-12-01 23:07:32 +0100486#include <linux/if_link.h>
487#include <linux/rtnetlink.h>
488
489#ifndef ARPHRD_FRAD
490#define ARPHRD_FRAD 770
491#endif
492
493/* validate the netlink attributes */
494static int data_attr_cb(const struct nlattr *attr, void *data)
495{
496 const struct nlattr **tb = data;
497 int type = mnl_attr_get_type(attr);
498
499 if (mnl_attr_type_valid(attr, IFLA_MAX) < 0)
500 return MNL_CB_OK;
501
502 switch (type) {
503 case IFLA_MTU:
504 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
505 return MNL_CB_ERROR;
506 break;
507 case IFLA_IFNAME:
508 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
509 return MNL_CB_ERROR;
510 break;
511 }
512 tb[type] = attr;
513 return MNL_CB_OK;
514}
515
516/* find the bind for the netdev (if any) */
517static struct gprs_ns2_vc_bind *bind4netdev(struct gprs_ns2_inst *nsi, const char *ifname)
518{
519 struct gprs_ns2_vc_bind *bind;
520
521 llist_for_each_entry(bind, &nsi->binding, list) {
522 struct priv_bind *bpriv = bind->priv;
523 if (!strcmp(bpriv->netif, ifname))
524 return bind;
525 }
526
527 return NULL;
528}
529
530/* handle a single netlink message received via libmnl */
531static int linkmon_mnl_cb(const struct nlmsghdr *nlh, void *data)
532{
533 struct osmo_mnl *omnl = data;
534 struct gprs_ns2_vc_bind *bind;
535 struct nlattr *tb[IFLA_MAX+1] = {};
536 struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh);
537 struct gprs_ns2_inst *nsi;
538 const char *ifname;
539 bool if_running;
540
541 OSMO_ASSERT(omnl);
542 OSMO_ASSERT(ifm);
543
544 nsi = omnl->priv;
545
546 if (ifm->ifi_type != ARPHRD_FRAD)
547 return MNL_CB_OK;
548
549 mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, tb);
550
551 if (!tb[IFLA_IFNAME])
552 return MNL_CB_OK;
553 ifname = mnl_attr_get_str(tb[IFLA_IFNAME]);
554 if_running = !!(ifm->ifi_flags & IFF_RUNNING);
555
556 bind = bind4netdev(nsi, ifname);
557 if (bind) {
558 struct priv_bind *bpriv = bind->priv;
559 if (bpriv->if_running != if_running) {
560 /* update running state */
Harald Weltef2949742021-01-20 14:54:14 +0100561 LOGBIND(bind, LOGL_NOTICE, "FR net-device '%s': Physical link state changed: %s\n",
562 ifname, if_running ? "UP" : "DOWN");
Harald Welte56f08a32020-12-01 23:07:32 +0100563 bpriv->if_running = if_running;
564 }
565 }
566
567 return MNL_CB_OK;
568}
569
570/* trigger one initial dump of all link information */
571static void linkmon_initial_dump(struct osmo_mnl *omnl)
572{
573 char buf[MNL_SOCKET_BUFFER_SIZE];
574 struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
575 struct rtgenmsg *rt;
576
577 nlh->nlmsg_type = RTM_GETLINK;
578 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
579 nlh->nlmsg_seq = time(NULL);
580 rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
581 rt->rtgen_family = AF_PACKET;
582
583 if (mnl_socket_sendto(omnl->mnls, nlh, nlh->nlmsg_len) < 0) {
584 LOGP(DLNS, LOGL_ERROR, "linkmon: Cannot send rtnetlink message: %s\n", strerror(errno));
585 }
586
587 /* the response[s] will be handled just like the events */
588}
589#endif /* LIBMNL */
590
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100591static int set_ifupdown(const char *netif, bool up)
592{
593 int sock, rc;
594 struct ifreq req;
595
596 sock = socket(AF_INET, SOCK_DGRAM, 0);
597 if (sock < 0)
598 return sock;
599
600 memset(&req, 0, sizeof req);
Harald Welte7f01b682020-12-21 12:39:38 +0100601 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100602
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100603 rc = ioctl(sock, SIOCGIFFLAGS, &req);
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100604 if (rc < 0) {
605 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100606 return rc;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100607 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100608
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100609 if ((req.ifr_flags & IFF_UP) == up) {
610 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100611 return 0;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100612 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100613
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100614 if (up)
615 req.ifr_flags |= IFF_UP;
616
617 rc = ioctl(sock, SIOCSIFFLAGS, &req);
618 close(sock);
619 return rc;
620}
621
Harald Weltef2949742021-01-20 14:54:14 +0100622static int setup_device(const char *netif, const struct gprs_ns2_vc_bind *bind)
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100623{
624 int sock, rc;
625 char buffer[128];
626 fr_proto *fr = (void*)buffer;
627 struct ifreq req;
628
629 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
630 if (sock < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100631 LOGBIND(bind, LOGL_ERROR, "%s: Unable to create socket: %s\n",
632 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100633 return sock;
634 }
635
636 memset(&req, 0, sizeof(struct ifreq));
637 memset(&buffer, 0, sizeof(buffer));
Harald Welteb8de1882020-12-21 12:40:45 +0100638 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100639 req.ifr_settings.ifs_ifsu.sync = (void*)buffer;
640 req.ifr_settings.size = sizeof(buffer);
641 req.ifr_settings.type = IF_GET_PROTO;
642
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100643 /* EINVAL is returned when no protocol has been set */
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100644 rc = ioctl(sock, SIOCWANDEV, &req);
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100645 if (rc < 0 && errno != EINVAL) {
Harald Weltef2949742021-01-20 14:54:14 +0100646 LOGBIND(bind, LOGL_ERROR, "%s: Unable to get FR protocol information: %s\n",
647 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100648 goto err;
649 }
650
651 /* check if the device is good */
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100652 if (rc == 0 && req.ifr_settings.type == IF_PROTO_FR && fr->lmi == LMI_NONE) {
Harald Weltef2949742021-01-20 14:54:14 +0100653 LOGBIND(bind, LOGL_NOTICE, "%s: has correct frame relay mode and lmi\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100654 goto ifup;
655 }
656
657 /* modify the device to match */
658 rc = set_ifupdown(netif, false);
659 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100660 LOGBIND(bind, LOGL_ERROR, "Unable to bring down the device %s: %s\n",
661 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100662 goto err;
663 }
664
665 memset(&req, 0, sizeof(struct ifreq));
666 memset(fr, 0, sizeof(fr_proto));
Harald Welteb8de1882020-12-21 12:40:45 +0100667 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100668 req.ifr_settings.type = IF_PROTO_FR;
669 req.ifr_settings.size = sizeof(fr_proto);
670 req.ifr_settings.ifs_ifsu.fr = fr;
671 fr->lmi = LMI_NONE;
672 /* even those settings aren't used, they must be in the range */
673 /* polling verification timer*/
674 fr->t391 = 10;
675 /* link integrity verification polling timer */
676 fr->t392 = 15;
677 /* full status polling counter*/
678 fr->n391 = 6;
679 /* error threshold */
680 fr->n392 = 3;
681 /* monitored events count */
682 fr->n393 = 4;
683
Harald Weltef2949742021-01-20 14:54:14 +0100684 LOGBIND(bind, LOGL_INFO, "%s: Setting frame relay related parameters\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100685 rc = ioctl(sock, SIOCWANDEV, &req);
686 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100687 LOGBIND(bind, LOGL_ERROR, "%s: Unable to set FR protocol on information: %s\n",
688 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100689 goto err;
690 }
691
692ifup:
693 rc = set_ifupdown(netif, true);
694 if (rc)
Harald Weltef2949742021-01-20 14:54:14 +0100695 LOGBIND(bind, LOGL_ERROR, "Unable to bring up the device %s: %s\n",
696 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100697err:
698 close(sock);
699 return rc;
700}
Harald Welte56f08a32020-12-01 23:07:32 +0100701
Alexander Couzens841817e2020-11-19 00:41:29 +0100702/*! Create a new bind for NS over FR.
703 * \param[in] nsi NS instance in which to create the bind
704 * \param[in] netif Network interface to bind to
705 * \param[in] fr_network
706 * \param[in] fr_role
707 * \param[out] result pointer to created bind
708 * \return 0 on success; negative on error */
709int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi,
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100710 const char *name,
Alexander Couzens841817e2020-11-19 00:41:29 +0100711 const char *netif,
712 struct osmo_fr_network *fr_network,
713 enum osmo_fr_role fr_role,
714 struct gprs_ns2_vc_bind **result)
715{
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100716 struct gprs_ns2_vc_bind *bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100717 struct priv_bind *priv;
718 struct osmo_fr_link *fr_link;
719 int rc = 0;
720
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100721 if (!name)
722 return -EINVAL;
723
724 if (gprs_ns2_bind_by_name(nsi, name))
725 return -EALREADY;
726
727 bind = talloc_zero(nsi, struct gprs_ns2_vc_bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100728 if (!bind)
729 return -ENOSPC;
730
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100731 bind->name = talloc_strdup(bind, name);
732 if (!bind->name) {
733 rc = -ENOSPC;
734 goto err_bind;
735 }
736
Alexander Couzens841817e2020-11-19 00:41:29 +0100737 bind->driver = &vc_driver_fr;
Alexander Couzensaac90162020-11-19 02:44:04 +0100738 bind->ll = GPRS_NS2_LL_FR;
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100739 /* 2 mbit */
740 bind->transfer_capability = 2;
Alexander Couzens841817e2020-11-19 00:41:29 +0100741 bind->send_vc = fr_vc_sendmsg;
742 bind->free_vc = free_vc;
743 bind->dump_vty = dump_vty;
744 bind->nsi = nsi;
745 priv = bind->priv = talloc_zero(bind, struct priv_bind);
746 if (!priv) {
747 rc = -ENOSPC;
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100748 goto err_name;
Alexander Couzens841817e2020-11-19 00:41:29 +0100749 }
750
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100751 if (strlen(netif) > IFNAMSIZ) {
Alexander Couzens841817e2020-11-19 00:41:29 +0100752 rc = -EINVAL;
753 goto err_priv;
754 }
Neels Hofmeyr8fef7612020-12-17 18:19:19 +0100755 OSMO_STRLCPY_ARRAY(priv->netif, netif);
Alexander Couzens841817e2020-11-19 00:41:29 +0100756
Alexander Couzens841817e2020-11-19 00:41:29 +0100757 if (result)
758 *result = bind;
759
760 /* FIXME: move fd handling into socket.c */
761 fr_link = osmo_fr_link_alloc(fr_network, fr_role, netif);
762 if (!fr_link) {
763 rc = -EINVAL;
764 goto err_priv;
765 }
766
767 fr_link->tx_cb = fr_tx_cb;
768 fr_link->tx_cb_data = bind;
769 priv->link = fr_link;
Harald Welte41b188b2020-12-10 22:00:23 +0100770
Alexander Couzens6f89c772020-12-17 03:06:39 +0100771 priv->ifindex = rc = devname2ifindex(netif);
772 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100773 LOGBIND(bind, LOGL_ERROR, "Can not get interface index for interface %s\n", netif);
Harald Welte41b188b2020-12-10 22:00:23 +0100774 goto err_fr;
775 }
776
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100777 /* set protocol frame relay and lmi */
Harald Weltef2949742021-01-20 14:54:14 +0100778 rc = setup_device(priv->netif, bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100779 if(rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100780 LOGBIND(bind, LOGL_ERROR, "Failed to setup the interface %s for frame relay and lmi\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100781 goto err_fr;
782 }
783
Harald Weltef2949742021-01-20 14:54:14 +0100784 rc = open_socket(priv->ifindex, bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100785 if (rc < 0)
786 goto err_fr;
Harald Welted06128d2021-01-30 21:17:21 +0100787 INIT_LLIST_HEAD(&priv->backlog.list);
788 priv->backlog.retry_us = 2500; /* start with some non-zero value; this corrsponds to 496 bytes */
789 osmo_timer_setup(&priv->backlog.timer, fr_backlog_timer_cb, bind);
790 osmo_fd_setup(&priv->backlog.ofd, rc, OSMO_FD_READ, fr_netif_ofd_cb, bind, 0);
791 rc = osmo_fd_register(&priv->backlog.ofd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100792 if (rc < 0)
793 goto err_fd;
794
795 INIT_LLIST_HEAD(&bind->nsvc);
796 llist_add(&bind->list, &nsi->binding);
797
Harald Welte56f08a32020-12-01 23:07:32 +0100798#ifdef ENABLE_LIBMNL
799 if (!nsi->linkmon_mnl)
800 nsi->linkmon_mnl = osmo_mnl_init(nsi, NETLINK_ROUTE, RTMGRP_LINK, linkmon_mnl_cb, nsi);
801
802 /* we get a new full dump after every bind. which is a bit excessive. But that's just once
803 * at start-up, so we can get away with it */
804 if (nsi->linkmon_mnl)
805 linkmon_initial_dump(nsi->linkmon_mnl);
806#endif
807
Alexander Couzens841817e2020-11-19 00:41:29 +0100808 return rc;
809
810err_fd:
Harald Welted06128d2021-01-30 21:17:21 +0100811 close(priv->backlog.ofd.fd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100812err_fr:
813 osmo_fr_link_free(fr_link);
814err_priv:
815 talloc_free(priv);
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100816err_name:
817 talloc_free((char *)bind->name);
Alexander Couzens841817e2020-11-19 00:41:29 +0100818err_bind:
819 talloc_free(bind);
820
821 return rc;
822}
823
Alexander Couzensc782cec2020-12-10 04:10:25 +0100824/*! Return the frame relay role of a bind
825 * \param[in] bind The bind
826 * \return the frame relay role or -EINVAL if bind is not frame relay
827 */
828enum osmo_fr_role gprs_ns2_fr_bind_role(struct gprs_ns2_vc_bind *bind)
829{
830 struct priv_bind *priv;
831
832 if (bind->driver != &vc_driver_fr)
833 return -EINVAL;
834
835 priv = bind->priv;
836 return priv->link->role;
837}
838
Alexander Couzens841817e2020-11-19 00:41:29 +0100839/*! Return the network interface of the bind
840 * \param[in] bind The bind
841 * \return the network interface
842 */
843const char *gprs_ns2_fr_bind_netif(struct gprs_ns2_vc_bind *bind)
844{
845 struct priv_bind *priv;
846
847 if (bind->driver != &vc_driver_fr)
848 return NULL;
849
850 priv = bind->priv;
851 return priv->netif;
852}
853
854/*! Find NS bind for a given network interface
855 * \param[in] nsi NS instance
856 * \param[in] netif the network interface to search for
857 * \return the bind or NULL if not found
858 */
859struct gprs_ns2_vc_bind *gprs_ns2_fr_bind_by_netif(
860 struct gprs_ns2_inst *nsi,
861 const char *netif)
862{
863 struct gprs_ns2_vc_bind *bind;
864 const char *_netif;
865
866 OSMO_ASSERT(nsi);
867 OSMO_ASSERT(netif);
868
869 llist_for_each_entry(bind, &nsi->binding, list) {
870 if (!gprs_ns2_is_fr_bind(bind))
871 continue;
872
873 _netif = gprs_ns2_fr_bind_netif(bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100874 if (!strncmp(_netif, netif, IFNAMSIZ))
Alexander Couzens841817e2020-11-19 00:41:29 +0100875 return bind;
876 }
877
878 return NULL;
879}
880
881/*! Create, connect and activate a new FR-based NS-VC
882 * \param[in] bind bind in which the new NS-VC is to be created
883 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
884 * \param[in] dlci Data Link connection identifier
885 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
886struct gprs_ns2_vc *gprs_ns2_fr_connect(struct gprs_ns2_vc_bind *bind,
Alexander Couzensebcbd722020-12-03 06:11:39 +0100887 struct gprs_ns2_nse *nse,
888 uint16_t nsvci,
889 uint16_t dlci)
890{
891 struct gprs_ns2_vc *nsvc = NULL;
892 struct priv_vc *priv = NULL;
Harald Welte603f4042020-11-29 17:39:19 +0100893 struct priv_bind *bpriv = bind->priv;
894 char idbuf[64];
Alexander Couzensebcbd722020-12-03 06:11:39 +0100895
Alexander Couzens55bc8692021-01-18 18:39:57 +0100896 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzensebcbd722020-12-03 06:11:39 +0100897 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
898 if (nsvc) {
899 goto err;
900 }
901
Harald Welte603f4042020-11-29 17:39:19 +0100902 snprintf(idbuf, sizeof(idbuf), "%s-%s-DLCI%u-NSE%05u-NSVC%05u", gprs_ns2_lltype_str(nse->ll),
903 bpriv->netif, dlci, nse->nsei, nsvci);
Alexander Couzens138b96f2021-01-25 16:23:29 +0100904 nsvc = ns2_vc_alloc(bind, nse, true, GPRS_NS2_VC_MODE_BLOCKRESET, idbuf);
Alexander Couzensebcbd722020-12-03 06:11:39 +0100905 if (!nsvc)
906 goto err;
907
908 nsvc->priv = priv = fr_alloc_vc(bind, nsvc, dlci);
909 if (!priv)
910 goto err;
911
912 nsvc->nsvci = nsvci;
913 nsvc->nsvci_is_valid = true;
914
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100915 ns2_vc_fsm_start(nsvc);
Alexander Couzensebcbd722020-12-03 06:11:39 +0100916
917 return nsvc;
918
919err:
920 gprs_ns2_free_nsvc(nsvc);
921 return NULL;
922}
923
924
925/*! Create, connect and activate a new FR-based NS-VC
926 * \param[in] bind bind in which the new NS-VC is to be created
927 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
928 * \param[in] dlci Data Link connection identifier
929 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
930struct gprs_ns2_vc *gprs_ns2_fr_connect2(struct gprs_ns2_vc_bind *bind,
Alexander Couzens841817e2020-11-19 00:41:29 +0100931 uint16_t nsei,
932 uint16_t nsvci,
933 uint16_t dlci)
934{
935 bool created_nse = false;
936 struct gprs_ns2_vc *nsvc = NULL;
Alexander Couzens55bc8692021-01-18 18:39:57 +0100937 struct gprs_ns2_nse *nse;
938
939 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
940 nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei);
Alexander Couzens841817e2020-11-19 00:41:29 +0100941 if (!nse) {
Alexander Couzens138b96f2021-01-25 16:23:29 +0100942 nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_FR, GPRS_NS2_DIALECT_STATIC_RESETBLOCK);
Alexander Couzens841817e2020-11-19 00:41:29 +0100943 if (!nse)
944 return NULL;
945 created_nse = true;
946 }
947
Harald Welte509047b2021-01-17 19:55:51 +0100948 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
Alexander Couzens841817e2020-11-19 00:41:29 +0100949 if (!nsvc)
950 goto err_nse;
951
Alexander Couzens841817e2020-11-19 00:41:29 +0100952 return nsvc;
953
Alexander Couzens841817e2020-11-19 00:41:29 +0100954err_nse:
955 if (created_nse)
956 gprs_ns2_free_nse(nse);
957
958 return NULL;
959}
960
961/*! Return the nsvc by dlci.
962 * \param[in] bind
963 * \param[in] dlci Data Link connection identifier
964 * \return the nsvc or NULL if not found
965 */
966struct gprs_ns2_vc *gprs_ns2_fr_nsvc_by_dlci(struct gprs_ns2_vc_bind *bind,
967 uint16_t dlci)
968{
969 struct gprs_ns2_vc *nsvc;
970 struct priv_vc *vcpriv;
971
Alexander Couzens55bc8692021-01-18 18:39:57 +0100972 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100973 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
974 vcpriv = nsvc->priv;
975
976 if (dlci == vcpriv->dlci)
977 return nsvc;
978 }
979
980 return NULL;
981}
982
983/*! Return the dlci of the nsvc
984 * \param[in] nsvc
985 * \return the dlci or 0 on error. 0 is not a valid dlci.
986 */
Alexander Couzens22c26e02020-12-10 04:10:07 +0100987uint16_t gprs_ns2_fr_nsvc_dlci(const struct gprs_ns2_vc *nsvc)
Alexander Couzens841817e2020-11-19 00:41:29 +0100988{
989 struct priv_vc *vcpriv;
990
991 if (!nsvc->bind)
992 return 0;
993
994 if (nsvc->bind->driver != &vc_driver_fr)
995 return 0;
996
997 vcpriv = nsvc->priv;
998 return vcpriv->dlci;
999}