blob: f85b1e47a09361616b4f13a3c6bfe26c523245c1 [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>
Harald Welte76346072021-01-31 11:54:02 +010050#include <osmocom/core/stat_item.h>
Alexander Couzens841817e2020-11-19 00:41:29 +010051#include <osmocom/core/logging.h>
52#include <osmocom/core/msgb.h>
53#include <osmocom/core/select.h>
54#include <osmocom/core/socket.h>
Harald Welted06128d2021-01-30 21:17:21 +010055#include <osmocom/core/timer.h>
Alexander Couzens841817e2020-11-19 00:41:29 +010056#include <osmocom/core/talloc.h>
57#include <osmocom/gprs/gprs_ns2.h>
Harald Welted06128d2021-01-30 21:17:21 +010058#include <osmocom/gprs/protocol/gsm_08_16.h>
59#include <osmocom/gprs/protocol/gsm_08_18.h>
Alexander Couzens841817e2020-11-19 00:41:29 +010060
Pau Espin Pedrold41800c2020-12-07 13:35:24 +010061#ifdef ENABLE_LIBMNL
62#include <osmocom/core/mnl.h>
63#endif
64
Harald Welte56f08a32020-12-01 23:07:32 +010065#include "config.h"
Alexander Couzens841817e2020-11-19 00:41:29 +010066#include "common_vty.h"
67#include "gprs_ns2_internal.h"
68
69#define GRE_PTYPE_FR 0x6559
70#define GRE_PTYPE_IPv4 0x0800
71#define GRE_PTYPE_IPv6 0x86dd
72#define GRE_PTYPE_KAR 0x0000 /* keepalive response */
73
74#ifndef IPPROTO_GRE
75# define IPPROTO_GRE 47
76#endif
77
Harald Welted06128d2021-01-30 21:17:21 +010078#define E1_LINERATE 2048000
79#define E1_SLOTS_TOTAL 32
80#define E1_SLOTS_USED 31
81/* usable bitrate of the E1 superchannel with 31 of 32 timeslots */
82#define SUPERCHANNEL_LINERATE (E1_LINERATE*E1_SLOTS_USED)/E1_SLOTS_TOTAL
83/* nanoseconds per bit (504) */
84#define BIT_DURATION_NS (1000000000 / SUPERCHANNEL_LINERATE)
85
Alexander Couzens841817e2020-11-19 00:41:29 +010086static void free_bind(struct gprs_ns2_vc_bind *bind);
87static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg);
88
89struct gprs_ns2_vc_driver vc_driver_fr = {
90 .name = "GB frame relay",
91 .free_bind = free_bind,
92};
93
94struct priv_bind {
Alexander Couzens5c96f5d2020-12-17 04:45:03 +010095 char netif[IFNAMSIZ];
Alexander Couzens841817e2020-11-19 00:41:29 +010096 struct osmo_fr_link *link;
Harald Welte41b188b2020-12-10 22:00:23 +010097 int ifindex;
Harald Welte56f08a32020-12-01 23:07:32 +010098 bool if_running;
Max73984a82022-10-19 20:37:28 +030099 /* backlog queue for AF_PACKET / ENOBUFS handling (see OS#4995) */
Harald Welted06128d2021-01-30 21:17:21 +0100100 struct {
101 /* file-descriptor for AF_PACKET socket */
102 struct osmo_fd ofd;
Harald Welte93740612021-02-02 19:54:10 +0100103 /* LMI bucket (we only store the last LMI message, no need to queue */
104 struct msgb *lmi_msg;
105 /* list of NS msgb (backlog) */
Harald Welted06128d2021-01-30 21:17:21 +0100106 struct llist_head list;
107 /* timer to trigger next attempt of AF_PACKET write */
108 struct osmo_timer_list timer;
109 /* re-try after that many micro-seconds */
110 uint32_t retry_us;
111 } backlog;
Alexander Couzens841817e2020-11-19 00:41:29 +0100112};
113
114struct priv_vc {
115 struct osmo_sockaddr remote;
116 uint16_t dlci;
117 struct osmo_fr_dlc *dlc;
118};
119
120static void free_vc(struct gprs_ns2_vc *nsvc)
121{
Alexander Couzensea377242021-01-17 16:51:55 +0100122 if (!nsvc)
123 return;
Alexander Couzens841817e2020-11-19 00:41:29 +0100124
125 if (!nsvc->priv)
126 return;
127
Alexander Couzens55bc8692021-01-18 18:39:57 +0100128 OSMO_ASSERT(gprs_ns2_is_fr_bind(nsvc->bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100129 talloc_free(nsvc->priv);
130 nsvc->priv = NULL;
131}
132
Alexander Couzens75b61882021-03-21 16:18:17 +0100133static void dump_vty(const struct gprs_ns2_vc_bind *bind, struct vty *vty, bool stats)
Alexander Couzens841817e2020-11-19 00:41:29 +0100134{
135 struct priv_bind *priv;
136 struct gprs_ns2_vc *nsvc;
Harald Welte48bd76c2020-12-01 16:53:06 +0100137 struct osmo_fr_link *fr_link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100138
139 if (!bind)
140 return;
141
142 priv = bind->priv;
Harald Welte48bd76c2020-12-01 16:53:06 +0100143 fr_link = priv->link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100144
Harald Welte56f08a32020-12-01 23:07:32 +0100145 vty_out(vty, "FR bind: %s, role: %s, link: %s%s", priv->netif,
146 osmo_fr_role_str(fr_link->role), priv->if_running ? "UP" : "DOWN", VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +0100147
148 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
Alexander Couzens75b61882021-03-21 16:18:17 +0100149 ns2_vty_dump_nsvc(vty, nsvc, stats);
Alexander Couzens841817e2020-11-19 00:41:29 +0100150 }
151
152 priv = bind->priv;
153}
154
155/*! clean up all private driver state. Should be only called by gprs_ns2_free_bind() */
156static void free_bind(struct gprs_ns2_vc_bind *bind)
157{
158 struct priv_bind *priv;
Harald Welted06128d2021-01-30 21:17:21 +0100159 struct msgb *msg, *msg2;
Alexander Couzens841817e2020-11-19 00:41:29 +0100160
161 if (!bind)
162 return;
163
Alexander Couzens24d9e802021-02-03 11:30:43 +0100164 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100165 priv = bind->priv;
166
167 OSMO_ASSERT(llist_empty(&bind->nsvc));
168
Harald Welted06128d2021-01-30 21:17:21 +0100169 osmo_timer_del(&priv->backlog.timer);
170 llist_for_each_entry_safe(msg, msg2, &priv->backlog.list, list) {
171 msgb_free(msg);
172 }
Harald Welte93740612021-02-02 19:54:10 +0100173 msgb_free(priv->backlog.lmi_msg);
Harald Welted06128d2021-01-30 21:17:21 +0100174
Alexander Couzens841817e2020-11-19 00:41:29 +0100175 osmo_fr_link_free(priv->link);
Harald Welted06128d2021-01-30 21:17:21 +0100176 osmo_fd_close(&priv->backlog.ofd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100177 talloc_free(priv);
178}
179
Harald Welte9d28ce52021-01-31 18:38:20 +0100180static void fr_dlci_status_cb(struct osmo_fr_dlc *dlc, void *cb_data, bool active)
181{
182 struct gprs_ns2_vc *nsvc = cb_data;
183
184 if (active) {
185 ns2_vc_fsm_start(nsvc);
186 } else {
187 ns2_vc_force_unconfigured(nsvc);
188 }
189}
190
Alexander Couzens841817e2020-11-19 00:41:29 +0100191static struct priv_vc *fr_alloc_vc(struct gprs_ns2_vc_bind *bind,
192 struct gprs_ns2_vc *nsvc,
193 uint16_t dlci)
194{
195 struct priv_bind *privb = bind->priv;
196 struct priv_vc *priv = talloc_zero(bind, struct priv_vc);
197 if (!priv)
198 return NULL;
199
Alexander Couzens55bc8692021-01-18 18:39:57 +0100200 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100201 nsvc->priv = priv;
202 priv->dlci = dlci;
203 priv->dlc = osmo_fr_dlc_alloc(privb->link, dlci);
204 if (!priv->dlc) {
205 nsvc->priv = NULL;
206 talloc_free(priv);
207 return NULL;
208 }
209
Harald Welte2cc1d4d2021-01-31 18:33:31 +0100210 priv->dlc->cb_data = nsvc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100211 priv->dlc->rx_cb = fr_dlci_rx_cb;
Harald Welte9d28ce52021-01-31 18:38:20 +0100212 priv->dlc->status_cb = fr_dlci_status_cb;
Alexander Couzens841817e2020-11-19 00:41:29 +0100213
214 return priv;
215}
216
217int gprs_ns2_find_vc_by_dlci(struct gprs_ns2_vc_bind *bind,
218 uint16_t dlci,
219 struct gprs_ns2_vc **result)
220{
221 struct gprs_ns2_vc *nsvc;
222 struct priv_vc *vcpriv;
223
Alexander Couzens55bc8692021-01-18 18:39:57 +0100224 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100225 if (!result)
226 return -EINVAL;
227
228 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
229 vcpriv = nsvc->priv;
230 if (vcpriv->dlci != dlci) {
231 *result = nsvc;
232 return 0;
233 }
234 }
235
236 return 1;
237}
238
239/* PDU from the network interface towards the fr layer (upwards) */
Harald Welted06128d2021-01-30 21:17:21 +0100240static int fr_netif_ofd_cb(struct osmo_fd *bfd, uint32_t what)
Alexander Couzens841817e2020-11-19 00:41:29 +0100241{
242 struct gprs_ns2_vc_bind *bind = bfd->data;
243 struct priv_bind *priv = bind->priv;
Harald Welted06128d2021-01-30 21:17:21 +0100244 struct msgb *msg;
Harald Welte41b188b2020-12-10 22:00:23 +0100245 struct sockaddr_ll sll;
246 socklen_t sll_len = sizeof(sll);
Alexander Couzens841817e2020-11-19 00:41:29 +0100247 int rc = 0;
248
Harald Welted06128d2021-01-30 21:17:21 +0100249 /* we only handle read here. write to AF_PACKET sockets cannot be triggered
250 * by select or poll, see OS#4995 */
251 if (!(what & OSMO_FD_READ))
252 return 0;
253
Daniel Willmann1f666e82021-10-26 16:15:51 +0200254 msg = msgb_alloc(NS_ALLOC_SIZE, "Gb/NS/FR Rx");
Alexander Couzens841817e2020-11-19 00:41:29 +0100255 if (!msg)
256 return -ENOMEM;
257
Harald Welte41b188b2020-12-10 22:00:23 +0100258 rc = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0, (struct sockaddr *)&sll, &sll_len);
Alexander Couzens841817e2020-11-19 00:41:29 +0100259 if (rc < 0) {
Daniel Willmann1f666e82021-10-26 16:15:51 +0200260 LOGBIND(bind, LOGL_ERROR, "recv error %s during NS-FR recv\n", strerror(errno));
Alexander Couzens841817e2020-11-19 00:41:29 +0100261 goto out_err;
262 } else if (rc == 0) {
263 goto out_err;
264 }
265
Harald Welte41b188b2020-12-10 22:00:23 +0100266 /* ignore any packets that we might have received for a different interface, between
267 * the socket() and the bind() call */
268 if (sll.sll_ifindex != priv->ifindex)
269 goto out_err;
270
Alexander Couzens841817e2020-11-19 00:41:29 +0100271 msgb_put(msg, rc);
272 msg->dst = priv->link;
273 return osmo_fr_rx(msg);
274
275out_err:
276 msgb_free(msg);
277 return rc;
278}
279
280/* PDU from the frame relay towards the NS-VC (upwards) */
281static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg)
282{
283 int rc;
284 struct gprs_ns2_vc *nsvc = cb_data;
285
286 rc = ns2_recv_vc(nsvc, msg);
287
288 return rc;
289}
290
Harald Welted06128d2021-01-30 21:17:21 +0100291static int fr_netif_write_one(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
Alexander Couzens841817e2020-11-19 00:41:29 +0100292{
Harald Welted06128d2021-01-30 21:17:21 +0100293 struct priv_bind *priv = bind->priv;
294 unsigned int len = msgb_length(msg);
Harald Weltef0073d72021-01-30 11:41:13 +0100295 int rc;
296
Harald Welted06128d2021-01-30 21:17:21 +0100297 /* estimate the retry time based on the data rate it takes to transmit */
298 priv->backlog.retry_us = (BIT_DURATION_NS * 8 * len) / 1000;
299
300 rc = write(priv->backlog.ofd.fd, msgb_data(msg), len);
301 if (rc == len) {
302 msgb_free(msg);
303 return 0;
304 } else if (rc < 0) {
305 /* don't free, the caller might want to re-transmit */
306 switch (errno) {
307 case EAGAIN:
308 case ENOBUFS:
Harald Welte9811f492021-02-02 22:58:00 +0100309 /* not a real error, but more a normal event on AF_PACKET */
310 /* don't free the message and let the caller re-enqueue */
Harald Welted06128d2021-01-30 21:17:21 +0100311 return -errno;
312 default:
Harald Welte9811f492021-02-02 22:58:00 +0100313 /* an actual error, like -ENETDOWN, -EMSGSIZE */
Harald Welted06128d2021-01-30 21:17:21 +0100314 LOGBIND(bind, LOGL_ERROR, "error during write to AF_PACKET: %s\n", strerror(errno));
Harald Welte9811f492021-02-02 22:58:00 +0100315 msgb_free(msg);
316 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100317 }
318 } else {
319 /* short write */
320 LOGBIND(bind, LOGL_ERROR, "short write on AF_PACKET: %d < %d\n", rc, len);
321 msgb_free(msg);
322 return 0;
323 }
Alexander Couzens841817e2020-11-19 00:41:29 +0100324}
325
326/*! determine if given bind is for FR-GRE encapsulation. */
327int gprs_ns2_is_fr_bind(struct gprs_ns2_vc_bind *bind)
328{
329 return (bind->driver == &vc_driver_fr);
330}
331
332/* PDU from the NS-VC towards the frame relay layer (downwards) */
333static int fr_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
334{
335 struct priv_vc *vcpriv = nsvc->priv;
336
337 msg->dst = vcpriv->dlc;
338 return osmo_fr_tx_dlc(msg);
339}
340
Harald Welted06128d2021-01-30 21:17:21 +0100341static void enqueue_at_head(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
342{
343 struct priv_bind *priv = bind->priv;
344 llist_add(&msg->list, &priv->backlog.list);
Pau Espin Pedrol7b894a72021-06-04 18:17:12 +0200345 osmo_stat_item_inc(osmo_stat_item_group_get_item(bind->statg, NS2_BIND_STAT_BACKLOG_LEN), 1);
Harald Welted06128d2021-01-30 21:17:21 +0100346 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
347}
348
349static void enqueue_at_tail(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
350{
351 struct priv_bind *priv = bind->priv;
352 llist_add_tail(&msg->list, &priv->backlog.list);
Pau Espin Pedrol7b894a72021-06-04 18:17:12 +0200353 osmo_stat_item_inc(osmo_stat_item_group_get_item(bind->statg, NS2_BIND_STAT_BACKLOG_LEN), 1);
Harald Welted06128d2021-01-30 21:17:21 +0100354 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
355}
356
357#define LMI_Q933A_DLCI 0
358
359/* enqueue to backlog (LMI, signaling) or drop (userdata msg) */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100360static int backlog_enqueue_or_free(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
Harald Welted06128d2021-01-30 21:17:21 +0100361{
Harald Welte93740612021-02-02 19:54:10 +0100362 struct priv_bind *priv = bind->priv;
Harald Welted06128d2021-01-30 21:17:21 +0100363 uint8_t dlci = msg->data[0];
364 uint8_t ns_pdu_type;
365 uint16_t bvci;
366
367 if (msgb_length(msg) < 1)
368 goto out_free;
369
370 /* we want to enqueue only Q.933 LMI traffic or NS signaling; NOT user traffic */
371 switch (dlci) {
372 case LMI_Q933A_DLCI:
Harald Welte93740612021-02-02 19:54:10 +0100373 /* always store only the last LMI message in the lmi_msg bucket */
374 msgb_free(priv->backlog.lmi_msg);
375 priv->backlog.lmi_msg = msg;
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100376 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100377 default:
Harald Welte6972aed2021-02-02 20:29:32 +0100378 /* there's no point in trying to enqueue messages if the interface is down */
379 if (!priv->if_running)
380 break;
381
Harald Welted06128d2021-01-30 21:17:21 +0100382 if (msgb_length(msg) < 3)
383 break;
384 ns_pdu_type = msg->data[2];
385 switch (ns_pdu_type) {
386 case NS_PDUT_UNITDATA:
387 if (msgb_length(msg) < 6)
388 break;
389 bvci = osmo_load16be(msg->data + 4);
390 /* enqueue BVCI=0 traffic at tail of queue */
391 if (bvci == BVCI_SIGNALLING) {
392 enqueue_at_tail(bind, msg);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100393 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100394 }
395 break;
396 default:
397 /* enqueue NS signaling traffic at head of queue */
398 enqueue_at_head(bind, msg);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100399 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100400 }
401 break;
402 }
403
404out_free:
405 /* drop everything that is not LMI, NS-signaling or BVCI-0 */
406 msgb_free(msg);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100407 return -1;
Harald Welted06128d2021-01-30 21:17:21 +0100408}
409
410static void fr_backlog_timer_cb(void *data)
411{
412 struct gprs_ns2_vc_bind *bind = data;
413 struct priv_bind *priv = bind->priv;
414 int i, rc;
415
Harald Welte93740612021-02-02 19:54:10 +0100416 /* first try to get rid of the LMI message, if any */
417 if (priv->backlog.lmi_msg) {
418 rc = fr_netif_write_one(bind, priv->backlog.lmi_msg);
419 if (rc < 0)
420 goto restart_timer;
421 /* fr_netif_write_one() has just free'd it */
422 priv->backlog.lmi_msg = NULL;
423 }
424
Harald Welted06128d2021-01-30 21:17:21 +0100425 /* attempt to send up to 10 messages in every timer */
426 for (i = 0; i < 10; i++) {
427 struct msgb *msg = msgb_dequeue(&priv->backlog.list);
428 if (!msg)
429 break;
430
431 rc = fr_netif_write_one(bind, msg);
432 if (rc < 0) {
433 /* re-add at head of list */
434 llist_add(&msg->list, &priv->backlog.list);
435 break;
436 }
Pau Espin Pedrol7b894a72021-06-04 18:17:12 +0200437 osmo_stat_item_dec(osmo_stat_item_group_get_item(bind->statg, NS2_BIND_STAT_BACKLOG_LEN), 1);
Harald Welted06128d2021-01-30 21:17:21 +0100438 }
439
Harald Welte93740612021-02-02 19:54:10 +0100440restart_timer:
Harald Welted06128d2021-01-30 21:17:21 +0100441 /* re-start timer if we still have data in the queue */
442 if (!llist_empty(&priv->backlog.list))
443 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
444}
445
Alexander Couzens841817e2020-11-19 00:41:29 +0100446/* PDU from the frame relay layer towards the network interface (downwards) */
447int fr_tx_cb(void *data, struct msgb *msg)
448{
449 struct gprs_ns2_vc_bind *bind = data;
450 struct priv_bind *priv = bind->priv;
Harald Welted06128d2021-01-30 21:17:21 +0100451 int rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100452
Harald Welted06128d2021-01-30 21:17:21 +0100453 if (llist_empty(&priv->backlog.list)) {
454 /* attempt to transmit right now */
455 rc = fr_netif_write_one(bind, msg);
456 if (rc < 0) {
457 /* enqueue to backlog in case it fails */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100458 return backlog_enqueue_or_free(bind, msg);
Harald Welted06128d2021-01-30 21:17:21 +0100459 }
460 } else {
461 /* enqueue to backlog */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100462 return backlog_enqueue_or_free(bind, msg);
Alexander Couzens60021a42020-12-17 02:48:22 +0100463 }
Alexander Couzens841817e2020-11-19 00:41:29 +0100464
Alexander Couzens60021a42020-12-17 02:48:22 +0100465 return 0;
Alexander Couzens841817e2020-11-19 00:41:29 +0100466}
467
468static int devname2ifindex(const char *ifname)
469{
470 struct ifreq ifr;
471 int sk, rc;
472
473 sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
474 if (sk < 0)
475 return sk;
476
477
478 memset(&ifr, 0, sizeof(ifr));
Neels Hofmeyr475a0ac2020-12-17 18:10:34 +0100479 OSMO_STRLCPY_ARRAY(ifr.ifr_name, ifname);
Alexander Couzens841817e2020-11-19 00:41:29 +0100480
481 rc = ioctl(sk, SIOCGIFINDEX, &ifr);
482 close(sk);
483 if (rc < 0)
484 return rc;
485
486 return ifr.ifr_ifindex;
487}
488
Harald Weltef2949742021-01-20 14:54:14 +0100489static int open_socket(int ifindex, const struct gprs_ns2_vc_bind *nsbind)
Alexander Couzens841817e2020-11-19 00:41:29 +0100490{
491 struct sockaddr_ll addr;
Harald Welte4ed0f4e2020-12-10 21:50:32 +0100492 int fd, rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100493
Alexander Couzens841817e2020-11-19 00:41:29 +0100494 memset(&addr, 0, sizeof(addr));
495 addr.sll_family = AF_PACKET;
496 addr.sll_protocol = htons(ETH_P_ALL);
497 addr.sll_ifindex = ifindex;
498
Harald Welte5bea72e2020-12-10 22:06:21 +0100499 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_HDLC));
Alexander Couzens841817e2020-11-19 00:41:29 +0100500 if (fd < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100501 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 +0100502 return fd;
503 }
504
Harald Welte41b188b2020-12-10 22:00:23 +0100505 /* there's a race condition between the above syscall and the bind() call below,
506 * causing other packets to be received in between */
507
Alexander Couzens841817e2020-11-19 00:41:29 +0100508 rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
509 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100510 LOGBIND(nsbind, LOGL_ERROR, "Can not bind AF_PACKET socket to ifindex %d\n", ifindex);
Alexander Couzens841817e2020-11-19 00:41:29 +0100511 close(fd);
512 return rc;
513 }
514
515 return fd;
516}
517
Harald Welte56f08a32020-12-01 23:07:32 +0100518#ifdef ENABLE_LIBMNL
519
520#include <osmocom/core/mnl.h>
Harald Welte56f08a32020-12-01 23:07:32 +0100521#include <linux/if_link.h>
522#include <linux/rtnetlink.h>
523
524#ifndef ARPHRD_FRAD
525#define ARPHRD_FRAD 770
526#endif
527
528/* validate the netlink attributes */
529static int data_attr_cb(const struct nlattr *attr, void *data)
530{
531 const struct nlattr **tb = data;
532 int type = mnl_attr_get_type(attr);
533
534 if (mnl_attr_type_valid(attr, IFLA_MAX) < 0)
535 return MNL_CB_OK;
536
537 switch (type) {
538 case IFLA_MTU:
539 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
540 return MNL_CB_ERROR;
541 break;
542 case IFLA_IFNAME:
543 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
544 return MNL_CB_ERROR;
545 break;
546 }
547 tb[type] = attr;
548 return MNL_CB_OK;
549}
550
551/* find the bind for the netdev (if any) */
552static struct gprs_ns2_vc_bind *bind4netdev(struct gprs_ns2_inst *nsi, const char *ifname)
553{
554 struct gprs_ns2_vc_bind *bind;
555
556 llist_for_each_entry(bind, &nsi->binding, list) {
557 struct priv_bind *bpriv = bind->priv;
558 if (!strcmp(bpriv->netif, ifname))
559 return bind;
560 }
561
562 return NULL;
563}
564
Harald Welte6972aed2021-02-02 20:29:32 +0100565static void link_state_change(struct gprs_ns2_vc_bind *bind, bool if_running)
566{
567 struct priv_bind *bpriv = bind->priv;
568 struct msgb *msg, *msg2;
569
570 if (bpriv->if_running == if_running)
571 return;
572
573 LOGBIND(bind, LOGL_NOTICE, "FR net-device '%s': Physical link state changed: %s\n",
574 bpriv->netif, if_running ? "UP" : "DOWN");
575
576 /* free any backlog, both on IFUP and IFDOWN. Keep the LMI, as it makes
577 * sense to get one out of the door ASAP. */
578 llist_for_each_entry_safe(msg, msg2, &bpriv->backlog.list, list) {
579 msgb_free(msg);
580 }
581
582 if (if_running) {
583 /* interface just came up */
584 if (bpriv->backlog.lmi_msg)
585 osmo_timer_schedule(&bpriv->backlog.timer, 0, bpriv->backlog.retry_us);
586 } else {
587 /* interface just went down; no need to retransmit */
588 osmo_timer_del(&bpriv->backlog.timer);
589 }
590
591 bpriv->if_running = if_running;
592}
593
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100594static void mtu_change(struct gprs_ns2_vc_bind *bind, uint32_t mtu)
595{
596 struct priv_bind *bpriv = bind->priv;
597 struct gprs_ns2_nse *nse;
598
Alexander Couzensa6096ad2021-07-02 16:23:06 +0200599 /* 2 byte DLCI header */
600 if (mtu <= 2)
601 return;
602 mtu -= 2;
603
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100604 if (mtu == bind->mtu)
605 return;
606
607 LOGBIND(bind, LOGL_INFO, "MTU changed from %d to %d.\n",
Alexander Couzensa6096ad2021-07-02 16:23:06 +0200608 bind->mtu + 2, mtu + 2);
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100609
Alexander Couzensa6096ad2021-07-02 16:23:06 +0200610 bind->mtu = mtu;
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100611 if (!bpriv->if_running)
612 return;
613
614 llist_for_each_entry(nse, &bind->nsi->nse, list) {
615 ns2_nse_update_mtu(nse);
616 }
617}
618
Harald Welte56f08a32020-12-01 23:07:32 +0100619/* handle a single netlink message received via libmnl */
620static int linkmon_mnl_cb(const struct nlmsghdr *nlh, void *data)
621{
622 struct osmo_mnl *omnl = data;
623 struct gprs_ns2_vc_bind *bind;
624 struct nlattr *tb[IFLA_MAX+1] = {};
625 struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh);
626 struct gprs_ns2_inst *nsi;
627 const char *ifname;
628 bool if_running;
629
630 OSMO_ASSERT(omnl);
631 OSMO_ASSERT(ifm);
632
633 nsi = omnl->priv;
634
635 if (ifm->ifi_type != ARPHRD_FRAD)
636 return MNL_CB_OK;
637
638 mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, tb);
639
640 if (!tb[IFLA_IFNAME])
641 return MNL_CB_OK;
642 ifname = mnl_attr_get_str(tb[IFLA_IFNAME]);
643 if_running = !!(ifm->ifi_flags & IFF_RUNNING);
644
645 bind = bind4netdev(nsi, ifname);
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100646 if (!bind)
647 return MNL_CB_OK;
648
649 if (tb[IFLA_MTU]) {
650 mtu_change(bind, mnl_attr_get_u32(tb[IFLA_MTU]));
651 }
652
653 link_state_change(bind, if_running);
Harald Welte56f08a32020-12-01 23:07:32 +0100654
655 return MNL_CB_OK;
656}
657
658/* trigger one initial dump of all link information */
659static void linkmon_initial_dump(struct osmo_mnl *omnl)
660{
661 char buf[MNL_SOCKET_BUFFER_SIZE];
662 struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
663 struct rtgenmsg *rt;
664
665 nlh->nlmsg_type = RTM_GETLINK;
666 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
667 nlh->nlmsg_seq = time(NULL);
668 rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
669 rt->rtgen_family = AF_PACKET;
670
671 if (mnl_socket_sendto(omnl->mnls, nlh, nlh->nlmsg_len) < 0) {
672 LOGP(DLNS, LOGL_ERROR, "linkmon: Cannot send rtnetlink message: %s\n", strerror(errno));
673 }
674
675 /* the response[s] will be handled just like the events */
676}
677#endif /* LIBMNL */
678
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100679static int set_ifupdown(const char *netif, bool up)
680{
681 int sock, rc;
682 struct ifreq req;
683
684 sock = socket(AF_INET, SOCK_DGRAM, 0);
685 if (sock < 0)
686 return sock;
687
688 memset(&req, 0, sizeof req);
Harald Welte7f01b682020-12-21 12:39:38 +0100689 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100690
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100691 rc = ioctl(sock, SIOCGIFFLAGS, &req);
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100692 if (rc < 0) {
693 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100694 return rc;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100695 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100696
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100697 if ((req.ifr_flags & IFF_UP) == up) {
698 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100699 return 0;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100700 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100701
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100702 if (up)
703 req.ifr_flags |= IFF_UP;
704
705 rc = ioctl(sock, SIOCSIFFLAGS, &req);
706 close(sock);
707 return rc;
708}
709
Harald Weltef2949742021-01-20 14:54:14 +0100710static int setup_device(const char *netif, const struct gprs_ns2_vc_bind *bind)
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100711{
712 int sock, rc;
713 char buffer[128];
714 fr_proto *fr = (void*)buffer;
715 struct ifreq req;
716
717 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
718 if (sock < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100719 LOGBIND(bind, LOGL_ERROR, "%s: Unable to create socket: %s\n",
720 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100721 return sock;
722 }
723
724 memset(&req, 0, sizeof(struct ifreq));
725 memset(&buffer, 0, sizeof(buffer));
Harald Welteb8de1882020-12-21 12:40:45 +0100726 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100727 req.ifr_settings.ifs_ifsu.sync = (void*)buffer;
728 req.ifr_settings.size = sizeof(buffer);
729 req.ifr_settings.type = IF_GET_PROTO;
730
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100731 /* EINVAL is returned when no protocol has been set */
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100732 rc = ioctl(sock, SIOCWANDEV, &req);
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100733 if (rc < 0 && errno != EINVAL) {
Harald Weltef2949742021-01-20 14:54:14 +0100734 LOGBIND(bind, LOGL_ERROR, "%s: Unable to get FR protocol information: %s\n",
735 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100736 goto err;
737 }
738
739 /* check if the device is good */
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100740 if (rc == 0 && req.ifr_settings.type == IF_PROTO_FR && fr->lmi == LMI_NONE) {
Harald Weltef2949742021-01-20 14:54:14 +0100741 LOGBIND(bind, LOGL_NOTICE, "%s: has correct frame relay mode and lmi\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100742 goto ifup;
743 }
744
745 /* modify the device to match */
746 rc = set_ifupdown(netif, false);
747 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100748 LOGBIND(bind, LOGL_ERROR, "Unable to bring down the device %s: %s\n",
749 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100750 goto err;
751 }
752
753 memset(&req, 0, sizeof(struct ifreq));
754 memset(fr, 0, sizeof(fr_proto));
Harald Welteb8de1882020-12-21 12:40:45 +0100755 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100756 req.ifr_settings.type = IF_PROTO_FR;
757 req.ifr_settings.size = sizeof(fr_proto);
758 req.ifr_settings.ifs_ifsu.fr = fr;
759 fr->lmi = LMI_NONE;
760 /* even those settings aren't used, they must be in the range */
761 /* polling verification timer*/
762 fr->t391 = 10;
763 /* link integrity verification polling timer */
764 fr->t392 = 15;
765 /* full status polling counter*/
766 fr->n391 = 6;
767 /* error threshold */
768 fr->n392 = 3;
769 /* monitored events count */
770 fr->n393 = 4;
771
Harald Weltef2949742021-01-20 14:54:14 +0100772 LOGBIND(bind, LOGL_INFO, "%s: Setting frame relay related parameters\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100773 rc = ioctl(sock, SIOCWANDEV, &req);
774 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100775 LOGBIND(bind, LOGL_ERROR, "%s: Unable to set FR protocol on information: %s\n",
776 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100777 goto err;
778 }
779
780ifup:
781 rc = set_ifupdown(netif, true);
782 if (rc)
Harald Weltef2949742021-01-20 14:54:14 +0100783 LOGBIND(bind, LOGL_ERROR, "Unable to bring up the device %s: %s\n",
784 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100785err:
786 close(sock);
787 return rc;
788}
Harald Welte56f08a32020-12-01 23:07:32 +0100789
Alexander Couzens841817e2020-11-19 00:41:29 +0100790/*! Create a new bind for NS over FR.
791 * \param[in] nsi NS instance in which to create the bind
792 * \param[in] netif Network interface to bind to
793 * \param[in] fr_network
794 * \param[in] fr_role
Alexander Couzensc80a8742021-02-03 11:27:52 +0100795 * \param[out] result pointer to the created bind or if a bind with the name exists return the bind.
796 * \return 0 on success; negative on error. -EALREADY returned in case a bind with the name exists */
Alexander Couzens841817e2020-11-19 00:41:29 +0100797int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi,
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100798 const char *name,
Alexander Couzens841817e2020-11-19 00:41:29 +0100799 const char *netif,
800 struct osmo_fr_network *fr_network,
801 enum osmo_fr_role fr_role,
802 struct gprs_ns2_vc_bind **result)
803{
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100804 struct gprs_ns2_vc_bind *bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100805 struct priv_bind *priv;
806 struct osmo_fr_link *fr_link;
807 int rc = 0;
808
Harald Weltec3aa8f92021-01-31 11:41:34 +0100809 if (strlen(netif) > IFNAMSIZ)
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100810 return -EINVAL;
811
Alexander Couzensc80a8742021-02-03 11:27:52 +0100812 bind = gprs_ns2_bind_by_name(nsi, name);
813 if (bind) {
814 if (result)
815 *result = bind;
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100816 return -EALREADY;
Alexander Couzensc80a8742021-02-03 11:27:52 +0100817 }
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100818
Harald Weltec3aa8f92021-01-31 11:41:34 +0100819 rc = ns2_bind_alloc(nsi, name, &bind);
820 if (rc < 0)
821 return rc;
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100822
Alexander Couzens841817e2020-11-19 00:41:29 +0100823 bind->driver = &vc_driver_fr;
Alexander Couzensaac90162020-11-19 02:44:04 +0100824 bind->ll = GPRS_NS2_LL_FR;
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100825 /* 2 mbit */
826 bind->transfer_capability = 2;
Alexander Couzens841817e2020-11-19 00:41:29 +0100827 bind->send_vc = fr_vc_sendmsg;
828 bind->free_vc = free_vc;
829 bind->dump_vty = dump_vty;
Alexander Couzens4f1128f2021-01-20 17:42:48 +0100830 bind->mtu = FRAME_RELAY_SDU;
Alexander Couzens841817e2020-11-19 00:41:29 +0100831 priv = bind->priv = talloc_zero(bind, struct priv_bind);
832 if (!priv) {
Harald Weltebdfb8b92021-01-31 11:44:57 +0100833 rc = -ENOMEM;
Harald Weltec3aa8f92021-01-31 11:41:34 +0100834 goto err_bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100835 }
836
Harald Weltece6e4b72021-02-11 15:58:40 +0100837 INIT_LLIST_HEAD(&priv->backlog.list);
Neels Hofmeyr8fef7612020-12-17 18:19:19 +0100838 OSMO_STRLCPY_ARRAY(priv->netif, netif);
Alexander Couzens841817e2020-11-19 00:41:29 +0100839
Alexander Couzens841817e2020-11-19 00:41:29 +0100840 /* FIXME: move fd handling into socket.c */
841 fr_link = osmo_fr_link_alloc(fr_network, fr_role, netif);
842 if (!fr_link) {
843 rc = -EINVAL;
Harald Weltec3aa8f92021-01-31 11:41:34 +0100844 goto err_bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100845 }
846
847 fr_link->tx_cb = fr_tx_cb;
Harald Welte2cc1d4d2021-01-31 18:33:31 +0100848 fr_link->cb_data = bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100849 priv->link = fr_link;
Harald Welte41b188b2020-12-10 22:00:23 +0100850
Alexander Couzens6f89c772020-12-17 03:06:39 +0100851 priv->ifindex = rc = devname2ifindex(netif);
852 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100853 LOGBIND(bind, LOGL_ERROR, "Can not get interface index for interface %s\n", netif);
Harald Welte41b188b2020-12-10 22:00:23 +0100854 goto err_fr;
855 }
856
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100857 /* set protocol frame relay and lmi */
Harald Weltef2949742021-01-20 14:54:14 +0100858 rc = setup_device(priv->netif, bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100859 if(rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100860 LOGBIND(bind, LOGL_ERROR, "Failed to setup the interface %s for frame relay and lmi\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100861 goto err_fr;
862 }
863
Harald Weltef2949742021-01-20 14:54:14 +0100864 rc = open_socket(priv->ifindex, bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100865 if (rc < 0)
866 goto err_fr;
Harald Welted06128d2021-01-30 21:17:21 +0100867 priv->backlog.retry_us = 2500; /* start with some non-zero value; this corrsponds to 496 bytes */
868 osmo_timer_setup(&priv->backlog.timer, fr_backlog_timer_cb, bind);
869 osmo_fd_setup(&priv->backlog.ofd, rc, OSMO_FD_READ, fr_netif_ofd_cb, bind, 0);
870 rc = osmo_fd_register(&priv->backlog.ofd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100871 if (rc < 0)
872 goto err_fd;
873
Harald Welte56f08a32020-12-01 23:07:32 +0100874#ifdef ENABLE_LIBMNL
875 if (!nsi->linkmon_mnl)
876 nsi->linkmon_mnl = osmo_mnl_init(nsi, NETLINK_ROUTE, RTMGRP_LINK, linkmon_mnl_cb, nsi);
877
878 /* we get a new full dump after every bind. which is a bit excessive. But that's just once
879 * at start-up, so we can get away with it */
880 if (nsi->linkmon_mnl)
881 linkmon_initial_dump(nsi->linkmon_mnl);
882#endif
883
Harald Weltec3aa8f92021-01-31 11:41:34 +0100884 if (result)
885 *result = bind;
886
Alexander Couzens841817e2020-11-19 00:41:29 +0100887 return rc;
888
889err_fd:
Harald Welted06128d2021-01-30 21:17:21 +0100890 close(priv->backlog.ofd.fd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100891err_fr:
892 osmo_fr_link_free(fr_link);
Harald Welte855155c2021-02-11 16:07:18 +0100893 priv->link = NULL;
Alexander Couzens841817e2020-11-19 00:41:29 +0100894err_bind:
Harald Weltec3aa8f92021-01-31 11:41:34 +0100895 gprs_ns2_free_bind(bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100896
897 return rc;
898}
899
Alexander Couzensc782cec2020-12-10 04:10:25 +0100900/*! Return the frame relay role of a bind
901 * \param[in] bind The bind
902 * \return the frame relay role or -EINVAL if bind is not frame relay
903 */
904enum osmo_fr_role gprs_ns2_fr_bind_role(struct gprs_ns2_vc_bind *bind)
905{
906 struct priv_bind *priv;
907
908 if (bind->driver != &vc_driver_fr)
909 return -EINVAL;
910
911 priv = bind->priv;
912 return priv->link->role;
913}
914
Alexander Couzens841817e2020-11-19 00:41:29 +0100915/*! Return the network interface of the bind
916 * \param[in] bind The bind
917 * \return the network interface
918 */
919const char *gprs_ns2_fr_bind_netif(struct gprs_ns2_vc_bind *bind)
920{
921 struct priv_bind *priv;
922
923 if (bind->driver != &vc_driver_fr)
924 return NULL;
925
926 priv = bind->priv;
927 return priv->netif;
928}
929
930/*! Find NS bind for a given network interface
931 * \param[in] nsi NS instance
932 * \param[in] netif the network interface to search for
933 * \return the bind or NULL if not found
934 */
935struct gprs_ns2_vc_bind *gprs_ns2_fr_bind_by_netif(
936 struct gprs_ns2_inst *nsi,
937 const char *netif)
938{
939 struct gprs_ns2_vc_bind *bind;
940 const char *_netif;
941
942 OSMO_ASSERT(nsi);
943 OSMO_ASSERT(netif);
944
945 llist_for_each_entry(bind, &nsi->binding, list) {
946 if (!gprs_ns2_is_fr_bind(bind))
947 continue;
948
949 _netif = gprs_ns2_fr_bind_netif(bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100950 if (!strncmp(_netif, netif, IFNAMSIZ))
Alexander Couzens841817e2020-11-19 00:41:29 +0100951 return bind;
952 }
953
954 return NULL;
955}
956
957/*! Create, connect and activate a new FR-based NS-VC
958 * \param[in] bind bind in which the new NS-VC is to be created
959 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
960 * \param[in] dlci Data Link connection identifier
961 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
962struct gprs_ns2_vc *gprs_ns2_fr_connect(struct gprs_ns2_vc_bind *bind,
Alexander Couzensebcbd722020-12-03 06:11:39 +0100963 struct gprs_ns2_nse *nse,
964 uint16_t nsvci,
965 uint16_t dlci)
966{
967 struct gprs_ns2_vc *nsvc = NULL;
968 struct priv_vc *priv = NULL;
Harald Welte603f4042020-11-29 17:39:19 +0100969 struct priv_bind *bpriv = bind->priv;
970 char idbuf[64];
Alexander Couzensebcbd722020-12-03 06:11:39 +0100971
Alexander Couzens55bc8692021-01-18 18:39:57 +0100972 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzensebcbd722020-12-03 06:11:39 +0100973 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
974 if (nsvc) {
975 goto err;
976 }
977
Alexander Couzensd7948062021-06-03 20:35:47 +0200978 snprintf(idbuf, sizeof(idbuf), "NSE%05u-NSVC%05u-%s-%s-DLCI%u", nse->nsei, nsvci,
979 gprs_ns2_lltype_str(nse->ll), bpriv->netif, dlci);
980 osmo_identifier_sanitize_buf(idbuf, NULL, '_');
Alexander Couzens138b96f2021-01-25 16:23:29 +0100981 nsvc = ns2_vc_alloc(bind, nse, true, GPRS_NS2_VC_MODE_BLOCKRESET, idbuf);
Alexander Couzensebcbd722020-12-03 06:11:39 +0100982 if (!nsvc)
983 goto err;
984
985 nsvc->priv = priv = fr_alloc_vc(bind, nsvc, dlci);
986 if (!priv)
987 goto err;
988
989 nsvc->nsvci = nsvci;
990 nsvc->nsvci_is_valid = true;
991
Alexander Couzensebcbd722020-12-03 06:11:39 +0100992 return nsvc;
993
994err:
995 gprs_ns2_free_nsvc(nsvc);
996 return NULL;
997}
998
999
1000/*! Create, connect and activate a new FR-based NS-VC
1001 * \param[in] bind bind in which the new NS-VC is to be created
1002 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
1003 * \param[in] dlci Data Link connection identifier
1004 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
1005struct gprs_ns2_vc *gprs_ns2_fr_connect2(struct gprs_ns2_vc_bind *bind,
Alexander Couzens841817e2020-11-19 00:41:29 +01001006 uint16_t nsei,
1007 uint16_t nsvci,
1008 uint16_t dlci)
1009{
1010 bool created_nse = false;
1011 struct gprs_ns2_vc *nsvc = NULL;
Alexander Couzens55bc8692021-01-18 18:39:57 +01001012 struct gprs_ns2_nse *nse;
1013
1014 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
1015 nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei);
Alexander Couzens841817e2020-11-19 00:41:29 +01001016 if (!nse) {
Alexander Couzens138b96f2021-01-25 16:23:29 +01001017 nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_FR, GPRS_NS2_DIALECT_STATIC_RESETBLOCK);
Alexander Couzens841817e2020-11-19 00:41:29 +01001018 if (!nse)
1019 return NULL;
1020 created_nse = true;
1021 }
1022
Harald Welte509047b2021-01-17 19:55:51 +01001023 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
Alexander Couzens841817e2020-11-19 00:41:29 +01001024 if (!nsvc)
1025 goto err_nse;
1026
Alexander Couzens841817e2020-11-19 00:41:29 +01001027 return nsvc;
1028
Alexander Couzens841817e2020-11-19 00:41:29 +01001029err_nse:
1030 if (created_nse)
1031 gprs_ns2_free_nse(nse);
1032
1033 return NULL;
1034}
1035
1036/*! Return the nsvc by dlci.
1037 * \param[in] bind
1038 * \param[in] dlci Data Link connection identifier
1039 * \return the nsvc or NULL if not found
1040 */
1041struct gprs_ns2_vc *gprs_ns2_fr_nsvc_by_dlci(struct gprs_ns2_vc_bind *bind,
1042 uint16_t dlci)
1043{
1044 struct gprs_ns2_vc *nsvc;
1045 struct priv_vc *vcpriv;
1046
Alexander Couzens55bc8692021-01-18 18:39:57 +01001047 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +01001048 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
1049 vcpriv = nsvc->priv;
1050
1051 if (dlci == vcpriv->dlci)
1052 return nsvc;
1053 }
1054
1055 return NULL;
1056}
1057
1058/*! Return the dlci of the nsvc
1059 * \param[in] nsvc
1060 * \return the dlci or 0 on error. 0 is not a valid dlci.
1061 */
Alexander Couzens22c26e02020-12-10 04:10:07 +01001062uint16_t gprs_ns2_fr_nsvc_dlci(const struct gprs_ns2_vc *nsvc)
Alexander Couzens841817e2020-11-19 00:41:29 +01001063{
1064 struct priv_vc *vcpriv;
1065
1066 if (!nsvc->bind)
1067 return 0;
1068
1069 if (nsvc->bind->driver != &vc_driver_fr)
1070 return 0;
1071
1072 vcpriv = nsvc->priv;
1073 return vcpriv->dlci;
1074}