blob: f6bee39cdfe9cb2d659b8ba3889161c4eb8ffa79 [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;
Pau Espin Pedrol8f026bf2023-04-27 16:00:01 +0200335 unsigned int vc_len = msgb_length(msg);
336 int rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100337
338 msg->dst = vcpriv->dlc;
Pau Espin Pedrol8f026bf2023-04-27 16:00:01 +0200339 rc = osmo_fr_tx_dlc(msg);
340 if (OSMO_LIKELY(rc >= 0)) {
341 RATE_CTR_INC_NS(nsvc, NS_CTR_PKTS_OUT);
342 RATE_CTR_ADD_NS(nsvc, NS_CTR_BYTES_OUT, vc_len);
343 } else {
344 RATE_CTR_INC_NS(nsvc, NS_CTR_PKTS_OUT_DROP);
345 RATE_CTR_ADD_NS(nsvc, NS_CTR_BYTES_OUT_DROP, vc_len);
346 }
347 return rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100348}
349
Harald Welted06128d2021-01-30 21:17:21 +0100350static void enqueue_at_head(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
351{
352 struct priv_bind *priv = bind->priv;
353 llist_add(&msg->list, &priv->backlog.list);
Pau Espin Pedrol7b894a72021-06-04 18:17:12 +0200354 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 +0100355 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
356}
357
358static void enqueue_at_tail(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
359{
360 struct priv_bind *priv = bind->priv;
361 llist_add_tail(&msg->list, &priv->backlog.list);
Pau Espin Pedrol7b894a72021-06-04 18:17:12 +0200362 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 +0100363 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
364}
365
366#define LMI_Q933A_DLCI 0
367
368/* enqueue to backlog (LMI, signaling) or drop (userdata msg) */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100369static int backlog_enqueue_or_free(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
Harald Welted06128d2021-01-30 21:17:21 +0100370{
Harald Welte93740612021-02-02 19:54:10 +0100371 struct priv_bind *priv = bind->priv;
Harald Welted06128d2021-01-30 21:17:21 +0100372 uint8_t dlci = msg->data[0];
373 uint8_t ns_pdu_type;
374 uint16_t bvci;
375
376 if (msgb_length(msg) < 1)
377 goto out_free;
378
379 /* we want to enqueue only Q.933 LMI traffic or NS signaling; NOT user traffic */
380 switch (dlci) {
381 case LMI_Q933A_DLCI:
Harald Welte93740612021-02-02 19:54:10 +0100382 /* always store only the last LMI message in the lmi_msg bucket */
383 msgb_free(priv->backlog.lmi_msg);
384 priv->backlog.lmi_msg = msg;
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100385 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100386 default:
Harald Welte6972aed2021-02-02 20:29:32 +0100387 /* there's no point in trying to enqueue messages if the interface is down */
388 if (!priv->if_running)
389 break;
390
Harald Welted06128d2021-01-30 21:17:21 +0100391 if (msgb_length(msg) < 3)
392 break;
393 ns_pdu_type = msg->data[2];
394 switch (ns_pdu_type) {
395 case NS_PDUT_UNITDATA:
396 if (msgb_length(msg) < 6)
397 break;
398 bvci = osmo_load16be(msg->data + 4);
399 /* enqueue BVCI=0 traffic at tail of queue */
400 if (bvci == BVCI_SIGNALLING) {
401 enqueue_at_tail(bind, msg);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100402 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100403 }
404 break;
405 default:
406 /* enqueue NS signaling traffic at head of queue */
407 enqueue_at_head(bind, msg);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100408 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100409 }
410 break;
411 }
412
413out_free:
414 /* drop everything that is not LMI, NS-signaling or BVCI-0 */
415 msgb_free(msg);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100416 return -1;
Harald Welted06128d2021-01-30 21:17:21 +0100417}
418
419static void fr_backlog_timer_cb(void *data)
420{
421 struct gprs_ns2_vc_bind *bind = data;
422 struct priv_bind *priv = bind->priv;
423 int i, rc;
424
Harald Welte93740612021-02-02 19:54:10 +0100425 /* first try to get rid of the LMI message, if any */
426 if (priv->backlog.lmi_msg) {
427 rc = fr_netif_write_one(bind, priv->backlog.lmi_msg);
428 if (rc < 0)
429 goto restart_timer;
430 /* fr_netif_write_one() has just free'd it */
431 priv->backlog.lmi_msg = NULL;
432 }
433
Harald Welted06128d2021-01-30 21:17:21 +0100434 /* attempt to send up to 10 messages in every timer */
435 for (i = 0; i < 10; i++) {
436 struct msgb *msg = msgb_dequeue(&priv->backlog.list);
437 if (!msg)
438 break;
439
440 rc = fr_netif_write_one(bind, msg);
441 if (rc < 0) {
442 /* re-add at head of list */
443 llist_add(&msg->list, &priv->backlog.list);
444 break;
445 }
Pau Espin Pedrol7b894a72021-06-04 18:17:12 +0200446 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 +0100447 }
448
Harald Welte93740612021-02-02 19:54:10 +0100449restart_timer:
Harald Welted06128d2021-01-30 21:17:21 +0100450 /* re-start timer if we still have data in the queue */
451 if (!llist_empty(&priv->backlog.list))
452 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
453}
454
Alexander Couzens841817e2020-11-19 00:41:29 +0100455/* PDU from the frame relay layer towards the network interface (downwards) */
456int fr_tx_cb(void *data, struct msgb *msg)
457{
458 struct gprs_ns2_vc_bind *bind = data;
459 struct priv_bind *priv = bind->priv;
Harald Welted06128d2021-01-30 21:17:21 +0100460 int rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100461
Harald Welted06128d2021-01-30 21:17:21 +0100462 if (llist_empty(&priv->backlog.list)) {
463 /* attempt to transmit right now */
464 rc = fr_netif_write_one(bind, msg);
465 if (rc < 0) {
466 /* enqueue to backlog in case it fails */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100467 return backlog_enqueue_or_free(bind, msg);
Harald Welted06128d2021-01-30 21:17:21 +0100468 }
469 } else {
470 /* enqueue to backlog */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100471 return backlog_enqueue_or_free(bind, msg);
Alexander Couzens60021a42020-12-17 02:48:22 +0100472 }
Alexander Couzens841817e2020-11-19 00:41:29 +0100473
Alexander Couzens60021a42020-12-17 02:48:22 +0100474 return 0;
Alexander Couzens841817e2020-11-19 00:41:29 +0100475}
476
477static int devname2ifindex(const char *ifname)
478{
479 struct ifreq ifr;
480 int sk, rc;
481
482 sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
483 if (sk < 0)
484 return sk;
485
486
487 memset(&ifr, 0, sizeof(ifr));
Neels Hofmeyr475a0ac2020-12-17 18:10:34 +0100488 OSMO_STRLCPY_ARRAY(ifr.ifr_name, ifname);
Alexander Couzens841817e2020-11-19 00:41:29 +0100489
490 rc = ioctl(sk, SIOCGIFINDEX, &ifr);
491 close(sk);
492 if (rc < 0)
493 return rc;
494
495 return ifr.ifr_ifindex;
496}
497
Harald Weltef2949742021-01-20 14:54:14 +0100498static int open_socket(int ifindex, const struct gprs_ns2_vc_bind *nsbind)
Alexander Couzens841817e2020-11-19 00:41:29 +0100499{
500 struct sockaddr_ll addr;
Harald Welte4ed0f4e2020-12-10 21:50:32 +0100501 int fd, rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100502
Alexander Couzens841817e2020-11-19 00:41:29 +0100503 memset(&addr, 0, sizeof(addr));
504 addr.sll_family = AF_PACKET;
505 addr.sll_protocol = htons(ETH_P_ALL);
506 addr.sll_ifindex = ifindex;
507
Harald Welte5bea72e2020-12-10 22:06:21 +0100508 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_HDLC));
Alexander Couzens841817e2020-11-19 00:41:29 +0100509 if (fd < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100510 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 +0100511 return fd;
512 }
513
Harald Welte41b188b2020-12-10 22:00:23 +0100514 /* there's a race condition between the above syscall and the bind() call below,
515 * causing other packets to be received in between */
516
Alexander Couzens841817e2020-11-19 00:41:29 +0100517 rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
518 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100519 LOGBIND(nsbind, LOGL_ERROR, "Can not bind AF_PACKET socket to ifindex %d\n", ifindex);
Alexander Couzens841817e2020-11-19 00:41:29 +0100520 close(fd);
521 return rc;
522 }
523
524 return fd;
525}
526
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100527static int gprs_n2_fr_ifupdown_ind_cb(struct osmo_netdev *netdev, bool if_running)
Harald Welte56f08a32020-12-01 23:07:32 +0100528{
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100529 struct gprs_ns2_vc_bind *bind = osmo_netdev_get_priv_data(netdev);
Harald Welte6972aed2021-02-02 20:29:32 +0100530 struct priv_bind *bpriv = bind->priv;
531 struct msgb *msg, *msg2;
532
533 if (bpriv->if_running == if_running)
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100534 return 0;
Harald Welte6972aed2021-02-02 20:29:32 +0100535
536 LOGBIND(bind, LOGL_NOTICE, "FR net-device '%s': Physical link state changed: %s\n",
537 bpriv->netif, if_running ? "UP" : "DOWN");
538
539 /* free any backlog, both on IFUP and IFDOWN. Keep the LMI, as it makes
540 * sense to get one out of the door ASAP. */
541 llist_for_each_entry_safe(msg, msg2, &bpriv->backlog.list, list) {
542 msgb_free(msg);
543 }
544
545 if (if_running) {
546 /* interface just came up */
547 if (bpriv->backlog.lmi_msg)
548 osmo_timer_schedule(&bpriv->backlog.timer, 0, bpriv->backlog.retry_us);
549 } else {
550 /* interface just went down; no need to retransmit */
551 osmo_timer_del(&bpriv->backlog.timer);
552 }
553
554 bpriv->if_running = if_running;
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100555 return 0;
Harald Welte6972aed2021-02-02 20:29:32 +0100556}
557
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100558static int gprs_n2_fr_mtu_chg_cb(struct osmo_netdev *netdev, uint32_t new_mtu)
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100559{
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100560 struct gprs_ns2_vc_bind *bind = osmo_netdev_get_priv_data(netdev);
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100561 struct priv_bind *bpriv = bind->priv;
562 struct gprs_ns2_nse *nse;
563
Alexander Couzensa6096ad2021-07-02 16:23:06 +0200564 /* 2 byte DLCI header */
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100565 if (new_mtu <= 2)
566 return 0;
567 new_mtu -= 2;
Alexander Couzensa6096ad2021-07-02 16:23:06 +0200568
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100569 if (new_mtu == bind->mtu)
570 return 0;
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100571
572 LOGBIND(bind, LOGL_INFO, "MTU changed from %d to %d.\n",
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100573 bind->mtu + 2, new_mtu + 2);
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100574
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100575 bind->mtu = new_mtu;
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100576 if (!bpriv->if_running)
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100577 return 0;
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100578
579 llist_for_each_entry(nse, &bind->nsi->nse, list) {
580 ns2_nse_update_mtu(nse);
581 }
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100582 return 0;
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100583}
584
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100585static int set_ifupdown(const char *netif, bool up)
586{
587 int sock, rc;
588 struct ifreq req;
589
590 sock = socket(AF_INET, SOCK_DGRAM, 0);
591 if (sock < 0)
592 return sock;
593
594 memset(&req, 0, sizeof req);
Harald Welte7f01b682020-12-21 12:39:38 +0100595 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100596
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100597 rc = ioctl(sock, SIOCGIFFLAGS, &req);
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100598 if (rc < 0) {
599 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100600 return rc;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100601 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100602
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100603 if ((req.ifr_flags & IFF_UP) == up) {
604 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100605 return 0;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100606 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100607
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100608 if (up)
609 req.ifr_flags |= IFF_UP;
610
611 rc = ioctl(sock, SIOCSIFFLAGS, &req);
612 close(sock);
613 return rc;
614}
615
Harald Weltef2949742021-01-20 14:54:14 +0100616static int setup_device(const char *netif, const struct gprs_ns2_vc_bind *bind)
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100617{
618 int sock, rc;
619 char buffer[128];
620 fr_proto *fr = (void*)buffer;
621 struct ifreq req;
622
623 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
624 if (sock < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100625 LOGBIND(bind, LOGL_ERROR, "%s: Unable to create socket: %s\n",
626 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100627 return sock;
628 }
629
630 memset(&req, 0, sizeof(struct ifreq));
631 memset(&buffer, 0, sizeof(buffer));
Harald Welteb8de1882020-12-21 12:40:45 +0100632 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100633 req.ifr_settings.ifs_ifsu.sync = (void*)buffer;
634 req.ifr_settings.size = sizeof(buffer);
635 req.ifr_settings.type = IF_GET_PROTO;
636
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100637 /* EINVAL is returned when no protocol has been set */
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100638 rc = ioctl(sock, SIOCWANDEV, &req);
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100639 if (rc < 0 && errno != EINVAL) {
Harald Weltef2949742021-01-20 14:54:14 +0100640 LOGBIND(bind, LOGL_ERROR, "%s: Unable to get FR protocol information: %s\n",
641 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100642 goto err;
643 }
644
645 /* check if the device is good */
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100646 if (rc == 0 && req.ifr_settings.type == IF_PROTO_FR && fr->lmi == LMI_NONE) {
Harald Weltef2949742021-01-20 14:54:14 +0100647 LOGBIND(bind, LOGL_NOTICE, "%s: has correct frame relay mode and lmi\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100648 goto ifup;
649 }
650
651 /* modify the device to match */
652 rc = set_ifupdown(netif, false);
653 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100654 LOGBIND(bind, LOGL_ERROR, "Unable to bring down the device %s: %s\n",
655 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100656 goto err;
657 }
658
659 memset(&req, 0, sizeof(struct ifreq));
660 memset(fr, 0, sizeof(fr_proto));
Harald Welteb8de1882020-12-21 12:40:45 +0100661 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100662 req.ifr_settings.type = IF_PROTO_FR;
663 req.ifr_settings.size = sizeof(fr_proto);
664 req.ifr_settings.ifs_ifsu.fr = fr;
665 fr->lmi = LMI_NONE;
666 /* even those settings aren't used, they must be in the range */
667 /* polling verification timer*/
668 fr->t391 = 10;
669 /* link integrity verification polling timer */
670 fr->t392 = 15;
671 /* full status polling counter*/
672 fr->n391 = 6;
673 /* error threshold */
674 fr->n392 = 3;
675 /* monitored events count */
676 fr->n393 = 4;
677
Harald Weltef2949742021-01-20 14:54:14 +0100678 LOGBIND(bind, LOGL_INFO, "%s: Setting frame relay related parameters\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100679 rc = ioctl(sock, SIOCWANDEV, &req);
680 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100681 LOGBIND(bind, LOGL_ERROR, "%s: Unable to set FR protocol on information: %s\n",
682 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100683 goto err;
684 }
685
686ifup:
687 rc = set_ifupdown(netif, true);
688 if (rc)
Harald Weltef2949742021-01-20 14:54:14 +0100689 LOGBIND(bind, LOGL_ERROR, "Unable to bring up the device %s: %s\n",
690 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100691err:
692 close(sock);
693 return rc;
694}
Harald Welte56f08a32020-12-01 23:07:32 +0100695
Alexander Couzens841817e2020-11-19 00:41:29 +0100696/*! Create a new bind for NS over FR.
697 * \param[in] nsi NS instance in which to create the bind
698 * \param[in] netif Network interface to bind to
699 * \param[in] fr_network
700 * \param[in] fr_role
Alexander Couzensc80a8742021-02-03 11:27:52 +0100701 * \param[out] result pointer to the created bind or if a bind with the name exists return the bind.
702 * \return 0 on success; negative on error. -EALREADY returned in case a bind with the name exists */
Alexander Couzens841817e2020-11-19 00:41:29 +0100703int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi,
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100704 const char *name,
Alexander Couzens841817e2020-11-19 00:41:29 +0100705 const char *netif,
706 struct osmo_fr_network *fr_network,
707 enum osmo_fr_role fr_role,
708 struct gprs_ns2_vc_bind **result)
709{
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100710 struct gprs_ns2_vc_bind *bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100711 struct priv_bind *priv;
712 struct osmo_fr_link *fr_link;
713 int rc = 0;
714
Harald Weltec3aa8f92021-01-31 11:41:34 +0100715 if (strlen(netif) > IFNAMSIZ)
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100716 return -EINVAL;
717
Alexander Couzensc80a8742021-02-03 11:27:52 +0100718 bind = gprs_ns2_bind_by_name(nsi, name);
719 if (bind) {
720 if (result)
721 *result = bind;
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100722 return -EALREADY;
Alexander Couzensc80a8742021-02-03 11:27:52 +0100723 }
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100724
Harald Weltec3aa8f92021-01-31 11:41:34 +0100725 rc = ns2_bind_alloc(nsi, name, &bind);
726 if (rc < 0)
727 return rc;
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100728
Alexander Couzens841817e2020-11-19 00:41:29 +0100729 bind->driver = &vc_driver_fr;
Alexander Couzensaac90162020-11-19 02:44:04 +0100730 bind->ll = GPRS_NS2_LL_FR;
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100731 /* 2 mbit */
732 bind->transfer_capability = 2;
Alexander Couzens841817e2020-11-19 00:41:29 +0100733 bind->send_vc = fr_vc_sendmsg;
734 bind->free_vc = free_vc;
735 bind->dump_vty = dump_vty;
Alexander Couzens4f1128f2021-01-20 17:42:48 +0100736 bind->mtu = FRAME_RELAY_SDU;
Alexander Couzens841817e2020-11-19 00:41:29 +0100737 priv = bind->priv = talloc_zero(bind, struct priv_bind);
738 if (!priv) {
Harald Weltebdfb8b92021-01-31 11:44:57 +0100739 rc = -ENOMEM;
Harald Weltec3aa8f92021-01-31 11:41:34 +0100740 goto err_bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100741 }
742
Harald Weltece6e4b72021-02-11 15:58:40 +0100743 INIT_LLIST_HEAD(&priv->backlog.list);
Neels Hofmeyr8fef7612020-12-17 18:19:19 +0100744 OSMO_STRLCPY_ARRAY(priv->netif, netif);
Alexander Couzens841817e2020-11-19 00:41:29 +0100745
Alexander Couzens841817e2020-11-19 00:41:29 +0100746 /* FIXME: move fd handling into socket.c */
747 fr_link = osmo_fr_link_alloc(fr_network, fr_role, netif);
748 if (!fr_link) {
749 rc = -EINVAL;
Harald Weltec3aa8f92021-01-31 11:41:34 +0100750 goto err_bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100751 }
752
753 fr_link->tx_cb = fr_tx_cb;
Harald Welte2cc1d4d2021-01-31 18:33:31 +0100754 fr_link->cb_data = bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100755 priv->link = fr_link;
Harald Welte41b188b2020-12-10 22:00:23 +0100756
Alexander Couzens6f89c772020-12-17 03:06:39 +0100757 priv->ifindex = rc = devname2ifindex(netif);
758 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100759 LOGBIND(bind, LOGL_ERROR, "Can not get interface index for interface %s\n", netif);
Harald Welte41b188b2020-12-10 22:00:23 +0100760 goto err_fr;
761 }
762
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100763 priv->netdev = osmo_netdev_alloc(bind, name);
764 if (!priv->netdev) {
765 rc = -ENOENT;
766 goto err_fr;
767 }
768 osmo_netdev_set_priv_data(priv->netdev, bind);
769 osmo_netdev_set_ifupdown_ind_cb(priv->netdev, gprs_n2_fr_ifupdown_ind_cb);
770 osmo_netdev_set_mtu_chg_cb(priv->netdev, gprs_n2_fr_mtu_chg_cb);
771 rc = osmo_netdev_set_ifindex(priv->netdev, priv->ifindex);
772 if (rc < 0)
773 goto err_free_netdev;
774 rc = osmo_netdev_register(priv->netdev);
775 if (rc < 0)
776 goto err_free_netdev;
777
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100778 /* set protocol frame relay and lmi */
Harald Weltef2949742021-01-20 14:54:14 +0100779 rc = setup_device(priv->netif, bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100780 if(rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100781 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 +0100782 goto err_free_netdev;
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100783 }
784
Harald Weltef2949742021-01-20 14:54:14 +0100785 rc = open_socket(priv->ifindex, bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100786 if (rc < 0)
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100787 goto err_free_netdev;
Harald Welted06128d2021-01-30 21:17:21 +0100788 priv->backlog.retry_us = 2500; /* start with some non-zero value; this corrsponds to 496 bytes */
789 osmo_timer_setup(&priv->backlog.timer, fr_backlog_timer_cb, bind);
790 osmo_fd_setup(&priv->backlog.ofd, rc, OSMO_FD_READ, fr_netif_ofd_cb, bind, 0);
791 rc = osmo_fd_register(&priv->backlog.ofd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100792 if (rc < 0)
793 goto err_fd;
794
Harald Weltec3aa8f92021-01-31 11:41:34 +0100795 if (result)
796 *result = bind;
797
Alexander Couzens841817e2020-11-19 00:41:29 +0100798 return rc;
799
800err_fd:
Harald Welted06128d2021-01-30 21:17:21 +0100801 close(priv->backlog.ofd.fd);
Pau Espin Pedrol5c7eaa62023-01-24 18:41:33 +0100802err_free_netdev:
803 osmo_netdev_free(priv->netdev);
804 priv->netdev = NULL;
Alexander Couzens841817e2020-11-19 00:41:29 +0100805err_fr:
806 osmo_fr_link_free(fr_link);
Harald Welte855155c2021-02-11 16:07:18 +0100807 priv->link = NULL;
Alexander Couzens841817e2020-11-19 00:41:29 +0100808err_bind:
Harald Weltec3aa8f92021-01-31 11:41:34 +0100809 gprs_ns2_free_bind(bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100810
811 return rc;
812}
813
Alexander Couzensc782cec2020-12-10 04:10:25 +0100814/*! Return the frame relay role of a bind
815 * \param[in] bind The bind
816 * \return the frame relay role or -EINVAL if bind is not frame relay
817 */
818enum osmo_fr_role gprs_ns2_fr_bind_role(struct gprs_ns2_vc_bind *bind)
819{
820 struct priv_bind *priv;
821
822 if (bind->driver != &vc_driver_fr)
823 return -EINVAL;
824
825 priv = bind->priv;
826 return priv->link->role;
827}
828
Alexander Couzens841817e2020-11-19 00:41:29 +0100829/*! Return the network interface of the bind
830 * \param[in] bind The bind
831 * \return the network interface
832 */
833const char *gprs_ns2_fr_bind_netif(struct gprs_ns2_vc_bind *bind)
834{
835 struct priv_bind *priv;
836
837 if (bind->driver != &vc_driver_fr)
838 return NULL;
839
840 priv = bind->priv;
841 return priv->netif;
842}
843
844/*! Find NS bind for a given network interface
845 * \param[in] nsi NS instance
846 * \param[in] netif the network interface to search for
847 * \return the bind or NULL if not found
848 */
849struct gprs_ns2_vc_bind *gprs_ns2_fr_bind_by_netif(
850 struct gprs_ns2_inst *nsi,
851 const char *netif)
852{
853 struct gprs_ns2_vc_bind *bind;
854 const char *_netif;
855
856 OSMO_ASSERT(nsi);
857 OSMO_ASSERT(netif);
858
859 llist_for_each_entry(bind, &nsi->binding, list) {
860 if (!gprs_ns2_is_fr_bind(bind))
861 continue;
862
863 _netif = gprs_ns2_fr_bind_netif(bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100864 if (!strncmp(_netif, netif, IFNAMSIZ))
Alexander Couzens841817e2020-11-19 00:41:29 +0100865 return bind;
866 }
867
868 return NULL;
869}
870
871/*! Create, connect and activate a new FR-based NS-VC
872 * \param[in] bind bind in which the new NS-VC is to be created
873 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
874 * \param[in] dlci Data Link connection identifier
875 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
876struct gprs_ns2_vc *gprs_ns2_fr_connect(struct gprs_ns2_vc_bind *bind,
Alexander Couzensebcbd722020-12-03 06:11:39 +0100877 struct gprs_ns2_nse *nse,
878 uint16_t nsvci,
879 uint16_t dlci)
880{
881 struct gprs_ns2_vc *nsvc = NULL;
882 struct priv_vc *priv = NULL;
Harald Welte603f4042020-11-29 17:39:19 +0100883 struct priv_bind *bpriv = bind->priv;
884 char idbuf[64];
Alexander Couzensebcbd722020-12-03 06:11:39 +0100885
Alexander Couzens55bc8692021-01-18 18:39:57 +0100886 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzensebcbd722020-12-03 06:11:39 +0100887 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
888 if (nsvc) {
889 goto err;
890 }
891
Alexander Couzensd7948062021-06-03 20:35:47 +0200892 snprintf(idbuf, sizeof(idbuf), "NSE%05u-NSVC%05u-%s-%s-DLCI%u", nse->nsei, nsvci,
893 gprs_ns2_lltype_str(nse->ll), bpriv->netif, dlci);
894 osmo_identifier_sanitize_buf(idbuf, NULL, '_');
Alexander Couzens138b96f2021-01-25 16:23:29 +0100895 nsvc = ns2_vc_alloc(bind, nse, true, GPRS_NS2_VC_MODE_BLOCKRESET, idbuf);
Alexander Couzensebcbd722020-12-03 06:11:39 +0100896 if (!nsvc)
897 goto err;
898
899 nsvc->priv = priv = fr_alloc_vc(bind, nsvc, dlci);
900 if (!priv)
901 goto err;
902
903 nsvc->nsvci = nsvci;
904 nsvc->nsvci_is_valid = true;
905
Alexander Couzensebcbd722020-12-03 06:11:39 +0100906 return nsvc;
907
908err:
909 gprs_ns2_free_nsvc(nsvc);
910 return NULL;
911}
912
913
914/*! Create, connect and activate a new FR-based NS-VC
915 * \param[in] bind bind in which the new NS-VC is to be created
916 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
917 * \param[in] dlci Data Link connection identifier
918 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
919struct gprs_ns2_vc *gprs_ns2_fr_connect2(struct gprs_ns2_vc_bind *bind,
Alexander Couzens841817e2020-11-19 00:41:29 +0100920 uint16_t nsei,
921 uint16_t nsvci,
922 uint16_t dlci)
923{
924 bool created_nse = false;
925 struct gprs_ns2_vc *nsvc = NULL;
Alexander Couzens55bc8692021-01-18 18:39:57 +0100926 struct gprs_ns2_nse *nse;
927
928 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
929 nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei);
Alexander Couzens841817e2020-11-19 00:41:29 +0100930 if (!nse) {
Alexander Couzens138b96f2021-01-25 16:23:29 +0100931 nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_FR, GPRS_NS2_DIALECT_STATIC_RESETBLOCK);
Alexander Couzens841817e2020-11-19 00:41:29 +0100932 if (!nse)
933 return NULL;
934 created_nse = true;
935 }
936
Harald Welte509047b2021-01-17 19:55:51 +0100937 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
Alexander Couzens841817e2020-11-19 00:41:29 +0100938 if (!nsvc)
939 goto err_nse;
940
Alexander Couzens841817e2020-11-19 00:41:29 +0100941 return nsvc;
942
Alexander Couzens841817e2020-11-19 00:41:29 +0100943err_nse:
944 if (created_nse)
945 gprs_ns2_free_nse(nse);
946
947 return NULL;
948}
949
950/*! Return the nsvc by dlci.
951 * \param[in] bind
952 * \param[in] dlci Data Link connection identifier
953 * \return the nsvc or NULL if not found
954 */
955struct gprs_ns2_vc *gprs_ns2_fr_nsvc_by_dlci(struct gprs_ns2_vc_bind *bind,
956 uint16_t dlci)
957{
958 struct gprs_ns2_vc *nsvc;
959 struct priv_vc *vcpriv;
960
Alexander Couzens55bc8692021-01-18 18:39:57 +0100961 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +0100962 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
963 vcpriv = nsvc->priv;
964
965 if (dlci == vcpriv->dlci)
966 return nsvc;
967 }
968
969 return NULL;
970}
971
972/*! Return the dlci of the nsvc
973 * \param[in] nsvc
974 * \return the dlci or 0 on error. 0 is not a valid dlci.
975 */
Alexander Couzens22c26e02020-12-10 04:10:07 +0100976uint16_t gprs_ns2_fr_nsvc_dlci(const struct gprs_ns2_vc *nsvc)
Alexander Couzens841817e2020-11-19 00:41:29 +0100977{
978 struct priv_vc *vcpriv;
979
980 if (!nsvc->bind)
981 return 0;
982
983 if (nsvc->bind->driver != &vc_driver_fr)
984 return 0;
985
986 vcpriv = nsvc->priv;
987 return vcpriv->dlci;
988}