blob: 2662df682f8b453592599f5fea22f7a3ed1899f2 [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 +010086struct gre_hdr {
87 uint16_t flags;
88 uint16_t ptype;
89} __attribute__ ((packed));
90
91static void free_bind(struct gprs_ns2_vc_bind *bind);
92static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg);
93
94struct gprs_ns2_vc_driver vc_driver_fr = {
95 .name = "GB frame relay",
96 .free_bind = free_bind,
97};
98
99struct priv_bind {
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100100 char netif[IFNAMSIZ];
Alexander Couzens841817e2020-11-19 00:41:29 +0100101 struct osmo_fr_link *link;
Harald Welte41b188b2020-12-10 22:00:23 +0100102 int ifindex;
Harald Welte56f08a32020-12-01 23:07:32 +0100103 bool if_running;
Harald Welted06128d2021-01-30 21:17:21 +0100104 /* backlog queue for AF_PACKET / ENOBUFS handling (see OS#4993) */
105 struct {
106 /* file-descriptor for AF_PACKET socket */
107 struct osmo_fd ofd;
Harald Welte93740612021-02-02 19:54:10 +0100108 /* LMI bucket (we only store the last LMI message, no need to queue */
109 struct msgb *lmi_msg;
110 /* list of NS msgb (backlog) */
Harald Welted06128d2021-01-30 21:17:21 +0100111 struct llist_head list;
112 /* timer to trigger next attempt of AF_PACKET write */
113 struct osmo_timer_list timer;
114 /* re-try after that many micro-seconds */
115 uint32_t retry_us;
116 } backlog;
Alexander Couzens841817e2020-11-19 00:41:29 +0100117};
118
119struct priv_vc {
120 struct osmo_sockaddr remote;
121 uint16_t dlci;
122 struct osmo_fr_dlc *dlc;
123};
124
125static void free_vc(struct gprs_ns2_vc *nsvc)
126{
Alexander Couzensea377242021-01-17 16:51:55 +0100127 if (!nsvc)
128 return;
Alexander Couzens841817e2020-11-19 00:41:29 +0100129
130 if (!nsvc->priv)
131 return;
132
Alexander Couzens55bc8692021-01-18 18:39:57 +0100133 OSMO_ASSERT(gprs_ns2_is_fr_bind(nsvc->bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100134 talloc_free(nsvc->priv);
135 nsvc->priv = NULL;
136}
137
138static void dump_vty(const struct gprs_ns2_vc_bind *bind, struct vty *vty, bool _stats)
139{
140 struct priv_bind *priv;
141 struct gprs_ns2_vc *nsvc;
Harald Welte48bd76c2020-12-01 16:53:06 +0100142 struct osmo_fr_link *fr_link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100143
144 if (!bind)
145 return;
146
147 priv = bind->priv;
Harald Welte48bd76c2020-12-01 16:53:06 +0100148 fr_link = priv->link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100149
Harald Welte56f08a32020-12-01 23:07:32 +0100150 vty_out(vty, "FR bind: %s, role: %s, link: %s%s", priv->netif,
151 osmo_fr_role_str(fr_link->role), priv->if_running ? "UP" : "DOWN", VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +0100152
153 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
Harald Welte96ec84a2020-12-01 17:56:05 +0100154 vty_out(vty, " NSVCI %05u: %s%s", nsvc->nsvci, gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +0100155 }
156
157 priv = bind->priv;
158}
159
160/*! clean up all private driver state. Should be only called by gprs_ns2_free_bind() */
161static void free_bind(struct gprs_ns2_vc_bind *bind)
162{
163 struct priv_bind *priv;
Harald Welted06128d2021-01-30 21:17:21 +0100164 struct msgb *msg, *msg2;
Alexander Couzens841817e2020-11-19 00:41:29 +0100165
166 if (!bind)
167 return;
168
Alexander Couzens24d9e802021-02-03 11:30:43 +0100169 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100170 priv = bind->priv;
171
172 OSMO_ASSERT(llist_empty(&bind->nsvc));
173
Harald Welted06128d2021-01-30 21:17:21 +0100174 osmo_timer_del(&priv->backlog.timer);
175 llist_for_each_entry_safe(msg, msg2, &priv->backlog.list, list) {
176 msgb_free(msg);
177 }
Harald Welte93740612021-02-02 19:54:10 +0100178 msgb_free(priv->backlog.lmi_msg);
Harald Welted06128d2021-01-30 21:17:21 +0100179
Alexander Couzens841817e2020-11-19 00:41:29 +0100180 osmo_fr_link_free(priv->link);
Harald Welted06128d2021-01-30 21:17:21 +0100181 osmo_fd_close(&priv->backlog.ofd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100182 talloc_free(priv);
183}
184
Harald Welte9d28ce52021-01-31 18:38:20 +0100185static void fr_dlci_status_cb(struct osmo_fr_dlc *dlc, void *cb_data, bool active)
186{
187 struct gprs_ns2_vc *nsvc = cb_data;
188
189 if (active) {
190 ns2_vc_fsm_start(nsvc);
191 } else {
192 ns2_vc_force_unconfigured(nsvc);
193 }
194}
195
Alexander Couzens841817e2020-11-19 00:41:29 +0100196static struct priv_vc *fr_alloc_vc(struct gprs_ns2_vc_bind *bind,
197 struct gprs_ns2_vc *nsvc,
198 uint16_t dlci)
199{
200 struct priv_bind *privb = bind->priv;
201 struct priv_vc *priv = talloc_zero(bind, struct priv_vc);
202 if (!priv)
203 return NULL;
204
Alexander Couzens55bc8692021-01-18 18:39:57 +0100205 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100206 nsvc->priv = priv;
207 priv->dlci = dlci;
208 priv->dlc = osmo_fr_dlc_alloc(privb->link, dlci);
209 if (!priv->dlc) {
210 nsvc->priv = NULL;
211 talloc_free(priv);
212 return NULL;
213 }
214
Harald Welte2cc1d4d2021-01-31 18:33:31 +0100215 priv->dlc->cb_data = nsvc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100216 priv->dlc->rx_cb = fr_dlci_rx_cb;
Harald Welte9d28ce52021-01-31 18:38:20 +0100217 priv->dlc->status_cb = fr_dlci_status_cb;
Alexander Couzens841817e2020-11-19 00:41:29 +0100218
219 return priv;
220}
221
222int gprs_ns2_find_vc_by_dlci(struct gprs_ns2_vc_bind *bind,
223 uint16_t dlci,
224 struct gprs_ns2_vc **result)
225{
226 struct gprs_ns2_vc *nsvc;
227 struct priv_vc *vcpriv;
228
Alexander Couzens55bc8692021-01-18 18:39:57 +0100229 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100230 if (!result)
231 return -EINVAL;
232
233 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
234 vcpriv = nsvc->priv;
235 if (vcpriv->dlci != dlci) {
236 *result = nsvc;
237 return 0;
238 }
239 }
240
241 return 1;
242}
243
244/* PDU from the network interface towards the fr layer (upwards) */
Harald Welted06128d2021-01-30 21:17:21 +0100245static int fr_netif_ofd_cb(struct osmo_fd *bfd, uint32_t what)
Alexander Couzens841817e2020-11-19 00:41:29 +0100246{
247 struct gprs_ns2_vc_bind *bind = bfd->data;
248 struct priv_bind *priv = bind->priv;
Harald Welted06128d2021-01-30 21:17:21 +0100249 struct msgb *msg;
Harald Welte41b188b2020-12-10 22:00:23 +0100250 struct sockaddr_ll sll;
251 socklen_t sll_len = sizeof(sll);
Alexander Couzens841817e2020-11-19 00:41:29 +0100252 int rc = 0;
253
Harald Welted06128d2021-01-30 21:17:21 +0100254 /* we only handle read here. write to AF_PACKET sockets cannot be triggered
255 * by select or poll, see OS#4995 */
256 if (!(what & OSMO_FD_READ))
257 return 0;
258
259 msg = msgb_alloc(NS_ALLOC_SIZE, "Gb/NS/FR/GRE Rx");
Alexander Couzens841817e2020-11-19 00:41:29 +0100260 if (!msg)
261 return -ENOMEM;
262
Harald Welte41b188b2020-12-10 22:00:23 +0100263 rc = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0, (struct sockaddr *)&sll, &sll_len);
Alexander Couzens841817e2020-11-19 00:41:29 +0100264 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100265 LOGBIND(bind, LOGL_ERROR, "recv error %s during NS-FR-GRE recv\n", strerror(errno));
Alexander Couzens841817e2020-11-19 00:41:29 +0100266 goto out_err;
267 } else if (rc == 0) {
268 goto out_err;
269 }
270
Harald Welte41b188b2020-12-10 22:00:23 +0100271 /* ignore any packets that we might have received for a different interface, between
272 * the socket() and the bind() call */
273 if (sll.sll_ifindex != priv->ifindex)
274 goto out_err;
275
Alexander Couzens841817e2020-11-19 00:41:29 +0100276 msgb_put(msg, rc);
277 msg->dst = priv->link;
278 return osmo_fr_rx(msg);
279
280out_err:
281 msgb_free(msg);
282 return rc;
283}
284
285/* PDU from the frame relay towards the NS-VC (upwards) */
286static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg)
287{
288 int rc;
289 struct gprs_ns2_vc *nsvc = cb_data;
290
291 rc = ns2_recv_vc(nsvc, msg);
292
293 return rc;
294}
295
Harald Welted06128d2021-01-30 21:17:21 +0100296static int fr_netif_write_one(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
Alexander Couzens841817e2020-11-19 00:41:29 +0100297{
Harald Welted06128d2021-01-30 21:17:21 +0100298 struct priv_bind *priv = bind->priv;
299 unsigned int len = msgb_length(msg);
Harald Weltef0073d72021-01-30 11:41:13 +0100300 int rc;
301
Harald Welted06128d2021-01-30 21:17:21 +0100302 /* estimate the retry time based on the data rate it takes to transmit */
303 priv->backlog.retry_us = (BIT_DURATION_NS * 8 * len) / 1000;
304
305 rc = write(priv->backlog.ofd.fd, msgb_data(msg), len);
306 if (rc == len) {
307 msgb_free(msg);
308 return 0;
309 } else if (rc < 0) {
310 /* don't free, the caller might want to re-transmit */
311 switch (errno) {
312 case EAGAIN:
313 case ENOBUFS:
314 return -errno;
315 default:
316 LOGBIND(bind, LOGL_ERROR, "error during write to AF_PACKET: %s\n", strerror(errno));
317 return -errno;
318 }
319 } else {
320 /* short write */
321 LOGBIND(bind, LOGL_ERROR, "short write on AF_PACKET: %d < %d\n", rc, len);
322 msgb_free(msg);
323 return 0;
324 }
Alexander Couzens841817e2020-11-19 00:41:29 +0100325}
326
327/*! determine if given bind is for FR-GRE encapsulation. */
328int gprs_ns2_is_fr_bind(struct gprs_ns2_vc_bind *bind)
329{
330 return (bind->driver == &vc_driver_fr);
331}
332
333/* PDU from the NS-VC towards the frame relay layer (downwards) */
334static int fr_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
335{
336 struct priv_vc *vcpriv = nsvc->priv;
337
338 msg->dst = vcpriv->dlc;
339 return osmo_fr_tx_dlc(msg);
340}
341
Harald Welted06128d2021-01-30 21:17:21 +0100342static void enqueue_at_head(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
343{
344 struct priv_bind *priv = bind->priv;
345 llist_add(&msg->list, &priv->backlog.list);
Harald Welte76346072021-01-31 11:54:02 +0100346 osmo_stat_item_inc(bind->statg->items[NS2_BIND_STAT_BACKLOG_LEN], 1);
Harald Welted06128d2021-01-30 21:17:21 +0100347 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
348}
349
350static void enqueue_at_tail(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
351{
352 struct priv_bind *priv = bind->priv;
353 llist_add_tail(&msg->list, &priv->backlog.list);
Harald Welte76346072021-01-31 11:54:02 +0100354 osmo_stat_item_inc(bind->statg->items[NS2_BIND_STAT_BACKLOG_LEN], 1);
Harald Welted06128d2021-01-30 21:17:21 +0100355 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
356}
357
358#define LMI_Q933A_DLCI 0
359
360/* enqueue to backlog (LMI, signaling) or drop (userdata msg) */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100361static int backlog_enqueue_or_free(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
Harald Welted06128d2021-01-30 21:17:21 +0100362{
Harald Welte93740612021-02-02 19:54:10 +0100363 struct priv_bind *priv = bind->priv;
Harald Welted06128d2021-01-30 21:17:21 +0100364 uint8_t dlci = msg->data[0];
365 uint8_t ns_pdu_type;
366 uint16_t bvci;
367
368 if (msgb_length(msg) < 1)
369 goto out_free;
370
371 /* we want to enqueue only Q.933 LMI traffic or NS signaling; NOT user traffic */
372 switch (dlci) {
373 case LMI_Q933A_DLCI:
Harald Welte93740612021-02-02 19:54:10 +0100374 /* always store only the last LMI message in the lmi_msg bucket */
375 msgb_free(priv->backlog.lmi_msg);
376 priv->backlog.lmi_msg = msg;
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100377 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100378 default:
Harald Welte6972aed2021-02-02 20:29:32 +0100379 /* there's no point in trying to enqueue messages if the interface is down */
380 if (!priv->if_running)
381 break;
382
Harald Welted06128d2021-01-30 21:17:21 +0100383 if (msgb_length(msg) < 3)
384 break;
385 ns_pdu_type = msg->data[2];
386 switch (ns_pdu_type) {
387 case NS_PDUT_UNITDATA:
388 if (msgb_length(msg) < 6)
389 break;
390 bvci = osmo_load16be(msg->data + 4);
391 /* enqueue BVCI=0 traffic at tail of queue */
392 if (bvci == BVCI_SIGNALLING) {
393 enqueue_at_tail(bind, msg);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100394 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100395 }
396 break;
397 default:
398 /* enqueue NS signaling traffic at head of queue */
399 enqueue_at_head(bind, msg);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100400 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100401 }
402 break;
403 }
404
405out_free:
406 /* drop everything that is not LMI, NS-signaling or BVCI-0 */
407 msgb_free(msg);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100408 return -1;
Harald Welted06128d2021-01-30 21:17:21 +0100409}
410
411static void fr_backlog_timer_cb(void *data)
412{
413 struct gprs_ns2_vc_bind *bind = data;
414 struct priv_bind *priv = bind->priv;
415 int i, rc;
416
Harald Welte93740612021-02-02 19:54:10 +0100417 /* first try to get rid of the LMI message, if any */
418 if (priv->backlog.lmi_msg) {
419 rc = fr_netif_write_one(bind, priv->backlog.lmi_msg);
420 if (rc < 0)
421 goto restart_timer;
422 /* fr_netif_write_one() has just free'd it */
423 priv->backlog.lmi_msg = NULL;
424 }
425
Harald Welted06128d2021-01-30 21:17:21 +0100426 /* attempt to send up to 10 messages in every timer */
427 for (i = 0; i < 10; i++) {
428 struct msgb *msg = msgb_dequeue(&priv->backlog.list);
429 if (!msg)
430 break;
431
432 rc = fr_netif_write_one(bind, msg);
433 if (rc < 0) {
434 /* re-add at head of list */
435 llist_add(&msg->list, &priv->backlog.list);
436 break;
437 }
Harald Welte76346072021-01-31 11:54:02 +0100438 osmo_stat_item_dec(bind->statg->items[NS2_BIND_STAT_BACKLOG_LEN], 1);
Harald Welted06128d2021-01-30 21:17:21 +0100439 }
440
Harald Welte93740612021-02-02 19:54:10 +0100441restart_timer:
Harald Welted06128d2021-01-30 21:17:21 +0100442 /* re-start timer if we still have data in the queue */
443 if (!llist_empty(&priv->backlog.list))
444 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
445}
446
Alexander Couzens841817e2020-11-19 00:41:29 +0100447/* PDU from the frame relay layer towards the network interface (downwards) */
448int fr_tx_cb(void *data, struct msgb *msg)
449{
450 struct gprs_ns2_vc_bind *bind = data;
451 struct priv_bind *priv = bind->priv;
Harald Welted06128d2021-01-30 21:17:21 +0100452 int rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100453
Harald Welted06128d2021-01-30 21:17:21 +0100454 if (llist_empty(&priv->backlog.list)) {
455 /* attempt to transmit right now */
456 rc = fr_netif_write_one(bind, msg);
457 if (rc < 0) {
458 /* enqueue to backlog in case it fails */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100459 return backlog_enqueue_or_free(bind, msg);
Harald Welted06128d2021-01-30 21:17:21 +0100460 }
461 } else {
462 /* enqueue to backlog */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100463 return backlog_enqueue_or_free(bind, msg);
Alexander Couzens60021a42020-12-17 02:48:22 +0100464 }
Alexander Couzens841817e2020-11-19 00:41:29 +0100465
Alexander Couzens60021a42020-12-17 02:48:22 +0100466 return 0;
Alexander Couzens841817e2020-11-19 00:41:29 +0100467}
468
469static int devname2ifindex(const char *ifname)
470{
471 struct ifreq ifr;
472 int sk, rc;
473
474 sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
475 if (sk < 0)
476 return sk;
477
478
479 memset(&ifr, 0, sizeof(ifr));
Neels Hofmeyr475a0ac2020-12-17 18:10:34 +0100480 OSMO_STRLCPY_ARRAY(ifr.ifr_name, ifname);
Alexander Couzens841817e2020-11-19 00:41:29 +0100481
482 rc = ioctl(sk, SIOCGIFINDEX, &ifr);
483 close(sk);
484 if (rc < 0)
485 return rc;
486
487 return ifr.ifr_ifindex;
488}
489
Harald Weltef2949742021-01-20 14:54:14 +0100490static int open_socket(int ifindex, const struct gprs_ns2_vc_bind *nsbind)
Alexander Couzens841817e2020-11-19 00:41:29 +0100491{
492 struct sockaddr_ll addr;
Harald Welte4ed0f4e2020-12-10 21:50:32 +0100493 int fd, rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100494
Alexander Couzens841817e2020-11-19 00:41:29 +0100495 memset(&addr, 0, sizeof(addr));
496 addr.sll_family = AF_PACKET;
497 addr.sll_protocol = htons(ETH_P_ALL);
498 addr.sll_ifindex = ifindex;
499
Harald Welte5bea72e2020-12-10 22:06:21 +0100500 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_HDLC));
Alexander Couzens841817e2020-11-19 00:41:29 +0100501 if (fd < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100502 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 +0100503 return fd;
504 }
505
Harald Welte41b188b2020-12-10 22:00:23 +0100506 /* there's a race condition between the above syscall and the bind() call below,
507 * causing other packets to be received in between */
508
Alexander Couzens841817e2020-11-19 00:41:29 +0100509 rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
510 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100511 LOGBIND(nsbind, LOGL_ERROR, "Can not bind AF_PACKET socket to ifindex %d\n", ifindex);
Alexander Couzens841817e2020-11-19 00:41:29 +0100512 close(fd);
513 return rc;
514 }
515
516 return fd;
517}
518
Harald Welte56f08a32020-12-01 23:07:32 +0100519#ifdef ENABLE_LIBMNL
520
521#include <osmocom/core/mnl.h>
Harald Welte56f08a32020-12-01 23:07:32 +0100522#include <linux/if_link.h>
523#include <linux/rtnetlink.h>
524
525#ifndef ARPHRD_FRAD
526#define ARPHRD_FRAD 770
527#endif
528
529/* validate the netlink attributes */
530static int data_attr_cb(const struct nlattr *attr, void *data)
531{
532 const struct nlattr **tb = data;
533 int type = mnl_attr_get_type(attr);
534
535 if (mnl_attr_type_valid(attr, IFLA_MAX) < 0)
536 return MNL_CB_OK;
537
538 switch (type) {
539 case IFLA_MTU:
540 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
541 return MNL_CB_ERROR;
542 break;
543 case IFLA_IFNAME:
544 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
545 return MNL_CB_ERROR;
546 break;
547 }
548 tb[type] = attr;
549 return MNL_CB_OK;
550}
551
552/* find the bind for the netdev (if any) */
553static struct gprs_ns2_vc_bind *bind4netdev(struct gprs_ns2_inst *nsi, const char *ifname)
554{
555 struct gprs_ns2_vc_bind *bind;
556
557 llist_for_each_entry(bind, &nsi->binding, list) {
558 struct priv_bind *bpriv = bind->priv;
559 if (!strcmp(bpriv->netif, ifname))
560 return bind;
561 }
562
563 return NULL;
564}
565
Harald Welte6972aed2021-02-02 20:29:32 +0100566static void link_state_change(struct gprs_ns2_vc_bind *bind, bool if_running)
567{
568 struct priv_bind *bpriv = bind->priv;
569 struct msgb *msg, *msg2;
570
571 if (bpriv->if_running == if_running)
572 return;
573
574 LOGBIND(bind, LOGL_NOTICE, "FR net-device '%s': Physical link state changed: %s\n",
575 bpriv->netif, if_running ? "UP" : "DOWN");
576
577 /* free any backlog, both on IFUP and IFDOWN. Keep the LMI, as it makes
578 * sense to get one out of the door ASAP. */
579 llist_for_each_entry_safe(msg, msg2, &bpriv->backlog.list, list) {
580 msgb_free(msg);
581 }
582
583 if (if_running) {
584 /* interface just came up */
585 if (bpriv->backlog.lmi_msg)
586 osmo_timer_schedule(&bpriv->backlog.timer, 0, bpriv->backlog.retry_us);
587 } else {
588 /* interface just went down; no need to retransmit */
589 osmo_timer_del(&bpriv->backlog.timer);
590 }
591
592 bpriv->if_running = if_running;
593}
594
Harald Welte56f08a32020-12-01 23:07:32 +0100595/* handle a single netlink message received via libmnl */
596static int linkmon_mnl_cb(const struct nlmsghdr *nlh, void *data)
597{
598 struct osmo_mnl *omnl = data;
599 struct gprs_ns2_vc_bind *bind;
600 struct nlattr *tb[IFLA_MAX+1] = {};
601 struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh);
602 struct gprs_ns2_inst *nsi;
603 const char *ifname;
604 bool if_running;
605
606 OSMO_ASSERT(omnl);
607 OSMO_ASSERT(ifm);
608
609 nsi = omnl->priv;
610
611 if (ifm->ifi_type != ARPHRD_FRAD)
612 return MNL_CB_OK;
613
614 mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, tb);
615
616 if (!tb[IFLA_IFNAME])
617 return MNL_CB_OK;
618 ifname = mnl_attr_get_str(tb[IFLA_IFNAME]);
619 if_running = !!(ifm->ifi_flags & IFF_RUNNING);
620
621 bind = bind4netdev(nsi, ifname);
Harald Welte6972aed2021-02-02 20:29:32 +0100622 if (bind)
623 link_state_change(bind, if_running);
Harald Welte56f08a32020-12-01 23:07:32 +0100624
625 return MNL_CB_OK;
626}
627
628/* trigger one initial dump of all link information */
629static void linkmon_initial_dump(struct osmo_mnl *omnl)
630{
631 char buf[MNL_SOCKET_BUFFER_SIZE];
632 struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
633 struct rtgenmsg *rt;
634
635 nlh->nlmsg_type = RTM_GETLINK;
636 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
637 nlh->nlmsg_seq = time(NULL);
638 rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
639 rt->rtgen_family = AF_PACKET;
640
641 if (mnl_socket_sendto(omnl->mnls, nlh, nlh->nlmsg_len) < 0) {
642 LOGP(DLNS, LOGL_ERROR, "linkmon: Cannot send rtnetlink message: %s\n", strerror(errno));
643 }
644
645 /* the response[s] will be handled just like the events */
646}
647#endif /* LIBMNL */
648
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100649static int set_ifupdown(const char *netif, bool up)
650{
651 int sock, rc;
652 struct ifreq req;
653
654 sock = socket(AF_INET, SOCK_DGRAM, 0);
655 if (sock < 0)
656 return sock;
657
658 memset(&req, 0, sizeof req);
Harald Welte7f01b682020-12-21 12:39:38 +0100659 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100660
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100661 rc = ioctl(sock, SIOCGIFFLAGS, &req);
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100662 if (rc < 0) {
663 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100664 return rc;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100665 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100666
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100667 if ((req.ifr_flags & IFF_UP) == up) {
668 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100669 return 0;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100670 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100671
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100672 if (up)
673 req.ifr_flags |= IFF_UP;
674
675 rc = ioctl(sock, SIOCSIFFLAGS, &req);
676 close(sock);
677 return rc;
678}
679
Harald Weltef2949742021-01-20 14:54:14 +0100680static int setup_device(const char *netif, const struct gprs_ns2_vc_bind *bind)
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100681{
682 int sock, rc;
683 char buffer[128];
684 fr_proto *fr = (void*)buffer;
685 struct ifreq req;
686
687 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
688 if (sock < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100689 LOGBIND(bind, LOGL_ERROR, "%s: Unable to create socket: %s\n",
690 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100691 return sock;
692 }
693
694 memset(&req, 0, sizeof(struct ifreq));
695 memset(&buffer, 0, sizeof(buffer));
Harald Welteb8de1882020-12-21 12:40:45 +0100696 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100697 req.ifr_settings.ifs_ifsu.sync = (void*)buffer;
698 req.ifr_settings.size = sizeof(buffer);
699 req.ifr_settings.type = IF_GET_PROTO;
700
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100701 /* EINVAL is returned when no protocol has been set */
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100702 rc = ioctl(sock, SIOCWANDEV, &req);
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100703 if (rc < 0 && errno != EINVAL) {
Harald Weltef2949742021-01-20 14:54:14 +0100704 LOGBIND(bind, LOGL_ERROR, "%s: Unable to get FR protocol information: %s\n",
705 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100706 goto err;
707 }
708
709 /* check if the device is good */
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100710 if (rc == 0 && req.ifr_settings.type == IF_PROTO_FR && fr->lmi == LMI_NONE) {
Harald Weltef2949742021-01-20 14:54:14 +0100711 LOGBIND(bind, LOGL_NOTICE, "%s: has correct frame relay mode and lmi\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100712 goto ifup;
713 }
714
715 /* modify the device to match */
716 rc = set_ifupdown(netif, false);
717 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100718 LOGBIND(bind, LOGL_ERROR, "Unable to bring down the device %s: %s\n",
719 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100720 goto err;
721 }
722
723 memset(&req, 0, sizeof(struct ifreq));
724 memset(fr, 0, sizeof(fr_proto));
Harald Welteb8de1882020-12-21 12:40:45 +0100725 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100726 req.ifr_settings.type = IF_PROTO_FR;
727 req.ifr_settings.size = sizeof(fr_proto);
728 req.ifr_settings.ifs_ifsu.fr = fr;
729 fr->lmi = LMI_NONE;
730 /* even those settings aren't used, they must be in the range */
731 /* polling verification timer*/
732 fr->t391 = 10;
733 /* link integrity verification polling timer */
734 fr->t392 = 15;
735 /* full status polling counter*/
736 fr->n391 = 6;
737 /* error threshold */
738 fr->n392 = 3;
739 /* monitored events count */
740 fr->n393 = 4;
741
Harald Weltef2949742021-01-20 14:54:14 +0100742 LOGBIND(bind, LOGL_INFO, "%s: Setting frame relay related parameters\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100743 rc = ioctl(sock, SIOCWANDEV, &req);
744 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100745 LOGBIND(bind, LOGL_ERROR, "%s: Unable to set FR protocol on information: %s\n",
746 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100747 goto err;
748 }
749
750ifup:
751 rc = set_ifupdown(netif, true);
752 if (rc)
Harald Weltef2949742021-01-20 14:54:14 +0100753 LOGBIND(bind, LOGL_ERROR, "Unable to bring up the device %s: %s\n",
754 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100755err:
756 close(sock);
757 return rc;
758}
Harald Welte56f08a32020-12-01 23:07:32 +0100759
Alexander Couzens841817e2020-11-19 00:41:29 +0100760/*! Create a new bind for NS over FR.
761 * \param[in] nsi NS instance in which to create the bind
762 * \param[in] netif Network interface to bind to
763 * \param[in] fr_network
764 * \param[in] fr_role
Alexander Couzensc80a8742021-02-03 11:27:52 +0100765 * \param[out] result pointer to the created bind or if a bind with the name exists return the bind.
766 * \return 0 on success; negative on error. -EALREADY returned in case a bind with the name exists */
Alexander Couzens841817e2020-11-19 00:41:29 +0100767int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi,
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100768 const char *name,
Alexander Couzens841817e2020-11-19 00:41:29 +0100769 const char *netif,
770 struct osmo_fr_network *fr_network,
771 enum osmo_fr_role fr_role,
772 struct gprs_ns2_vc_bind **result)
773{
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100774 struct gprs_ns2_vc_bind *bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100775 struct priv_bind *priv;
776 struct osmo_fr_link *fr_link;
777 int rc = 0;
778
Harald Weltec3aa8f92021-01-31 11:41:34 +0100779 if (strlen(netif) > IFNAMSIZ)
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100780 return -EINVAL;
781
Alexander Couzensc80a8742021-02-03 11:27:52 +0100782 bind = gprs_ns2_bind_by_name(nsi, name);
783 if (bind) {
784 if (result)
785 *result = bind;
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100786 return -EALREADY;
Alexander Couzensc80a8742021-02-03 11:27:52 +0100787 }
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100788
Harald Weltec3aa8f92021-01-31 11:41:34 +0100789 rc = ns2_bind_alloc(nsi, name, &bind);
790 if (rc < 0)
791 return rc;
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100792
Alexander Couzens841817e2020-11-19 00:41:29 +0100793 bind->driver = &vc_driver_fr;
Alexander Couzensaac90162020-11-19 02:44:04 +0100794 bind->ll = GPRS_NS2_LL_FR;
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100795 /* 2 mbit */
796 bind->transfer_capability = 2;
Alexander Couzens841817e2020-11-19 00:41:29 +0100797 bind->send_vc = fr_vc_sendmsg;
798 bind->free_vc = free_vc;
799 bind->dump_vty = dump_vty;
Alexander Couzens841817e2020-11-19 00:41:29 +0100800 priv = bind->priv = talloc_zero(bind, struct priv_bind);
801 if (!priv) {
Harald Weltebdfb8b92021-01-31 11:44:57 +0100802 rc = -ENOMEM;
Harald Weltec3aa8f92021-01-31 11:41:34 +0100803 goto err_bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100804 }
805
Neels Hofmeyr8fef7612020-12-17 18:19:19 +0100806 OSMO_STRLCPY_ARRAY(priv->netif, netif);
Alexander Couzens841817e2020-11-19 00:41:29 +0100807
Alexander Couzens841817e2020-11-19 00:41:29 +0100808 /* FIXME: move fd handling into socket.c */
809 fr_link = osmo_fr_link_alloc(fr_network, fr_role, netif);
810 if (!fr_link) {
811 rc = -EINVAL;
Harald Weltec3aa8f92021-01-31 11:41:34 +0100812 goto err_bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100813 }
814
815 fr_link->tx_cb = fr_tx_cb;
Harald Welte2cc1d4d2021-01-31 18:33:31 +0100816 fr_link->cb_data = bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100817 priv->link = fr_link;
Harald Welte41b188b2020-12-10 22:00:23 +0100818
Alexander Couzens6f89c772020-12-17 03:06:39 +0100819 priv->ifindex = rc = devname2ifindex(netif);
820 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100821 LOGBIND(bind, LOGL_ERROR, "Can not get interface index for interface %s\n", netif);
Harald Welte41b188b2020-12-10 22:00:23 +0100822 goto err_fr;
823 }
824
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100825 /* set protocol frame relay and lmi */
Harald Weltef2949742021-01-20 14:54:14 +0100826 rc = setup_device(priv->netif, bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100827 if(rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100828 LOGBIND(bind, LOGL_ERROR, "Failed to setup the interface %s for frame relay and lmi\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100829 goto err_fr;
830 }
831
Harald Weltef2949742021-01-20 14:54:14 +0100832 rc = open_socket(priv->ifindex, bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100833 if (rc < 0)
834 goto err_fr;
Harald Welted06128d2021-01-30 21:17:21 +0100835 INIT_LLIST_HEAD(&priv->backlog.list);
836 priv->backlog.retry_us = 2500; /* start with some non-zero value; this corrsponds to 496 bytes */
837 osmo_timer_setup(&priv->backlog.timer, fr_backlog_timer_cb, bind);
838 osmo_fd_setup(&priv->backlog.ofd, rc, OSMO_FD_READ, fr_netif_ofd_cb, bind, 0);
839 rc = osmo_fd_register(&priv->backlog.ofd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100840 if (rc < 0)
841 goto err_fd;
842
Harald Welte56f08a32020-12-01 23:07:32 +0100843#ifdef ENABLE_LIBMNL
844 if (!nsi->linkmon_mnl)
845 nsi->linkmon_mnl = osmo_mnl_init(nsi, NETLINK_ROUTE, RTMGRP_LINK, linkmon_mnl_cb, nsi);
846
847 /* we get a new full dump after every bind. which is a bit excessive. But that's just once
848 * at start-up, so we can get away with it */
849 if (nsi->linkmon_mnl)
850 linkmon_initial_dump(nsi->linkmon_mnl);
851#endif
852
Harald Weltec3aa8f92021-01-31 11:41:34 +0100853 if (result)
854 *result = bind;
855
Alexander Couzens841817e2020-11-19 00:41:29 +0100856 return rc;
857
858err_fd:
Harald Welted06128d2021-01-30 21:17:21 +0100859 close(priv->backlog.ofd.fd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100860err_fr:
861 osmo_fr_link_free(fr_link);
Alexander Couzens841817e2020-11-19 00:41:29 +0100862err_bind:
Harald Weltec3aa8f92021-01-31 11:41:34 +0100863 gprs_ns2_free_bind(bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100864
865 return rc;
866}
867
Alexander Couzensc782cec2020-12-10 04:10:25 +0100868/*! Return the frame relay role of a bind
869 * \param[in] bind The bind
870 * \return the frame relay role or -EINVAL if bind is not frame relay
871 */
872enum osmo_fr_role gprs_ns2_fr_bind_role(struct gprs_ns2_vc_bind *bind)
873{
874 struct priv_bind *priv;
875
876 if (bind->driver != &vc_driver_fr)
877 return -EINVAL;
878
879 priv = bind->priv;
880 return priv->link->role;
881}
882
Alexander Couzens841817e2020-11-19 00:41:29 +0100883/*! Return the network interface of the bind
884 * \param[in] bind The bind
885 * \return the network interface
886 */
887const char *gprs_ns2_fr_bind_netif(struct gprs_ns2_vc_bind *bind)
888{
889 struct priv_bind *priv;
890
891 if (bind->driver != &vc_driver_fr)
892 return NULL;
893
894 priv = bind->priv;
895 return priv->netif;
896}
897
898/*! Find NS bind for a given network interface
899 * \param[in] nsi NS instance
900 * \param[in] netif the network interface to search for
901 * \return the bind or NULL if not found
902 */
903struct gprs_ns2_vc_bind *gprs_ns2_fr_bind_by_netif(
904 struct gprs_ns2_inst *nsi,
905 const char *netif)
906{
907 struct gprs_ns2_vc_bind *bind;
908 const char *_netif;
909
910 OSMO_ASSERT(nsi);
911 OSMO_ASSERT(netif);
912
913 llist_for_each_entry(bind, &nsi->binding, list) {
914 if (!gprs_ns2_is_fr_bind(bind))
915 continue;
916
917 _netif = gprs_ns2_fr_bind_netif(bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100918 if (!strncmp(_netif, netif, IFNAMSIZ))
Alexander Couzens841817e2020-11-19 00:41:29 +0100919 return bind;
920 }
921
922 return NULL;
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_connect(struct gprs_ns2_vc_bind *bind,
Alexander Couzensebcbd722020-12-03 06:11:39 +0100931 struct gprs_ns2_nse *nse,
932 uint16_t nsvci,
933 uint16_t dlci)
934{
935 struct gprs_ns2_vc *nsvc = NULL;
936 struct priv_vc *priv = NULL;
Harald Welte603f4042020-11-29 17:39:19 +0100937 struct priv_bind *bpriv = bind->priv;
938 char idbuf[64];
Alexander Couzensebcbd722020-12-03 06:11:39 +0100939
Alexander Couzens55bc8692021-01-18 18:39:57 +0100940 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzensebcbd722020-12-03 06:11:39 +0100941 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
942 if (nsvc) {
943 goto err;
944 }
945
Harald Welte603f4042020-11-29 17:39:19 +0100946 snprintf(idbuf, sizeof(idbuf), "%s-%s-DLCI%u-NSE%05u-NSVC%05u", gprs_ns2_lltype_str(nse->ll),
947 bpriv->netif, dlci, nse->nsei, nsvci);
Alexander Couzens138b96f2021-01-25 16:23:29 +0100948 nsvc = ns2_vc_alloc(bind, nse, true, GPRS_NS2_VC_MODE_BLOCKRESET, idbuf);
Alexander Couzensebcbd722020-12-03 06:11:39 +0100949 if (!nsvc)
950 goto err;
951
952 nsvc->priv = priv = fr_alloc_vc(bind, nsvc, dlci);
953 if (!priv)
954 goto err;
955
956 nsvc->nsvci = nsvci;
957 nsvc->nsvci_is_valid = true;
958
Alexander Couzensebcbd722020-12-03 06:11:39 +0100959 return nsvc;
960
961err:
962 gprs_ns2_free_nsvc(nsvc);
963 return NULL;
964}
965
966
967/*! Create, connect and activate a new FR-based NS-VC
968 * \param[in] bind bind in which the new NS-VC is to be created
969 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
970 * \param[in] dlci Data Link connection identifier
971 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
972struct gprs_ns2_vc *gprs_ns2_fr_connect2(struct gprs_ns2_vc_bind *bind,
Alexander Couzens841817e2020-11-19 00:41:29 +0100973 uint16_t nsei,
974 uint16_t nsvci,
975 uint16_t dlci)
976{
977 bool created_nse = false;
978 struct gprs_ns2_vc *nsvc = NULL;
Alexander Couzens55bc8692021-01-18 18:39:57 +0100979 struct gprs_ns2_nse *nse;
980
981 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
982 nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei);
Alexander Couzens841817e2020-11-19 00:41:29 +0100983 if (!nse) {
Alexander Couzens138b96f2021-01-25 16:23:29 +0100984 nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_FR, GPRS_NS2_DIALECT_STATIC_RESETBLOCK);
Alexander Couzens841817e2020-11-19 00:41:29 +0100985 if (!nse)
986 return NULL;
987 created_nse = true;
988 }
989
Harald Welte509047b2021-01-17 19:55:51 +0100990 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
Alexander Couzens841817e2020-11-19 00:41:29 +0100991 if (!nsvc)
992 goto err_nse;
993
Alexander Couzens841817e2020-11-19 00:41:29 +0100994 return nsvc;
995
Alexander Couzens841817e2020-11-19 00:41:29 +0100996err_nse:
997 if (created_nse)
998 gprs_ns2_free_nse(nse);
999
1000 return NULL;
1001}
1002
1003/*! Return the nsvc by dlci.
1004 * \param[in] bind
1005 * \param[in] dlci Data Link connection identifier
1006 * \return the nsvc or NULL if not found
1007 */
1008struct gprs_ns2_vc *gprs_ns2_fr_nsvc_by_dlci(struct gprs_ns2_vc_bind *bind,
1009 uint16_t dlci)
1010{
1011 struct gprs_ns2_vc *nsvc;
1012 struct priv_vc *vcpriv;
1013
Alexander Couzens55bc8692021-01-18 18:39:57 +01001014 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +01001015 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
1016 vcpriv = nsvc->priv;
1017
1018 if (dlci == vcpriv->dlci)
1019 return nsvc;
1020 }
1021
1022 return NULL;
1023}
1024
1025/*! Return the dlci of the nsvc
1026 * \param[in] nsvc
1027 * \return the dlci or 0 on error. 0 is not a valid dlci.
1028 */
Alexander Couzens22c26e02020-12-10 04:10:07 +01001029uint16_t gprs_ns2_fr_nsvc_dlci(const struct gprs_ns2_vc *nsvc)
Alexander Couzens841817e2020-11-19 00:41:29 +01001030{
1031 struct priv_vc *vcpriv;
1032
1033 if (!nsvc->bind)
1034 return 0;
1035
1036 if (nsvc->bind->driver != &vc_driver_fr)
1037 return 0;
1038
1039 vcpriv = nsvc->priv;
1040 return vcpriv->dlci;
1041}