blob: 953f4cad58240cdc93d7331926980c2c36979c2b [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) */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100343static int backlog_enqueue_or_free(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
Harald Welted06128d2021-01-30 21:17:21 +0100344{
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);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100357 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100358 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);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100370 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100371 }
372 break;
373 default:
374 /* enqueue NS signaling traffic at head of queue */
375 enqueue_at_head(bind, msg);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100376 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100377 }
378 break;
379 }
380
381out_free:
382 /* drop everything that is not LMI, NS-signaling or BVCI-0 */
383 msgb_free(msg);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100384 return -1;
Harald Welted06128d2021-01-30 21:17:21 +0100385}
386
387static void fr_backlog_timer_cb(void *data)
388{
389 struct gprs_ns2_vc_bind *bind = data;
390 struct priv_bind *priv = bind->priv;
391 int i, rc;
392
393 /* attempt to send up to 10 messages in every timer */
394 for (i = 0; i < 10; i++) {
395 struct msgb *msg = msgb_dequeue(&priv->backlog.list);
396 if (!msg)
397 break;
398
399 rc = fr_netif_write_one(bind, msg);
400 if (rc < 0) {
401 /* re-add at head of list */
402 llist_add(&msg->list, &priv->backlog.list);
403 break;
404 }
405 }
406
407 /* re-start timer if we still have data in the queue */
408 if (!llist_empty(&priv->backlog.list))
409 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
410}
411
Alexander Couzens841817e2020-11-19 00:41:29 +0100412/* PDU from the frame relay layer towards the network interface (downwards) */
413int fr_tx_cb(void *data, struct msgb *msg)
414{
415 struct gprs_ns2_vc_bind *bind = data;
416 struct priv_bind *priv = bind->priv;
Harald Welted06128d2021-01-30 21:17:21 +0100417 int rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100418
Harald Welted06128d2021-01-30 21:17:21 +0100419 if (llist_empty(&priv->backlog.list)) {
420 /* attempt to transmit right now */
421 rc = fr_netif_write_one(bind, msg);
422 if (rc < 0) {
423 /* enqueue to backlog in case it fails */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100424 return backlog_enqueue_or_free(bind, msg);
Harald Welted06128d2021-01-30 21:17:21 +0100425 }
426 } else {
427 /* enqueue to backlog */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100428 return backlog_enqueue_or_free(bind, msg);
Alexander Couzens60021a42020-12-17 02:48:22 +0100429 }
Alexander Couzens841817e2020-11-19 00:41:29 +0100430
Alexander Couzens60021a42020-12-17 02:48:22 +0100431 return 0;
Alexander Couzens841817e2020-11-19 00:41:29 +0100432}
433
434static int devname2ifindex(const char *ifname)
435{
436 struct ifreq ifr;
437 int sk, rc;
438
439 sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
440 if (sk < 0)
441 return sk;
442
443
444 memset(&ifr, 0, sizeof(ifr));
Neels Hofmeyr475a0ac2020-12-17 18:10:34 +0100445 OSMO_STRLCPY_ARRAY(ifr.ifr_name, ifname);
Alexander Couzens841817e2020-11-19 00:41:29 +0100446
447 rc = ioctl(sk, SIOCGIFINDEX, &ifr);
448 close(sk);
449 if (rc < 0)
450 return rc;
451
452 return ifr.ifr_ifindex;
453}
454
Harald Weltef2949742021-01-20 14:54:14 +0100455static int open_socket(int ifindex, const struct gprs_ns2_vc_bind *nsbind)
Alexander Couzens841817e2020-11-19 00:41:29 +0100456{
457 struct sockaddr_ll addr;
Harald Welte4ed0f4e2020-12-10 21:50:32 +0100458 int fd, rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100459
Alexander Couzens841817e2020-11-19 00:41:29 +0100460 memset(&addr, 0, sizeof(addr));
461 addr.sll_family = AF_PACKET;
462 addr.sll_protocol = htons(ETH_P_ALL);
463 addr.sll_ifindex = ifindex;
464
Harald Welte5bea72e2020-12-10 22:06:21 +0100465 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_HDLC));
Alexander Couzens841817e2020-11-19 00:41:29 +0100466 if (fd < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100467 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 +0100468 return fd;
469 }
470
Harald Welte41b188b2020-12-10 22:00:23 +0100471 /* there's a race condition between the above syscall and the bind() call below,
472 * causing other packets to be received in between */
473
Alexander Couzens841817e2020-11-19 00:41:29 +0100474 rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
475 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100476 LOGBIND(nsbind, LOGL_ERROR, "Can not bind AF_PACKET socket to ifindex %d\n", ifindex);
Alexander Couzens841817e2020-11-19 00:41:29 +0100477 close(fd);
478 return rc;
479 }
480
481 return fd;
482}
483
Harald Welte56f08a32020-12-01 23:07:32 +0100484#ifdef ENABLE_LIBMNL
485
486#include <osmocom/core/mnl.h>
Harald Welte56f08a32020-12-01 23:07:32 +0100487#include <linux/if_link.h>
488#include <linux/rtnetlink.h>
489
490#ifndef ARPHRD_FRAD
491#define ARPHRD_FRAD 770
492#endif
493
494/* validate the netlink attributes */
495static int data_attr_cb(const struct nlattr *attr, void *data)
496{
497 const struct nlattr **tb = data;
498 int type = mnl_attr_get_type(attr);
499
500 if (mnl_attr_type_valid(attr, IFLA_MAX) < 0)
501 return MNL_CB_OK;
502
503 switch (type) {
504 case IFLA_MTU:
505 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
506 return MNL_CB_ERROR;
507 break;
508 case IFLA_IFNAME:
509 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
510 return MNL_CB_ERROR;
511 break;
512 }
513 tb[type] = attr;
514 return MNL_CB_OK;
515}
516
517/* find the bind for the netdev (if any) */
518static struct gprs_ns2_vc_bind *bind4netdev(struct gprs_ns2_inst *nsi, const char *ifname)
519{
520 struct gprs_ns2_vc_bind *bind;
521
522 llist_for_each_entry(bind, &nsi->binding, list) {
523 struct priv_bind *bpriv = bind->priv;
524 if (!strcmp(bpriv->netif, ifname))
525 return bind;
526 }
527
528 return NULL;
529}
530
531/* handle a single netlink message received via libmnl */
532static int linkmon_mnl_cb(const struct nlmsghdr *nlh, void *data)
533{
534 struct osmo_mnl *omnl = data;
535 struct gprs_ns2_vc_bind *bind;
536 struct nlattr *tb[IFLA_MAX+1] = {};
537 struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh);
538 struct gprs_ns2_inst *nsi;
539 const char *ifname;
540 bool if_running;
541
542 OSMO_ASSERT(omnl);
543 OSMO_ASSERT(ifm);
544
545 nsi = omnl->priv;
546
547 if (ifm->ifi_type != ARPHRD_FRAD)
548 return MNL_CB_OK;
549
550 mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, tb);
551
552 if (!tb[IFLA_IFNAME])
553 return MNL_CB_OK;
554 ifname = mnl_attr_get_str(tb[IFLA_IFNAME]);
555 if_running = !!(ifm->ifi_flags & IFF_RUNNING);
556
557 bind = bind4netdev(nsi, ifname);
558 if (bind) {
559 struct priv_bind *bpriv = bind->priv;
560 if (bpriv->if_running != if_running) {
561 /* update running state */
Harald Weltef2949742021-01-20 14:54:14 +0100562 LOGBIND(bind, LOGL_NOTICE, "FR net-device '%s': Physical link state changed: %s\n",
563 ifname, if_running ? "UP" : "DOWN");
Harald Welte56f08a32020-12-01 23:07:32 +0100564 bpriv->if_running = if_running;
565 }
566 }
567
568 return MNL_CB_OK;
569}
570
571/* trigger one initial dump of all link information */
572static void linkmon_initial_dump(struct osmo_mnl *omnl)
573{
574 char buf[MNL_SOCKET_BUFFER_SIZE];
575 struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
576 struct rtgenmsg *rt;
577
578 nlh->nlmsg_type = RTM_GETLINK;
579 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
580 nlh->nlmsg_seq = time(NULL);
581 rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
582 rt->rtgen_family = AF_PACKET;
583
584 if (mnl_socket_sendto(omnl->mnls, nlh, nlh->nlmsg_len) < 0) {
585 LOGP(DLNS, LOGL_ERROR, "linkmon: Cannot send rtnetlink message: %s\n", strerror(errno));
586 }
587
588 /* the response[s] will be handled just like the events */
589}
590#endif /* LIBMNL */
591
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100592static int set_ifupdown(const char *netif, bool up)
593{
594 int sock, rc;
595 struct ifreq req;
596
597 sock = socket(AF_INET, SOCK_DGRAM, 0);
598 if (sock < 0)
599 return sock;
600
601 memset(&req, 0, sizeof req);
Harald Welte7f01b682020-12-21 12:39:38 +0100602 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100603
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100604 rc = ioctl(sock, SIOCGIFFLAGS, &req);
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100605 if (rc < 0) {
606 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100607 return rc;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100608 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100609
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100610 if ((req.ifr_flags & IFF_UP) == up) {
611 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100612 return 0;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100613 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100614
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100615 if (up)
616 req.ifr_flags |= IFF_UP;
617
618 rc = ioctl(sock, SIOCSIFFLAGS, &req);
619 close(sock);
620 return rc;
621}
622
Harald Weltef2949742021-01-20 14:54:14 +0100623static int setup_device(const char *netif, const struct gprs_ns2_vc_bind *bind)
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100624{
625 int sock, rc;
626 char buffer[128];
627 fr_proto *fr = (void*)buffer;
628 struct ifreq req;
629
630 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
631 if (sock < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100632 LOGBIND(bind, LOGL_ERROR, "%s: Unable to create socket: %s\n",
633 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100634 return sock;
635 }
636
637 memset(&req, 0, sizeof(struct ifreq));
638 memset(&buffer, 0, sizeof(buffer));
Harald Welteb8de1882020-12-21 12:40:45 +0100639 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100640 req.ifr_settings.ifs_ifsu.sync = (void*)buffer;
641 req.ifr_settings.size = sizeof(buffer);
642 req.ifr_settings.type = IF_GET_PROTO;
643
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100644 /* EINVAL is returned when no protocol has been set */
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100645 rc = ioctl(sock, SIOCWANDEV, &req);
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100646 if (rc < 0 && errno != EINVAL) {
Harald Weltef2949742021-01-20 14:54:14 +0100647 LOGBIND(bind, LOGL_ERROR, "%s: Unable to get FR protocol information: %s\n",
648 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100649 goto err;
650 }
651
652 /* check if the device is good */
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100653 if (rc == 0 && req.ifr_settings.type == IF_PROTO_FR && fr->lmi == LMI_NONE) {
Harald Weltef2949742021-01-20 14:54:14 +0100654 LOGBIND(bind, LOGL_NOTICE, "%s: has correct frame relay mode and lmi\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100655 goto ifup;
656 }
657
658 /* modify the device to match */
659 rc = set_ifupdown(netif, false);
660 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100661 LOGBIND(bind, LOGL_ERROR, "Unable to bring down the device %s: %s\n",
662 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100663 goto err;
664 }
665
666 memset(&req, 0, sizeof(struct ifreq));
667 memset(fr, 0, sizeof(fr_proto));
Harald Welteb8de1882020-12-21 12:40:45 +0100668 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100669 req.ifr_settings.type = IF_PROTO_FR;
670 req.ifr_settings.size = sizeof(fr_proto);
671 req.ifr_settings.ifs_ifsu.fr = fr;
672 fr->lmi = LMI_NONE;
673 /* even those settings aren't used, they must be in the range */
674 /* polling verification timer*/
675 fr->t391 = 10;
676 /* link integrity verification polling timer */
677 fr->t392 = 15;
678 /* full status polling counter*/
679 fr->n391 = 6;
680 /* error threshold */
681 fr->n392 = 3;
682 /* monitored events count */
683 fr->n393 = 4;
684
Harald Weltef2949742021-01-20 14:54:14 +0100685 LOGBIND(bind, LOGL_INFO, "%s: Setting frame relay related parameters\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100686 rc = ioctl(sock, SIOCWANDEV, &req);
687 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100688 LOGBIND(bind, LOGL_ERROR, "%s: Unable to set FR protocol on information: %s\n",
689 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100690 goto err;
691 }
692
693ifup:
694 rc = set_ifupdown(netif, true);
695 if (rc)
Harald Weltef2949742021-01-20 14:54:14 +0100696 LOGBIND(bind, LOGL_ERROR, "Unable to bring up the device %s: %s\n",
697 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100698err:
699 close(sock);
700 return rc;
701}
Harald Welte56f08a32020-12-01 23:07:32 +0100702
Alexander Couzens841817e2020-11-19 00:41:29 +0100703/*! Create a new bind for NS over FR.
704 * \param[in] nsi NS instance in which to create the bind
705 * \param[in] netif Network interface to bind to
706 * \param[in] fr_network
707 * \param[in] fr_role
708 * \param[out] result pointer to created bind
709 * \return 0 on success; negative on error */
710int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi,
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100711 const char *name,
Alexander Couzens841817e2020-11-19 00:41:29 +0100712 const char *netif,
713 struct osmo_fr_network *fr_network,
714 enum osmo_fr_role fr_role,
715 struct gprs_ns2_vc_bind **result)
716{
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100717 struct gprs_ns2_vc_bind *bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100718 struct priv_bind *priv;
719 struct osmo_fr_link *fr_link;
720 int rc = 0;
721
Harald Weltec3aa8f92021-01-31 11:41:34 +0100722 if (strlen(netif) > IFNAMSIZ)
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100723 return -EINVAL;
724
725 if (gprs_ns2_bind_by_name(nsi, name))
726 return -EALREADY;
727
Harald Weltec3aa8f92021-01-31 11:41:34 +0100728 rc = ns2_bind_alloc(nsi, name, &bind);
729 if (rc < 0)
730 return rc;
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100731
Alexander Couzens841817e2020-11-19 00:41:29 +0100732 bind->driver = &vc_driver_fr;
Alexander Couzensaac90162020-11-19 02:44:04 +0100733 bind->ll = GPRS_NS2_LL_FR;
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100734 /* 2 mbit */
735 bind->transfer_capability = 2;
Alexander Couzens841817e2020-11-19 00:41:29 +0100736 bind->send_vc = fr_vc_sendmsg;
737 bind->free_vc = free_vc;
738 bind->dump_vty = dump_vty;
Alexander Couzens841817e2020-11-19 00:41:29 +0100739 priv = bind->priv = talloc_zero(bind, struct priv_bind);
740 if (!priv) {
741 rc = -ENOSPC;
Harald Weltec3aa8f92021-01-31 11:41:34 +0100742 goto err_bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100743 }
744
Neels Hofmeyr8fef7612020-12-17 18:19:19 +0100745 OSMO_STRLCPY_ARRAY(priv->netif, netif);
Alexander Couzens841817e2020-11-19 00:41:29 +0100746
Alexander Couzens841817e2020-11-19 00:41:29 +0100747 /* FIXME: move fd handling into socket.c */
748 fr_link = osmo_fr_link_alloc(fr_network, fr_role, netif);
749 if (!fr_link) {
750 rc = -EINVAL;
Harald Weltec3aa8f92021-01-31 11:41:34 +0100751 goto err_bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100752 }
753
754 fr_link->tx_cb = fr_tx_cb;
755 fr_link->tx_cb_data = bind;
756 priv->link = fr_link;
Harald Welte41b188b2020-12-10 22:00:23 +0100757
Alexander Couzens6f89c772020-12-17 03:06:39 +0100758 priv->ifindex = rc = devname2ifindex(netif);
759 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100760 LOGBIND(bind, LOGL_ERROR, "Can not get interface index for interface %s\n", netif);
Harald Welte41b188b2020-12-10 22:00:23 +0100761 goto err_fr;
762 }
763
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100764 /* set protocol frame relay and lmi */
Harald Weltef2949742021-01-20 14:54:14 +0100765 rc = setup_device(priv->netif, bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100766 if(rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100767 LOGBIND(bind, LOGL_ERROR, "Failed to setup the interface %s for frame relay and lmi\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100768 goto err_fr;
769 }
770
Harald Weltef2949742021-01-20 14:54:14 +0100771 rc = open_socket(priv->ifindex, bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100772 if (rc < 0)
773 goto err_fr;
Harald Welted06128d2021-01-30 21:17:21 +0100774 INIT_LLIST_HEAD(&priv->backlog.list);
775 priv->backlog.retry_us = 2500; /* start with some non-zero value; this corrsponds to 496 bytes */
776 osmo_timer_setup(&priv->backlog.timer, fr_backlog_timer_cb, bind);
777 osmo_fd_setup(&priv->backlog.ofd, rc, OSMO_FD_READ, fr_netif_ofd_cb, bind, 0);
778 rc = osmo_fd_register(&priv->backlog.ofd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100779 if (rc < 0)
780 goto err_fd;
781
Harald Welte56f08a32020-12-01 23:07:32 +0100782#ifdef ENABLE_LIBMNL
783 if (!nsi->linkmon_mnl)
784 nsi->linkmon_mnl = osmo_mnl_init(nsi, NETLINK_ROUTE, RTMGRP_LINK, linkmon_mnl_cb, nsi);
785
786 /* we get a new full dump after every bind. which is a bit excessive. But that's just once
787 * at start-up, so we can get away with it */
788 if (nsi->linkmon_mnl)
789 linkmon_initial_dump(nsi->linkmon_mnl);
790#endif
791
Harald Weltec3aa8f92021-01-31 11:41:34 +0100792 if (result)
793 *result = bind;
794
Alexander Couzens841817e2020-11-19 00:41:29 +0100795 return rc;
796
797err_fd:
Harald Welted06128d2021-01-30 21:17:21 +0100798 close(priv->backlog.ofd.fd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100799err_fr:
800 osmo_fr_link_free(fr_link);
Alexander Couzens841817e2020-11-19 00:41:29 +0100801err_bind:
Harald Weltec3aa8f92021-01-31 11:41:34 +0100802 gprs_ns2_free_bind(bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100803
804 return rc;
805}
806
Alexander Couzensc782cec2020-12-10 04:10:25 +0100807/*! Return the frame relay role of a bind
808 * \param[in] bind The bind
809 * \return the frame relay role or -EINVAL if bind is not frame relay
810 */
811enum osmo_fr_role gprs_ns2_fr_bind_role(struct gprs_ns2_vc_bind *bind)
812{
813 struct priv_bind *priv;
814
815 if (bind->driver != &vc_driver_fr)
816 return -EINVAL;
817
818 priv = bind->priv;
819 return priv->link->role;
820}
821
Alexander Couzens841817e2020-11-19 00:41:29 +0100822/*! Return the network interface of the bind
823 * \param[in] bind The bind
824 * \return the network interface
825 */
826const char *gprs_ns2_fr_bind_netif(struct gprs_ns2_vc_bind *bind)
827{
828 struct priv_bind *priv;
829
830 if (bind->driver != &vc_driver_fr)
831 return NULL;
832
833 priv = bind->priv;
834 return priv->netif;
835}
836
837/*! Find NS bind for a given network interface
838 * \param[in] nsi NS instance
839 * \param[in] netif the network interface to search for
840 * \return the bind or NULL if not found
841 */
842struct gprs_ns2_vc_bind *gprs_ns2_fr_bind_by_netif(
843 struct gprs_ns2_inst *nsi,
844 const char *netif)
845{
846 struct gprs_ns2_vc_bind *bind;
847 const char *_netif;
848
849 OSMO_ASSERT(nsi);
850 OSMO_ASSERT(netif);
851
852 llist_for_each_entry(bind, &nsi->binding, list) {
853 if (!gprs_ns2_is_fr_bind(bind))
854 continue;
855
856 _netif = gprs_ns2_fr_bind_netif(bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100857 if (!strncmp(_netif, netif, IFNAMSIZ))
Alexander Couzens841817e2020-11-19 00:41:29 +0100858 return bind;
859 }
860
861 return NULL;
862}
863
864/*! Create, connect and activate a new FR-based NS-VC
865 * \param[in] bind bind in which the new NS-VC is to be created
866 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
867 * \param[in] dlci Data Link connection identifier
868 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
869struct gprs_ns2_vc *gprs_ns2_fr_connect(struct gprs_ns2_vc_bind *bind,
Alexander Couzensebcbd722020-12-03 06:11:39 +0100870 struct gprs_ns2_nse *nse,
871 uint16_t nsvci,
872 uint16_t dlci)
873{
874 struct gprs_ns2_vc *nsvc = NULL;
875 struct priv_vc *priv = NULL;
Harald Welte603f4042020-11-29 17:39:19 +0100876 struct priv_bind *bpriv = bind->priv;
877 char idbuf[64];
Alexander Couzensebcbd722020-12-03 06:11:39 +0100878
Alexander Couzens55bc8692021-01-18 18:39:57 +0100879 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzensebcbd722020-12-03 06:11:39 +0100880 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
881 if (nsvc) {
882 goto err;
883 }
884
Harald Welte603f4042020-11-29 17:39:19 +0100885 snprintf(idbuf, sizeof(idbuf), "%s-%s-DLCI%u-NSE%05u-NSVC%05u", gprs_ns2_lltype_str(nse->ll),
886 bpriv->netif, dlci, nse->nsei, nsvci);
Alexander Couzens138b96f2021-01-25 16:23:29 +0100887 nsvc = ns2_vc_alloc(bind, nse, true, GPRS_NS2_VC_MODE_BLOCKRESET, idbuf);
Alexander Couzensebcbd722020-12-03 06:11:39 +0100888 if (!nsvc)
889 goto err;
890
891 nsvc->priv = priv = fr_alloc_vc(bind, nsvc, dlci);
892 if (!priv)
893 goto err;
894
895 nsvc->nsvci = nsvci;
896 nsvc->nsvci_is_valid = true;
897
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100898 ns2_vc_fsm_start(nsvc);
Alexander Couzensebcbd722020-12-03 06:11:39 +0100899
900 return nsvc;
901
902err:
903 gprs_ns2_free_nsvc(nsvc);
904 return NULL;
905}
906
907
908/*! Create, connect and activate a new FR-based NS-VC
909 * \param[in] bind bind in which the new NS-VC is to be created
910 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
911 * \param[in] dlci Data Link connection identifier
912 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
913struct gprs_ns2_vc *gprs_ns2_fr_connect2(struct gprs_ns2_vc_bind *bind,
Alexander Couzens841817e2020-11-19 00:41:29 +0100914 uint16_t nsei,
915 uint16_t nsvci,
916 uint16_t dlci)
917{
918 bool created_nse = false;
919 struct gprs_ns2_vc *nsvc = NULL;
Alexander Couzens55bc8692021-01-18 18:39:57 +0100920 struct gprs_ns2_nse *nse;
921
922 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
923 nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei);
Alexander Couzens841817e2020-11-19 00:41:29 +0100924 if (!nse) {
Alexander Couzens138b96f2021-01-25 16:23:29 +0100925 nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_FR, GPRS_NS2_DIALECT_STATIC_RESETBLOCK);
Alexander Couzens841817e2020-11-19 00:41:29 +0100926 if (!nse)
927 return NULL;
928 created_nse = true;
929 }
930
Harald Welte509047b2021-01-17 19:55:51 +0100931 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
Alexander Couzens841817e2020-11-19 00:41:29 +0100932 if (!nsvc)
933 goto err_nse;
934
Alexander Couzens841817e2020-11-19 00:41:29 +0100935 return nsvc;
936
Alexander Couzens841817e2020-11-19 00:41:29 +0100937err_nse:
938 if (created_nse)
939 gprs_ns2_free_nse(nse);
940
941 return NULL;
942}
943
944/*! Return the nsvc by dlci.
945 * \param[in] bind
946 * \param[in] dlci Data Link connection identifier
947 * \return the nsvc or NULL if not found
948 */
949struct gprs_ns2_vc *gprs_ns2_fr_nsvc_by_dlci(struct gprs_ns2_vc_bind *bind,
950 uint16_t dlci)
951{
952 struct gprs_ns2_vc *nsvc;
953 struct priv_vc *vcpriv;
954
Alexander Couzens55bc8692021-01-18 18:39:57 +0100955 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100956 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
957 vcpriv = nsvc->priv;
958
959 if (dlci == vcpriv->dlci)
960 return nsvc;
961 }
962
963 return NULL;
964}
965
966/*! Return the dlci of the nsvc
967 * \param[in] nsvc
968 * \return the dlci or 0 on error. 0 is not a valid dlci.
969 */
Alexander Couzens22c26e02020-12-10 04:10:07 +0100970uint16_t gprs_ns2_fr_nsvc_dlci(const struct gprs_ns2_vc *nsvc)
Alexander Couzens841817e2020-11-19 00:41:29 +0100971{
972 struct priv_vc *vcpriv;
973
974 if (!nsvc->bind)
975 return 0;
976
977 if (nsvc->bind->driver != &vc_driver_fr)
978 return 0;
979
980 vcpriv = nsvc->priv;
981 return vcpriv->dlci;
982}