blob: d6516012bd38bf933d546ad7b053913e2c2571b0 [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>
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +010058#include <osmocom/core/netdev.h>
Harald Welted06128d2021-01-30 21:17:21 +010059#include <osmocom/gprs/protocol/gsm_08_16.h>
60#include <osmocom/gprs/protocol/gsm_08_18.h>
Alexander Couzens841817e2020-11-19 00:41:29 +010061
Harald Welte56f08a32020-12-01 23:07:32 +010062#include "config.h"
Alexander Couzens841817e2020-11-19 00:41:29 +010063#include "common_vty.h"
64#include "gprs_ns2_internal.h"
65
66#define GRE_PTYPE_FR 0x6559
67#define GRE_PTYPE_IPv4 0x0800
68#define GRE_PTYPE_IPv6 0x86dd
69#define GRE_PTYPE_KAR 0x0000 /* keepalive response */
70
71#ifndef IPPROTO_GRE
72# define IPPROTO_GRE 47
73#endif
74
Harald Welted06128d2021-01-30 21:17:21 +010075#define E1_LINERATE 2048000
76#define E1_SLOTS_TOTAL 32
77#define E1_SLOTS_USED 31
78/* usable bitrate of the E1 superchannel with 31 of 32 timeslots */
79#define SUPERCHANNEL_LINERATE (E1_LINERATE*E1_SLOTS_USED)/E1_SLOTS_TOTAL
80/* nanoseconds per bit (504) */
81#define BIT_DURATION_NS (1000000000 / SUPERCHANNEL_LINERATE)
82
Alexander Couzens841817e2020-11-19 00:41:29 +010083static void free_bind(struct gprs_ns2_vc_bind *bind);
84static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg);
85
86struct gprs_ns2_vc_driver vc_driver_fr = {
87 .name = "GB frame relay",
88 .free_bind = free_bind,
89};
90
91struct priv_bind {
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +010092 struct osmo_netdev *netdev;
Alexander Couzens5c96f5d2020-12-17 04:45:03 +010093 char netif[IFNAMSIZ];
Alexander Couzens841817e2020-11-19 00:41:29 +010094 struct osmo_fr_link *link;
Harald Welte41b188b2020-12-10 22:00:23 +010095 int ifindex;
Harald Welte56f08a32020-12-01 23:07:32 +010096 bool if_running;
Max73984a82022-10-19 20:37:28 +030097 /* backlog queue for AF_PACKET / ENOBUFS handling (see OS#4995) */
Harald Welted06128d2021-01-30 21:17:21 +010098 struct {
99 /* file-descriptor for AF_PACKET socket */
100 struct osmo_fd ofd;
Harald Welte93740612021-02-02 19:54:10 +0100101 /* LMI bucket (we only store the last LMI message, no need to queue */
102 struct msgb *lmi_msg;
103 /* list of NS msgb (backlog) */
Harald Welted06128d2021-01-30 21:17:21 +0100104 struct llist_head list;
105 /* timer to trigger next attempt of AF_PACKET write */
106 struct osmo_timer_list timer;
107 /* re-try after that many micro-seconds */
108 uint32_t retry_us;
109 } backlog;
Alexander Couzens841817e2020-11-19 00:41:29 +0100110};
111
112struct priv_vc {
113 struct osmo_sockaddr remote;
114 uint16_t dlci;
115 struct osmo_fr_dlc *dlc;
116};
117
118static void free_vc(struct gprs_ns2_vc *nsvc)
119{
Alexander Couzensea377242021-01-17 16:51:55 +0100120 if (!nsvc)
121 return;
Alexander Couzens841817e2020-11-19 00:41:29 +0100122
123 if (!nsvc->priv)
124 return;
125
Alexander Couzens55bc8692021-01-18 18:39:57 +0100126 OSMO_ASSERT(gprs_ns2_is_fr_bind(nsvc->bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100127 talloc_free(nsvc->priv);
128 nsvc->priv = NULL;
129}
130
Alexander Couzens75b61882021-03-21 16:18:17 +0100131static void dump_vty(const struct gprs_ns2_vc_bind *bind, struct vty *vty, bool stats)
Alexander Couzens841817e2020-11-19 00:41:29 +0100132{
133 struct priv_bind *priv;
134 struct gprs_ns2_vc *nsvc;
Harald Welte48bd76c2020-12-01 16:53:06 +0100135 struct osmo_fr_link *fr_link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100136
137 if (!bind)
138 return;
139
140 priv = bind->priv;
Harald Welte48bd76c2020-12-01 16:53:06 +0100141 fr_link = priv->link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100142
Harald Welte56f08a32020-12-01 23:07:32 +0100143 vty_out(vty, "FR bind: %s, role: %s, link: %s%s", priv->netif,
144 osmo_fr_role_str(fr_link->role), priv->if_running ? "UP" : "DOWN", VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +0100145
146 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
Alexander Couzens75b61882021-03-21 16:18:17 +0100147 ns2_vty_dump_nsvc(vty, nsvc, stats);
Alexander Couzens841817e2020-11-19 00:41:29 +0100148 }
149
150 priv = bind->priv;
151}
152
153/*! clean up all private driver state. Should be only called by gprs_ns2_free_bind() */
154static void free_bind(struct gprs_ns2_vc_bind *bind)
155{
156 struct priv_bind *priv;
Harald Welted06128d2021-01-30 21:17:21 +0100157 struct msgb *msg, *msg2;
Alexander Couzens841817e2020-11-19 00:41:29 +0100158
159 if (!bind)
160 return;
161
Alexander Couzens24d9e802021-02-03 11:30:43 +0100162 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100163 priv = bind->priv;
164
165 OSMO_ASSERT(llist_empty(&bind->nsvc));
166
Harald Welted06128d2021-01-30 21:17:21 +0100167 osmo_timer_del(&priv->backlog.timer);
168 llist_for_each_entry_safe(msg, msg2, &priv->backlog.list, list) {
169 msgb_free(msg);
170 }
Harald Welte93740612021-02-02 19:54:10 +0100171 msgb_free(priv->backlog.lmi_msg);
Harald Welted06128d2021-01-30 21:17:21 +0100172
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100173 osmo_netdev_free(priv->netdev);
Alexander Couzens841817e2020-11-19 00:41:29 +0100174 osmo_fr_link_free(priv->link);
Harald Welted06128d2021-01-30 21:17:21 +0100175 osmo_fd_close(&priv->backlog.ofd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100176 talloc_free(priv);
177}
178
Harald Welte9d28ce52021-01-31 18:38:20 +0100179static void fr_dlci_status_cb(struct osmo_fr_dlc *dlc, void *cb_data, bool active)
180{
181 struct gprs_ns2_vc *nsvc = cb_data;
182
183 if (active) {
184 ns2_vc_fsm_start(nsvc);
185 } else {
186 ns2_vc_force_unconfigured(nsvc);
187 }
188}
189
Alexander Couzens841817e2020-11-19 00:41:29 +0100190static struct priv_vc *fr_alloc_vc(struct gprs_ns2_vc_bind *bind,
191 struct gprs_ns2_vc *nsvc,
192 uint16_t dlci)
193{
194 struct priv_bind *privb = bind->priv;
195 struct priv_vc *priv = talloc_zero(bind, struct priv_vc);
196 if (!priv)
197 return NULL;
198
Alexander Couzens55bc8692021-01-18 18:39:57 +0100199 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100200 nsvc->priv = priv;
201 priv->dlci = dlci;
202 priv->dlc = osmo_fr_dlc_alloc(privb->link, dlci);
203 if (!priv->dlc) {
204 nsvc->priv = NULL;
205 talloc_free(priv);
206 return NULL;
207 }
208
Harald Welte2cc1d4d2021-01-31 18:33:31 +0100209 priv->dlc->cb_data = nsvc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100210 priv->dlc->rx_cb = fr_dlci_rx_cb;
Harald Welte9d28ce52021-01-31 18:38:20 +0100211 priv->dlc->status_cb = fr_dlci_status_cb;
Alexander Couzens841817e2020-11-19 00:41:29 +0100212
213 return priv;
214}
215
216int gprs_ns2_find_vc_by_dlci(struct gprs_ns2_vc_bind *bind,
217 uint16_t dlci,
218 struct gprs_ns2_vc **result)
219{
220 struct gprs_ns2_vc *nsvc;
221 struct priv_vc *vcpriv;
222
Alexander Couzens55bc8692021-01-18 18:39:57 +0100223 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100224 if (!result)
225 return -EINVAL;
226
227 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
228 vcpriv = nsvc->priv;
229 if (vcpriv->dlci != dlci) {
230 *result = nsvc;
231 return 0;
232 }
233 }
234
235 return 1;
236}
237
238/* PDU from the network interface towards the fr layer (upwards) */
Harald Welted06128d2021-01-30 21:17:21 +0100239static int fr_netif_ofd_cb(struct osmo_fd *bfd, uint32_t what)
Alexander Couzens841817e2020-11-19 00:41:29 +0100240{
241 struct gprs_ns2_vc_bind *bind = bfd->data;
242 struct priv_bind *priv = bind->priv;
Harald Welted06128d2021-01-30 21:17:21 +0100243 struct msgb *msg;
Harald Welte41b188b2020-12-10 22:00:23 +0100244 struct sockaddr_ll sll;
245 socklen_t sll_len = sizeof(sll);
Alexander Couzens841817e2020-11-19 00:41:29 +0100246 int rc = 0;
247
Harald Welted06128d2021-01-30 21:17:21 +0100248 /* we only handle read here. write to AF_PACKET sockets cannot be triggered
249 * by select or poll, see OS#4995 */
250 if (!(what & OSMO_FD_READ))
251 return 0;
252
Daniel Willmann1f666e82021-10-26 16:15:51 +0200253 msg = msgb_alloc(NS_ALLOC_SIZE, "Gb/NS/FR Rx");
Alexander Couzens841817e2020-11-19 00:41:29 +0100254 if (!msg)
255 return -ENOMEM;
256
Harald Welte41b188b2020-12-10 22:00:23 +0100257 rc = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0, (struct sockaddr *)&sll, &sll_len);
Alexander Couzens841817e2020-11-19 00:41:29 +0100258 if (rc < 0) {
Daniel Willmann1f666e82021-10-26 16:15:51 +0200259 LOGBIND(bind, LOGL_ERROR, "recv error %s during NS-FR recv\n", strerror(errno));
Alexander Couzens841817e2020-11-19 00:41:29 +0100260 goto out_err;
261 } else if (rc == 0) {
262 goto out_err;
263 }
264
Harald Welte41b188b2020-12-10 22:00:23 +0100265 /* ignore any packets that we might have received for a different interface, between
266 * the socket() and the bind() call */
267 if (sll.sll_ifindex != priv->ifindex)
268 goto out_err;
269
Alexander Couzens841817e2020-11-19 00:41:29 +0100270 msgb_put(msg, rc);
271 msg->dst = priv->link;
272 return osmo_fr_rx(msg);
273
274out_err:
275 msgb_free(msg);
276 return rc;
277}
278
279/* PDU from the frame relay towards the NS-VC (upwards) */
280static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg)
281{
282 int rc;
283 struct gprs_ns2_vc *nsvc = cb_data;
284
285 rc = ns2_recv_vc(nsvc, msg);
286
287 return rc;
288}
289
Harald Welted06128d2021-01-30 21:17:21 +0100290static int fr_netif_write_one(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
Alexander Couzens841817e2020-11-19 00:41:29 +0100291{
Harald Welted06128d2021-01-30 21:17:21 +0100292 struct priv_bind *priv = bind->priv;
293 unsigned int len = msgb_length(msg);
Harald Weltef0073d72021-01-30 11:41:13 +0100294 int rc;
295
Harald Welted06128d2021-01-30 21:17:21 +0100296 /* estimate the retry time based on the data rate it takes to transmit */
297 priv->backlog.retry_us = (BIT_DURATION_NS * 8 * len) / 1000;
298
299 rc = write(priv->backlog.ofd.fd, msgb_data(msg), len);
300 if (rc == len) {
301 msgb_free(msg);
302 return 0;
303 } else if (rc < 0) {
304 /* don't free, the caller might want to re-transmit */
305 switch (errno) {
306 case EAGAIN:
307 case ENOBUFS:
Harald Welte9811f492021-02-02 22:58:00 +0100308 /* not a real error, but more a normal event on AF_PACKET */
309 /* don't free the message and let the caller re-enqueue */
Harald Welted06128d2021-01-30 21:17:21 +0100310 return -errno;
311 default:
Harald Welte9811f492021-02-02 22:58:00 +0100312 /* an actual error, like -ENETDOWN, -EMSGSIZE */
Harald Welted06128d2021-01-30 21:17:21 +0100313 LOGBIND(bind, LOGL_ERROR, "error during write to AF_PACKET: %s\n", strerror(errno));
Harald Welte9811f492021-02-02 22:58:00 +0100314 msgb_free(msg);
315 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100316 }
317 } else {
318 /* short write */
319 LOGBIND(bind, LOGL_ERROR, "short write on AF_PACKET: %d < %d\n", rc, len);
320 msgb_free(msg);
321 return 0;
322 }
Alexander Couzens841817e2020-11-19 00:41:29 +0100323}
324
325/*! determine if given bind is for FR-GRE encapsulation. */
326int gprs_ns2_is_fr_bind(struct gprs_ns2_vc_bind *bind)
327{
328 return (bind->driver == &vc_driver_fr);
329}
330
331/* PDU from the NS-VC towards the frame relay layer (downwards) */
332static int fr_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
333{
334 struct priv_vc *vcpriv = nsvc->priv;
335
336 msg->dst = vcpriv->dlc;
337 return osmo_fr_tx_dlc(msg);
338}
339
Harald Welted06128d2021-01-30 21:17:21 +0100340static void enqueue_at_head(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
341{
342 struct priv_bind *priv = bind->priv;
343 llist_add(&msg->list, &priv->backlog.list);
Pau Espin Pedrol7b894a72021-06-04 18:17:12 +0200344 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 +0100345 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
346}
347
348static void enqueue_at_tail(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
349{
350 struct priv_bind *priv = bind->priv;
351 llist_add_tail(&msg->list, &priv->backlog.list);
Pau Espin Pedrol7b894a72021-06-04 18:17:12 +0200352 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 +0100353 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
354}
355
356#define LMI_Q933A_DLCI 0
357
358/* enqueue to backlog (LMI, signaling) or drop (userdata msg) */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100359static int backlog_enqueue_or_free(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
Harald Welted06128d2021-01-30 21:17:21 +0100360{
Harald Welte93740612021-02-02 19:54:10 +0100361 struct priv_bind *priv = bind->priv;
Harald Welted06128d2021-01-30 21:17:21 +0100362 uint8_t dlci = msg->data[0];
363 uint8_t ns_pdu_type;
364 uint16_t bvci;
365
366 if (msgb_length(msg) < 1)
367 goto out_free;
368
369 /* we want to enqueue only Q.933 LMI traffic or NS signaling; NOT user traffic */
370 switch (dlci) {
371 case LMI_Q933A_DLCI:
Harald Welte93740612021-02-02 19:54:10 +0100372 /* always store only the last LMI message in the lmi_msg bucket */
373 msgb_free(priv->backlog.lmi_msg);
374 priv->backlog.lmi_msg = msg;
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100375 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100376 default:
Harald Welte6972aed2021-02-02 20:29:32 +0100377 /* there's no point in trying to enqueue messages if the interface is down */
378 if (!priv->if_running)
379 break;
380
Harald Welted06128d2021-01-30 21:17:21 +0100381 if (msgb_length(msg) < 3)
382 break;
383 ns_pdu_type = msg->data[2];
384 switch (ns_pdu_type) {
385 case NS_PDUT_UNITDATA:
386 if (msgb_length(msg) < 6)
387 break;
388 bvci = osmo_load16be(msg->data + 4);
389 /* enqueue BVCI=0 traffic at tail of queue */
390 if (bvci == BVCI_SIGNALLING) {
391 enqueue_at_tail(bind, msg);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100392 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100393 }
394 break;
395 default:
396 /* enqueue NS signaling traffic at head of queue */
397 enqueue_at_head(bind, msg);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100398 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100399 }
400 break;
401 }
402
403out_free:
404 /* drop everything that is not LMI, NS-signaling or BVCI-0 */
405 msgb_free(msg);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100406 return -1;
Harald Welted06128d2021-01-30 21:17:21 +0100407}
408
409static void fr_backlog_timer_cb(void *data)
410{
411 struct gprs_ns2_vc_bind *bind = data;
412 struct priv_bind *priv = bind->priv;
413 int i, rc;
414
Harald Welte93740612021-02-02 19:54:10 +0100415 /* first try to get rid of the LMI message, if any */
416 if (priv->backlog.lmi_msg) {
417 rc = fr_netif_write_one(bind, priv->backlog.lmi_msg);
418 if (rc < 0)
419 goto restart_timer;
420 /* fr_netif_write_one() has just free'd it */
421 priv->backlog.lmi_msg = NULL;
422 }
423
Harald Welted06128d2021-01-30 21:17:21 +0100424 /* attempt to send up to 10 messages in every timer */
425 for (i = 0; i < 10; i++) {
426 struct msgb *msg = msgb_dequeue(&priv->backlog.list);
427 if (!msg)
428 break;
429
430 rc = fr_netif_write_one(bind, msg);
431 if (rc < 0) {
432 /* re-add at head of list */
433 llist_add(&msg->list, &priv->backlog.list);
434 break;
435 }
Pau Espin Pedrol7b894a72021-06-04 18:17:12 +0200436 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 +0100437 }
438
Harald Welte93740612021-02-02 19:54:10 +0100439restart_timer:
Harald Welted06128d2021-01-30 21:17:21 +0100440 /* re-start timer if we still have data in the queue */
441 if (!llist_empty(&priv->backlog.list))
442 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
443}
444
Alexander Couzens841817e2020-11-19 00:41:29 +0100445/* PDU from the frame relay layer towards the network interface (downwards) */
446int fr_tx_cb(void *data, struct msgb *msg)
447{
448 struct gprs_ns2_vc_bind *bind = data;
449 struct priv_bind *priv = bind->priv;
Harald Welted06128d2021-01-30 21:17:21 +0100450 int rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100451
Harald Welted06128d2021-01-30 21:17:21 +0100452 if (llist_empty(&priv->backlog.list)) {
453 /* attempt to transmit right now */
454 rc = fr_netif_write_one(bind, msg);
455 if (rc < 0) {
456 /* enqueue to backlog in case it fails */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100457 return backlog_enqueue_or_free(bind, msg);
Harald Welted06128d2021-01-30 21:17:21 +0100458 }
459 } else {
460 /* enqueue to backlog */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100461 return backlog_enqueue_or_free(bind, msg);
Alexander Couzens60021a42020-12-17 02:48:22 +0100462 }
Alexander Couzens841817e2020-11-19 00:41:29 +0100463
Alexander Couzens60021a42020-12-17 02:48:22 +0100464 return 0;
Alexander Couzens841817e2020-11-19 00:41:29 +0100465}
466
467static int devname2ifindex(const char *ifname)
468{
469 struct ifreq ifr;
470 int sk, rc;
471
472 sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
473 if (sk < 0)
474 return sk;
475
476
477 memset(&ifr, 0, sizeof(ifr));
Neels Hofmeyr475a0ac2020-12-17 18:10:34 +0100478 OSMO_STRLCPY_ARRAY(ifr.ifr_name, ifname);
Alexander Couzens841817e2020-11-19 00:41:29 +0100479
480 rc = ioctl(sk, SIOCGIFINDEX, &ifr);
481 close(sk);
482 if (rc < 0)
483 return rc;
484
485 return ifr.ifr_ifindex;
486}
487
Harald Weltef2949742021-01-20 14:54:14 +0100488static int open_socket(int ifindex, const struct gprs_ns2_vc_bind *nsbind)
Alexander Couzens841817e2020-11-19 00:41:29 +0100489{
490 struct sockaddr_ll addr;
Harald Welte4ed0f4e2020-12-10 21:50:32 +0100491 int fd, rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100492
Alexander Couzens841817e2020-11-19 00:41:29 +0100493 memset(&addr, 0, sizeof(addr));
494 addr.sll_family = AF_PACKET;
495 addr.sll_protocol = htons(ETH_P_ALL);
496 addr.sll_ifindex = ifindex;
497
Harald Welte5bea72e2020-12-10 22:06:21 +0100498 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_HDLC));
Alexander Couzens841817e2020-11-19 00:41:29 +0100499 if (fd < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100500 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 +0100501 return fd;
502 }
503
Harald Welte41b188b2020-12-10 22:00:23 +0100504 /* there's a race condition between the above syscall and the bind() call below,
505 * causing other packets to be received in between */
506
Alexander Couzens841817e2020-11-19 00:41:29 +0100507 rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
508 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100509 LOGBIND(nsbind, LOGL_ERROR, "Can not bind AF_PACKET socket to ifindex %d\n", ifindex);
Alexander Couzens841817e2020-11-19 00:41:29 +0100510 close(fd);
511 return rc;
512 }
513
514 return fd;
515}
516
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100517static int gprs_n2_fr_ifupdown_ind_cb(struct osmo_netdev *netdev, bool if_running)
Harald Welte56f08a32020-12-01 23:07:32 +0100518{
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100519 struct gprs_ns2_vc_bind *bind = osmo_netdev_get_priv_data(netdev);
Harald Welte6972aed2021-02-02 20:29:32 +0100520 struct priv_bind *bpriv = bind->priv;
521 struct msgb *msg, *msg2;
522
523 if (bpriv->if_running == if_running)
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100524 return 0;
Harald Welte6972aed2021-02-02 20:29:32 +0100525
526 LOGBIND(bind, LOGL_NOTICE, "FR net-device '%s': Physical link state changed: %s\n",
527 bpriv->netif, if_running ? "UP" : "DOWN");
528
529 /* free any backlog, both on IFUP and IFDOWN. Keep the LMI, as it makes
530 * sense to get one out of the door ASAP. */
531 llist_for_each_entry_safe(msg, msg2, &bpriv->backlog.list, list) {
532 msgb_free(msg);
533 }
534
535 if (if_running) {
536 /* interface just came up */
537 if (bpriv->backlog.lmi_msg)
538 osmo_timer_schedule(&bpriv->backlog.timer, 0, bpriv->backlog.retry_us);
539 } else {
540 /* interface just went down; no need to retransmit */
541 osmo_timer_del(&bpriv->backlog.timer);
542 }
543
544 bpriv->if_running = if_running;
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100545 return 0;
Harald Welte6972aed2021-02-02 20:29:32 +0100546}
547
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100548static int gprs_n2_fr_mtu_chg_cb(struct osmo_netdev *netdev, uint32_t new_mtu)
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100549{
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100550 struct gprs_ns2_vc_bind *bind = osmo_netdev_get_priv_data(netdev);
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100551 struct priv_bind *bpriv = bind->priv;
552 struct gprs_ns2_nse *nse;
553
Alexander Couzensa6096ad2021-07-02 16:23:06 +0200554 /* 2 byte DLCI header */
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100555 if (new_mtu <= 2)
556 return 0;
557 new_mtu -= 2;
Alexander Couzensa6096ad2021-07-02 16:23:06 +0200558
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100559 if (new_mtu == bind->mtu)
560 return 0;
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100561
562 LOGBIND(bind, LOGL_INFO, "MTU changed from %d to %d.\n",
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100563 bind->mtu + 2, new_mtu + 2);
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100564
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100565 bind->mtu = new_mtu;
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100566 if (!bpriv->if_running)
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100567 return 0;
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100568
569 llist_for_each_entry(nse, &bind->nsi->nse, list) {
570 ns2_nse_update_mtu(nse);
571 }
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100572 return 0;
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100573}
574
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100575static int set_ifupdown(const char *netif, bool up)
576{
577 int sock, rc;
578 struct ifreq req;
579
580 sock = socket(AF_INET, SOCK_DGRAM, 0);
581 if (sock < 0)
582 return sock;
583
584 memset(&req, 0, sizeof req);
Harald Welte7f01b682020-12-21 12:39:38 +0100585 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100586
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100587 rc = ioctl(sock, SIOCGIFFLAGS, &req);
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100588 if (rc < 0) {
589 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100590 return rc;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100591 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100592
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100593 if ((req.ifr_flags & IFF_UP) == up) {
594 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100595 return 0;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100596 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100597
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100598 if (up)
599 req.ifr_flags |= IFF_UP;
600
601 rc = ioctl(sock, SIOCSIFFLAGS, &req);
602 close(sock);
603 return rc;
604}
605
Harald Weltef2949742021-01-20 14:54:14 +0100606static int setup_device(const char *netif, const struct gprs_ns2_vc_bind *bind)
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100607{
608 int sock, rc;
609 char buffer[128];
610 fr_proto *fr = (void*)buffer;
611 struct ifreq req;
612
613 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
614 if (sock < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100615 LOGBIND(bind, LOGL_ERROR, "%s: Unable to create socket: %s\n",
616 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100617 return sock;
618 }
619
620 memset(&req, 0, sizeof(struct ifreq));
621 memset(&buffer, 0, sizeof(buffer));
Harald Welteb8de1882020-12-21 12:40:45 +0100622 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100623 req.ifr_settings.ifs_ifsu.sync = (void*)buffer;
624 req.ifr_settings.size = sizeof(buffer);
625 req.ifr_settings.type = IF_GET_PROTO;
626
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100627 /* EINVAL is returned when no protocol has been set */
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100628 rc = ioctl(sock, SIOCWANDEV, &req);
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100629 if (rc < 0 && errno != EINVAL) {
Harald Weltef2949742021-01-20 14:54:14 +0100630 LOGBIND(bind, LOGL_ERROR, "%s: Unable to get FR protocol information: %s\n",
631 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100632 goto err;
633 }
634
635 /* check if the device is good */
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100636 if (rc == 0 && req.ifr_settings.type == IF_PROTO_FR && fr->lmi == LMI_NONE) {
Harald Weltef2949742021-01-20 14:54:14 +0100637 LOGBIND(bind, LOGL_NOTICE, "%s: has correct frame relay mode and lmi\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100638 goto ifup;
639 }
640
641 /* modify the device to match */
642 rc = set_ifupdown(netif, false);
643 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100644 LOGBIND(bind, LOGL_ERROR, "Unable to bring down the device %s: %s\n",
645 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100646 goto err;
647 }
648
649 memset(&req, 0, sizeof(struct ifreq));
650 memset(fr, 0, sizeof(fr_proto));
Harald Welteb8de1882020-12-21 12:40:45 +0100651 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100652 req.ifr_settings.type = IF_PROTO_FR;
653 req.ifr_settings.size = sizeof(fr_proto);
654 req.ifr_settings.ifs_ifsu.fr = fr;
655 fr->lmi = LMI_NONE;
656 /* even those settings aren't used, they must be in the range */
657 /* polling verification timer*/
658 fr->t391 = 10;
659 /* link integrity verification polling timer */
660 fr->t392 = 15;
661 /* full status polling counter*/
662 fr->n391 = 6;
663 /* error threshold */
664 fr->n392 = 3;
665 /* monitored events count */
666 fr->n393 = 4;
667
Harald Weltef2949742021-01-20 14:54:14 +0100668 LOGBIND(bind, LOGL_INFO, "%s: Setting frame relay related parameters\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100669 rc = ioctl(sock, SIOCWANDEV, &req);
670 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100671 LOGBIND(bind, LOGL_ERROR, "%s: Unable to set FR protocol on information: %s\n",
672 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100673 goto err;
674 }
675
676ifup:
677 rc = set_ifupdown(netif, true);
678 if (rc)
Harald Weltef2949742021-01-20 14:54:14 +0100679 LOGBIND(bind, LOGL_ERROR, "Unable to bring up the device %s: %s\n",
680 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100681err:
682 close(sock);
683 return rc;
684}
Harald Welte56f08a32020-12-01 23:07:32 +0100685
Alexander Couzens841817e2020-11-19 00:41:29 +0100686/*! Create a new bind for NS over FR.
687 * \param[in] nsi NS instance in which to create the bind
688 * \param[in] netif Network interface to bind to
689 * \param[in] fr_network
690 * \param[in] fr_role
Alexander Couzensc80a8742021-02-03 11:27:52 +0100691 * \param[out] result pointer to the created bind or if a bind with the name exists return the bind.
692 * \return 0 on success; negative on error. -EALREADY returned in case a bind with the name exists */
Alexander Couzens841817e2020-11-19 00:41:29 +0100693int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi,
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100694 const char *name,
Alexander Couzens841817e2020-11-19 00:41:29 +0100695 const char *netif,
696 struct osmo_fr_network *fr_network,
697 enum osmo_fr_role fr_role,
698 struct gprs_ns2_vc_bind **result)
699{
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100700 struct gprs_ns2_vc_bind *bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100701 struct priv_bind *priv;
702 struct osmo_fr_link *fr_link;
703 int rc = 0;
704
Harald Weltec3aa8f92021-01-31 11:41:34 +0100705 if (strlen(netif) > IFNAMSIZ)
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100706 return -EINVAL;
707
Alexander Couzensc80a8742021-02-03 11:27:52 +0100708 bind = gprs_ns2_bind_by_name(nsi, name);
709 if (bind) {
710 if (result)
711 *result = bind;
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100712 return -EALREADY;
Alexander Couzensc80a8742021-02-03 11:27:52 +0100713 }
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100714
Harald Weltec3aa8f92021-01-31 11:41:34 +0100715 rc = ns2_bind_alloc(nsi, name, &bind);
716 if (rc < 0)
717 return rc;
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100718
Alexander Couzens841817e2020-11-19 00:41:29 +0100719 bind->driver = &vc_driver_fr;
Alexander Couzensaac90162020-11-19 02:44:04 +0100720 bind->ll = GPRS_NS2_LL_FR;
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100721 /* 2 mbit */
722 bind->transfer_capability = 2;
Alexander Couzens841817e2020-11-19 00:41:29 +0100723 bind->send_vc = fr_vc_sendmsg;
724 bind->free_vc = free_vc;
725 bind->dump_vty = dump_vty;
Alexander Couzens4f1128f2021-01-20 17:42:48 +0100726 bind->mtu = FRAME_RELAY_SDU;
Alexander Couzens841817e2020-11-19 00:41:29 +0100727 priv = bind->priv = talloc_zero(bind, struct priv_bind);
728 if (!priv) {
Harald Weltebdfb8b92021-01-31 11:44:57 +0100729 rc = -ENOMEM;
Harald Weltec3aa8f92021-01-31 11:41:34 +0100730 goto err_bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100731 }
732
Harald Weltece6e4b72021-02-11 15:58:40 +0100733 INIT_LLIST_HEAD(&priv->backlog.list);
Neels Hofmeyr8fef7612020-12-17 18:19:19 +0100734 OSMO_STRLCPY_ARRAY(priv->netif, netif);
Alexander Couzens841817e2020-11-19 00:41:29 +0100735
Alexander Couzens841817e2020-11-19 00:41:29 +0100736 /* FIXME: move fd handling into socket.c */
737 fr_link = osmo_fr_link_alloc(fr_network, fr_role, netif);
738 if (!fr_link) {
739 rc = -EINVAL;
Harald Weltec3aa8f92021-01-31 11:41:34 +0100740 goto err_bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100741 }
742
743 fr_link->tx_cb = fr_tx_cb;
Harald Welte2cc1d4d2021-01-31 18:33:31 +0100744 fr_link->cb_data = bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100745 priv->link = fr_link;
Harald Welte41b188b2020-12-10 22:00:23 +0100746
Alexander Couzens6f89c772020-12-17 03:06:39 +0100747 priv->ifindex = rc = devname2ifindex(netif);
748 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100749 LOGBIND(bind, LOGL_ERROR, "Can not get interface index for interface %s\n", netif);
Harald Welte41b188b2020-12-10 22:00:23 +0100750 goto err_fr;
751 }
752
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100753 priv->netdev = osmo_netdev_alloc(bind, name);
754 if (!priv->netdev) {
755 rc = -ENOENT;
756 goto err_fr;
757 }
758 osmo_netdev_set_priv_data(priv->netdev, bind);
759 osmo_netdev_set_ifupdown_ind_cb(priv->netdev, gprs_n2_fr_ifupdown_ind_cb);
760 osmo_netdev_set_mtu_chg_cb(priv->netdev, gprs_n2_fr_mtu_chg_cb);
761 rc = osmo_netdev_set_ifindex(priv->netdev, priv->ifindex);
762 if (rc < 0)
763 goto err_free_netdev;
764 rc = osmo_netdev_register(priv->netdev);
765 if (rc < 0)
766 goto err_free_netdev;
767
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100768 /* set protocol frame relay and lmi */
Harald Weltef2949742021-01-20 14:54:14 +0100769 rc = setup_device(priv->netif, bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100770 if(rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100771 LOGBIND(bind, LOGL_ERROR, "Failed to setup the interface %s for frame relay and lmi\n", netif);
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100772 goto err_free_netdev;
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100773 }
774
Harald Weltef2949742021-01-20 14:54:14 +0100775 rc = open_socket(priv->ifindex, bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100776 if (rc < 0)
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100777 goto err_free_netdev;
Harald Welted06128d2021-01-30 21:17:21 +0100778 priv->backlog.retry_us = 2500; /* start with some non-zero value; this corrsponds to 496 bytes */
779 osmo_timer_setup(&priv->backlog.timer, fr_backlog_timer_cb, bind);
780 osmo_fd_setup(&priv->backlog.ofd, rc, OSMO_FD_READ, fr_netif_ofd_cb, bind, 0);
781 rc = osmo_fd_register(&priv->backlog.ofd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100782 if (rc < 0)
783 goto err_fd;
784
Harald Weltec3aa8f92021-01-31 11:41:34 +0100785 if (result)
786 *result = bind;
787
Alexander Couzens841817e2020-11-19 00:41:29 +0100788 return rc;
789
790err_fd:
Harald Welted06128d2021-01-30 21:17:21 +0100791 close(priv->backlog.ofd.fd);
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100792err_free_netdev:
793 osmo_netdev_free(priv->netdev);
794 priv->netdev = NULL;
Alexander Couzens841817e2020-11-19 00:41:29 +0100795err_fr:
796 osmo_fr_link_free(fr_link);
Harald Welte855155c2021-02-11 16:07:18 +0100797 priv->link = NULL;
Alexander Couzens841817e2020-11-19 00:41:29 +0100798err_bind:
Harald Weltec3aa8f92021-01-31 11:41:34 +0100799 gprs_ns2_free_bind(bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100800
801 return rc;
802}
803
Alexander Couzensc782cec2020-12-10 04:10:25 +0100804/*! Return the frame relay role of a bind
805 * \param[in] bind The bind
806 * \return the frame relay role or -EINVAL if bind is not frame relay
807 */
808enum osmo_fr_role gprs_ns2_fr_bind_role(struct gprs_ns2_vc_bind *bind)
809{
810 struct priv_bind *priv;
811
812 if (bind->driver != &vc_driver_fr)
813 return -EINVAL;
814
815 priv = bind->priv;
816 return priv->link->role;
817}
818
Alexander Couzens841817e2020-11-19 00:41:29 +0100819/*! Return the network interface of the bind
820 * \param[in] bind The bind
821 * \return the network interface
822 */
823const char *gprs_ns2_fr_bind_netif(struct gprs_ns2_vc_bind *bind)
824{
825 struct priv_bind *priv;
826
827 if (bind->driver != &vc_driver_fr)
828 return NULL;
829
830 priv = bind->priv;
831 return priv->netif;
832}
833
834/*! Find NS bind for a given network interface
835 * \param[in] nsi NS instance
836 * \param[in] netif the network interface to search for
837 * \return the bind or NULL if not found
838 */
839struct gprs_ns2_vc_bind *gprs_ns2_fr_bind_by_netif(
840 struct gprs_ns2_inst *nsi,
841 const char *netif)
842{
843 struct gprs_ns2_vc_bind *bind;
844 const char *_netif;
845
846 OSMO_ASSERT(nsi);
847 OSMO_ASSERT(netif);
848
849 llist_for_each_entry(bind, &nsi->binding, list) {
850 if (!gprs_ns2_is_fr_bind(bind))
851 continue;
852
853 _netif = gprs_ns2_fr_bind_netif(bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100854 if (!strncmp(_netif, netif, IFNAMSIZ))
Alexander Couzens841817e2020-11-19 00:41:29 +0100855 return bind;
856 }
857
858 return NULL;
859}
860
861/*! Create, connect and activate a new FR-based NS-VC
862 * \param[in] bind bind in which the new NS-VC is to be created
863 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
864 * \param[in] dlci Data Link connection identifier
865 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
866struct gprs_ns2_vc *gprs_ns2_fr_connect(struct gprs_ns2_vc_bind *bind,
Alexander Couzensebcbd722020-12-03 06:11:39 +0100867 struct gprs_ns2_nse *nse,
868 uint16_t nsvci,
869 uint16_t dlci)
870{
871 struct gprs_ns2_vc *nsvc = NULL;
872 struct priv_vc *priv = NULL;
Harald Welte603f4042020-11-29 17:39:19 +0100873 struct priv_bind *bpriv = bind->priv;
874 char idbuf[64];
Alexander Couzensebcbd722020-12-03 06:11:39 +0100875
Alexander Couzens55bc8692021-01-18 18:39:57 +0100876 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzensebcbd722020-12-03 06:11:39 +0100877 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
878 if (nsvc) {
879 goto err;
880 }
881
Alexander Couzensd7948062021-06-03 20:35:47 +0200882 snprintf(idbuf, sizeof(idbuf), "NSE%05u-NSVC%05u-%s-%s-DLCI%u", nse->nsei, nsvci,
883 gprs_ns2_lltype_str(nse->ll), bpriv->netif, dlci);
884 osmo_identifier_sanitize_buf(idbuf, NULL, '_');
Alexander Couzens138b96f2021-01-25 16:23:29 +0100885 nsvc = ns2_vc_alloc(bind, nse, true, GPRS_NS2_VC_MODE_BLOCKRESET, idbuf);
Alexander Couzensebcbd722020-12-03 06:11:39 +0100886 if (!nsvc)
887 goto err;
888
889 nsvc->priv = priv = fr_alloc_vc(bind, nsvc, dlci);
890 if (!priv)
891 goto err;
892
893 nsvc->nsvci = nsvci;
894 nsvc->nsvci_is_valid = true;
895
Alexander Couzensebcbd722020-12-03 06:11:39 +0100896 return nsvc;
897
898err:
899 gprs_ns2_free_nsvc(nsvc);
900 return NULL;
901}
902
903
904/*! Create, connect and activate a new FR-based NS-VC
905 * \param[in] bind bind in which the new NS-VC is to be created
906 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
907 * \param[in] dlci Data Link connection identifier
908 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
909struct gprs_ns2_vc *gprs_ns2_fr_connect2(struct gprs_ns2_vc_bind *bind,
Alexander Couzens841817e2020-11-19 00:41:29 +0100910 uint16_t nsei,
911 uint16_t nsvci,
912 uint16_t dlci)
913{
914 bool created_nse = false;
915 struct gprs_ns2_vc *nsvc = NULL;
Alexander Couzens55bc8692021-01-18 18:39:57 +0100916 struct gprs_ns2_nse *nse;
917
918 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
919 nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei);
Alexander Couzens841817e2020-11-19 00:41:29 +0100920 if (!nse) {
Alexander Couzens138b96f2021-01-25 16:23:29 +0100921 nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_FR, GPRS_NS2_DIALECT_STATIC_RESETBLOCK);
Alexander Couzens841817e2020-11-19 00:41:29 +0100922 if (!nse)
923 return NULL;
924 created_nse = true;
925 }
926
Harald Welte509047b2021-01-17 19:55:51 +0100927 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
Alexander Couzens841817e2020-11-19 00:41:29 +0100928 if (!nsvc)
929 goto err_nse;
930
Alexander Couzens841817e2020-11-19 00:41:29 +0100931 return nsvc;
932
Alexander Couzens841817e2020-11-19 00:41:29 +0100933err_nse:
934 if (created_nse)
935 gprs_ns2_free_nse(nse);
936
937 return NULL;
938}
939
940/*! Return the nsvc by dlci.
941 * \param[in] bind
942 * \param[in] dlci Data Link connection identifier
943 * \return the nsvc or NULL if not found
944 */
945struct gprs_ns2_vc *gprs_ns2_fr_nsvc_by_dlci(struct gprs_ns2_vc_bind *bind,
946 uint16_t dlci)
947{
948 struct gprs_ns2_vc *nsvc;
949 struct priv_vc *vcpriv;
950
Alexander Couzens55bc8692021-01-18 18:39:57 +0100951 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100952 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
953 vcpriv = nsvc->priv;
954
955 if (dlci == vcpriv->dlci)
956 return nsvc;
957 }
958
959 return NULL;
960}
961
962/*! Return the dlci of the nsvc
963 * \param[in] nsvc
964 * \return the dlci or 0 on error. 0 is not a valid dlci.
965 */
Alexander Couzens22c26e02020-12-10 04:10:07 +0100966uint16_t gprs_ns2_fr_nsvc_dlci(const struct gprs_ns2_vc *nsvc)
Alexander Couzens841817e2020-11-19 00:41:29 +0100967{
968 struct priv_vc *vcpriv;
969
970 if (!nsvc->bind)
971 return 0;
972
973 if (nsvc->bind->driver != &vc_driver_fr)
974 return 0;
975
976 vcpriv = nsvc->priv;
977 return vcpriv->dlci;
978}