blob: 2df5986924fa94a7eb85b620ec92fcc45b6e53c7 [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:
Harald Welte9811f492021-02-02 22:58:00 +0100314 /* not a real error, but more a normal event on AF_PACKET */
315 /* don't free the message and let the caller re-enqueue */
Harald Welted06128d2021-01-30 21:17:21 +0100316 return -errno;
317 default:
Harald Welte9811f492021-02-02 22:58:00 +0100318 /* an actual error, like -ENETDOWN, -EMSGSIZE */
Harald Welted06128d2021-01-30 21:17:21 +0100319 LOGBIND(bind, LOGL_ERROR, "error during write to AF_PACKET: %s\n", strerror(errno));
Harald Welte9811f492021-02-02 22:58:00 +0100320 msgb_free(msg);
321 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100322 }
323 } else {
324 /* short write */
325 LOGBIND(bind, LOGL_ERROR, "short write on AF_PACKET: %d < %d\n", rc, len);
326 msgb_free(msg);
327 return 0;
328 }
Alexander Couzens841817e2020-11-19 00:41:29 +0100329}
330
331/*! determine if given bind is for FR-GRE encapsulation. */
332int gprs_ns2_is_fr_bind(struct gprs_ns2_vc_bind *bind)
333{
334 return (bind->driver == &vc_driver_fr);
335}
336
337/* PDU from the NS-VC towards the frame relay layer (downwards) */
338static int fr_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
339{
340 struct priv_vc *vcpriv = nsvc->priv;
341
342 msg->dst = vcpriv->dlc;
343 return osmo_fr_tx_dlc(msg);
344}
345
Harald Welted06128d2021-01-30 21:17:21 +0100346static void enqueue_at_head(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
347{
348 struct priv_bind *priv = bind->priv;
349 llist_add(&msg->list, &priv->backlog.list);
Harald Welte76346072021-01-31 11:54:02 +0100350 osmo_stat_item_inc(bind->statg->items[NS2_BIND_STAT_BACKLOG_LEN], 1);
Harald Welted06128d2021-01-30 21:17:21 +0100351 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
352}
353
354static void enqueue_at_tail(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
355{
356 struct priv_bind *priv = bind->priv;
357 llist_add_tail(&msg->list, &priv->backlog.list);
Harald Welte76346072021-01-31 11:54:02 +0100358 osmo_stat_item_inc(bind->statg->items[NS2_BIND_STAT_BACKLOG_LEN], 1);
Harald Welted06128d2021-01-30 21:17:21 +0100359 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
360}
361
362#define LMI_Q933A_DLCI 0
363
364/* enqueue to backlog (LMI, signaling) or drop (userdata msg) */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100365static int backlog_enqueue_or_free(struct gprs_ns2_vc_bind *bind, struct msgb *msg)
Harald Welted06128d2021-01-30 21:17:21 +0100366{
Harald Welte93740612021-02-02 19:54:10 +0100367 struct priv_bind *priv = bind->priv;
Harald Welted06128d2021-01-30 21:17:21 +0100368 uint8_t dlci = msg->data[0];
369 uint8_t ns_pdu_type;
370 uint16_t bvci;
371
372 if (msgb_length(msg) < 1)
373 goto out_free;
374
375 /* we want to enqueue only Q.933 LMI traffic or NS signaling; NOT user traffic */
376 switch (dlci) {
377 case LMI_Q933A_DLCI:
Harald Welte93740612021-02-02 19:54:10 +0100378 /* always store only the last LMI message in the lmi_msg bucket */
379 msgb_free(priv->backlog.lmi_msg);
380 priv->backlog.lmi_msg = msg;
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100381 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100382 default:
Harald Welte6972aed2021-02-02 20:29:32 +0100383 /* there's no point in trying to enqueue messages if the interface is down */
384 if (!priv->if_running)
385 break;
386
Harald Welted06128d2021-01-30 21:17:21 +0100387 if (msgb_length(msg) < 3)
388 break;
389 ns_pdu_type = msg->data[2];
390 switch (ns_pdu_type) {
391 case NS_PDUT_UNITDATA:
392 if (msgb_length(msg) < 6)
393 break;
394 bvci = osmo_load16be(msg->data + 4);
395 /* enqueue BVCI=0 traffic at tail of queue */
396 if (bvci == BVCI_SIGNALLING) {
397 enqueue_at_tail(bind, msg);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100398 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100399 }
400 break;
401 default:
402 /* enqueue NS signaling traffic at head of queue */
403 enqueue_at_head(bind, msg);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100404 return 0;
Harald Welted06128d2021-01-30 21:17:21 +0100405 }
406 break;
407 }
408
409out_free:
410 /* drop everything that is not LMI, NS-signaling or BVCI-0 */
411 msgb_free(msg);
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100412 return -1;
Harald Welted06128d2021-01-30 21:17:21 +0100413}
414
415static void fr_backlog_timer_cb(void *data)
416{
417 struct gprs_ns2_vc_bind *bind = data;
418 struct priv_bind *priv = bind->priv;
419 int i, rc;
420
Harald Welte93740612021-02-02 19:54:10 +0100421 /* first try to get rid of the LMI message, if any */
422 if (priv->backlog.lmi_msg) {
423 rc = fr_netif_write_one(bind, priv->backlog.lmi_msg);
424 if (rc < 0)
425 goto restart_timer;
426 /* fr_netif_write_one() has just free'd it */
427 priv->backlog.lmi_msg = NULL;
428 }
429
Harald Welted06128d2021-01-30 21:17:21 +0100430 /* attempt to send up to 10 messages in every timer */
431 for (i = 0; i < 10; i++) {
432 struct msgb *msg = msgb_dequeue(&priv->backlog.list);
433 if (!msg)
434 break;
435
436 rc = fr_netif_write_one(bind, msg);
437 if (rc < 0) {
438 /* re-add at head of list */
439 llist_add(&msg->list, &priv->backlog.list);
440 break;
441 }
Harald Welte76346072021-01-31 11:54:02 +0100442 osmo_stat_item_dec(bind->statg->items[NS2_BIND_STAT_BACKLOG_LEN], 1);
Harald Welted06128d2021-01-30 21:17:21 +0100443 }
444
Harald Welte93740612021-02-02 19:54:10 +0100445restart_timer:
Harald Welted06128d2021-01-30 21:17:21 +0100446 /* re-start timer if we still have data in the queue */
447 if (!llist_empty(&priv->backlog.list))
448 osmo_timer_schedule(&priv->backlog.timer, 0, priv->backlog.retry_us);
449}
450
Alexander Couzens841817e2020-11-19 00:41:29 +0100451/* PDU from the frame relay layer towards the network interface (downwards) */
452int fr_tx_cb(void *data, struct msgb *msg)
453{
454 struct gprs_ns2_vc_bind *bind = data;
455 struct priv_bind *priv = bind->priv;
Harald Welted06128d2021-01-30 21:17:21 +0100456 int rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100457
Harald Welted06128d2021-01-30 21:17:21 +0100458 if (llist_empty(&priv->backlog.list)) {
459 /* attempt to transmit right now */
460 rc = fr_netif_write_one(bind, msg);
461 if (rc < 0) {
462 /* enqueue to backlog in case it fails */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100463 return backlog_enqueue_or_free(bind, msg);
Harald Welted06128d2021-01-30 21:17:21 +0100464 }
465 } else {
466 /* enqueue to backlog */
Harald Welte5e0ef6f2021-01-30 22:03:26 +0100467 return backlog_enqueue_or_free(bind, msg);
Alexander Couzens60021a42020-12-17 02:48:22 +0100468 }
Alexander Couzens841817e2020-11-19 00:41:29 +0100469
Alexander Couzens60021a42020-12-17 02:48:22 +0100470 return 0;
Alexander Couzens841817e2020-11-19 00:41:29 +0100471}
472
473static int devname2ifindex(const char *ifname)
474{
475 struct ifreq ifr;
476 int sk, rc;
477
478 sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
479 if (sk < 0)
480 return sk;
481
482
483 memset(&ifr, 0, sizeof(ifr));
Neels Hofmeyr475a0ac2020-12-17 18:10:34 +0100484 OSMO_STRLCPY_ARRAY(ifr.ifr_name, ifname);
Alexander Couzens841817e2020-11-19 00:41:29 +0100485
486 rc = ioctl(sk, SIOCGIFINDEX, &ifr);
487 close(sk);
488 if (rc < 0)
489 return rc;
490
491 return ifr.ifr_ifindex;
492}
493
Harald Weltef2949742021-01-20 14:54:14 +0100494static int open_socket(int ifindex, const struct gprs_ns2_vc_bind *nsbind)
Alexander Couzens841817e2020-11-19 00:41:29 +0100495{
496 struct sockaddr_ll addr;
Harald Welte4ed0f4e2020-12-10 21:50:32 +0100497 int fd, rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100498
Alexander Couzens841817e2020-11-19 00:41:29 +0100499 memset(&addr, 0, sizeof(addr));
500 addr.sll_family = AF_PACKET;
501 addr.sll_protocol = htons(ETH_P_ALL);
502 addr.sll_ifindex = ifindex;
503
Harald Welte5bea72e2020-12-10 22:06:21 +0100504 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_HDLC));
Alexander Couzens841817e2020-11-19 00:41:29 +0100505 if (fd < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100506 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 +0100507 return fd;
508 }
509
Harald Welte41b188b2020-12-10 22:00:23 +0100510 /* there's a race condition between the above syscall and the bind() call below,
511 * causing other packets to be received in between */
512
Alexander Couzens841817e2020-11-19 00:41:29 +0100513 rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
514 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100515 LOGBIND(nsbind, LOGL_ERROR, "Can not bind AF_PACKET socket to ifindex %d\n", ifindex);
Alexander Couzens841817e2020-11-19 00:41:29 +0100516 close(fd);
517 return rc;
518 }
519
520 return fd;
521}
522
Harald Welte56f08a32020-12-01 23:07:32 +0100523#ifdef ENABLE_LIBMNL
524
525#include <osmocom/core/mnl.h>
Harald Welte56f08a32020-12-01 23:07:32 +0100526#include <linux/if_link.h>
527#include <linux/rtnetlink.h>
528
529#ifndef ARPHRD_FRAD
530#define ARPHRD_FRAD 770
531#endif
532
533/* validate the netlink attributes */
534static int data_attr_cb(const struct nlattr *attr, void *data)
535{
536 const struct nlattr **tb = data;
537 int type = mnl_attr_get_type(attr);
538
539 if (mnl_attr_type_valid(attr, IFLA_MAX) < 0)
540 return MNL_CB_OK;
541
542 switch (type) {
543 case IFLA_MTU:
544 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
545 return MNL_CB_ERROR;
546 break;
547 case IFLA_IFNAME:
548 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
549 return MNL_CB_ERROR;
550 break;
551 }
552 tb[type] = attr;
553 return MNL_CB_OK;
554}
555
556/* find the bind for the netdev (if any) */
557static struct gprs_ns2_vc_bind *bind4netdev(struct gprs_ns2_inst *nsi, const char *ifname)
558{
559 struct gprs_ns2_vc_bind *bind;
560
561 llist_for_each_entry(bind, &nsi->binding, list) {
562 struct priv_bind *bpriv = bind->priv;
563 if (!strcmp(bpriv->netif, ifname))
564 return bind;
565 }
566
567 return NULL;
568}
569
Harald Welte6972aed2021-02-02 20:29:32 +0100570static void link_state_change(struct gprs_ns2_vc_bind *bind, bool if_running)
571{
572 struct priv_bind *bpriv = bind->priv;
573 struct msgb *msg, *msg2;
574
575 if (bpriv->if_running == if_running)
576 return;
577
578 LOGBIND(bind, LOGL_NOTICE, "FR net-device '%s': Physical link state changed: %s\n",
579 bpriv->netif, if_running ? "UP" : "DOWN");
580
581 /* free any backlog, both on IFUP and IFDOWN. Keep the LMI, as it makes
582 * sense to get one out of the door ASAP. */
583 llist_for_each_entry_safe(msg, msg2, &bpriv->backlog.list, list) {
584 msgb_free(msg);
585 }
586
587 if (if_running) {
588 /* interface just came up */
589 if (bpriv->backlog.lmi_msg)
590 osmo_timer_schedule(&bpriv->backlog.timer, 0, bpriv->backlog.retry_us);
591 } else {
592 /* interface just went down; no need to retransmit */
593 osmo_timer_del(&bpriv->backlog.timer);
594 }
595
596 bpriv->if_running = if_running;
597}
598
Harald Welte56f08a32020-12-01 23:07:32 +0100599/* handle a single netlink message received via libmnl */
600static int linkmon_mnl_cb(const struct nlmsghdr *nlh, void *data)
601{
602 struct osmo_mnl *omnl = data;
603 struct gprs_ns2_vc_bind *bind;
604 struct nlattr *tb[IFLA_MAX+1] = {};
605 struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh);
606 struct gprs_ns2_inst *nsi;
607 const char *ifname;
608 bool if_running;
609
610 OSMO_ASSERT(omnl);
611 OSMO_ASSERT(ifm);
612
613 nsi = omnl->priv;
614
615 if (ifm->ifi_type != ARPHRD_FRAD)
616 return MNL_CB_OK;
617
618 mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, tb);
619
620 if (!tb[IFLA_IFNAME])
621 return MNL_CB_OK;
622 ifname = mnl_attr_get_str(tb[IFLA_IFNAME]);
623 if_running = !!(ifm->ifi_flags & IFF_RUNNING);
624
625 bind = bind4netdev(nsi, ifname);
Harald Welte6972aed2021-02-02 20:29:32 +0100626 if (bind)
627 link_state_change(bind, if_running);
Harald Welte56f08a32020-12-01 23:07:32 +0100628
629 return MNL_CB_OK;
630}
631
632/* trigger one initial dump of all link information */
633static void linkmon_initial_dump(struct osmo_mnl *omnl)
634{
635 char buf[MNL_SOCKET_BUFFER_SIZE];
636 struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
637 struct rtgenmsg *rt;
638
639 nlh->nlmsg_type = RTM_GETLINK;
640 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
641 nlh->nlmsg_seq = time(NULL);
642 rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
643 rt->rtgen_family = AF_PACKET;
644
645 if (mnl_socket_sendto(omnl->mnls, nlh, nlh->nlmsg_len) < 0) {
646 LOGP(DLNS, LOGL_ERROR, "linkmon: Cannot send rtnetlink message: %s\n", strerror(errno));
647 }
648
649 /* the response[s] will be handled just like the events */
650}
651#endif /* LIBMNL */
652
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100653static int set_ifupdown(const char *netif, bool up)
654{
655 int sock, rc;
656 struct ifreq req;
657
658 sock = socket(AF_INET, SOCK_DGRAM, 0);
659 if (sock < 0)
660 return sock;
661
662 memset(&req, 0, sizeof req);
Harald Welte7f01b682020-12-21 12:39:38 +0100663 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100664
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100665 rc = ioctl(sock, SIOCGIFFLAGS, &req);
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100666 if (rc < 0) {
667 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100668 return rc;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100669 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100670
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100671 if ((req.ifr_flags & IFF_UP) == up) {
672 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100673 return 0;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100674 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100675
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100676 if (up)
677 req.ifr_flags |= IFF_UP;
678
679 rc = ioctl(sock, SIOCSIFFLAGS, &req);
680 close(sock);
681 return rc;
682}
683
Harald Weltef2949742021-01-20 14:54:14 +0100684static int setup_device(const char *netif, const struct gprs_ns2_vc_bind *bind)
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100685{
686 int sock, rc;
687 char buffer[128];
688 fr_proto *fr = (void*)buffer;
689 struct ifreq req;
690
691 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
692 if (sock < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100693 LOGBIND(bind, LOGL_ERROR, "%s: Unable to create socket: %s\n",
694 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100695 return sock;
696 }
697
698 memset(&req, 0, sizeof(struct ifreq));
699 memset(&buffer, 0, sizeof(buffer));
Harald Welteb8de1882020-12-21 12:40:45 +0100700 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100701 req.ifr_settings.ifs_ifsu.sync = (void*)buffer;
702 req.ifr_settings.size = sizeof(buffer);
703 req.ifr_settings.type = IF_GET_PROTO;
704
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100705 /* EINVAL is returned when no protocol has been set */
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100706 rc = ioctl(sock, SIOCWANDEV, &req);
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100707 if (rc < 0 && errno != EINVAL) {
Harald Weltef2949742021-01-20 14:54:14 +0100708 LOGBIND(bind, LOGL_ERROR, "%s: Unable to get FR protocol information: %s\n",
709 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100710 goto err;
711 }
712
713 /* check if the device is good */
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100714 if (rc == 0 && req.ifr_settings.type == IF_PROTO_FR && fr->lmi == LMI_NONE) {
Harald Weltef2949742021-01-20 14:54:14 +0100715 LOGBIND(bind, LOGL_NOTICE, "%s: has correct frame relay mode and lmi\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100716 goto ifup;
717 }
718
719 /* modify the device to match */
720 rc = set_ifupdown(netif, false);
721 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100722 LOGBIND(bind, LOGL_ERROR, "Unable to bring down the device %s: %s\n",
723 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100724 goto err;
725 }
726
727 memset(&req, 0, sizeof(struct ifreq));
728 memset(fr, 0, sizeof(fr_proto));
Harald Welteb8de1882020-12-21 12:40:45 +0100729 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100730 req.ifr_settings.type = IF_PROTO_FR;
731 req.ifr_settings.size = sizeof(fr_proto);
732 req.ifr_settings.ifs_ifsu.fr = fr;
733 fr->lmi = LMI_NONE;
734 /* even those settings aren't used, they must be in the range */
735 /* polling verification timer*/
736 fr->t391 = 10;
737 /* link integrity verification polling timer */
738 fr->t392 = 15;
739 /* full status polling counter*/
740 fr->n391 = 6;
741 /* error threshold */
742 fr->n392 = 3;
743 /* monitored events count */
744 fr->n393 = 4;
745
Harald Weltef2949742021-01-20 14:54:14 +0100746 LOGBIND(bind, LOGL_INFO, "%s: Setting frame relay related parameters\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100747 rc = ioctl(sock, SIOCWANDEV, &req);
748 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100749 LOGBIND(bind, LOGL_ERROR, "%s: Unable to set FR protocol on information: %s\n",
750 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100751 goto err;
752 }
753
754ifup:
755 rc = set_ifupdown(netif, true);
756 if (rc)
Harald Weltef2949742021-01-20 14:54:14 +0100757 LOGBIND(bind, LOGL_ERROR, "Unable to bring up the device %s: %s\n",
758 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100759err:
760 close(sock);
761 return rc;
762}
Harald Welte56f08a32020-12-01 23:07:32 +0100763
Alexander Couzens841817e2020-11-19 00:41:29 +0100764/*! Create a new bind for NS over FR.
765 * \param[in] nsi NS instance in which to create the bind
766 * \param[in] netif Network interface to bind to
767 * \param[in] fr_network
768 * \param[in] fr_role
Alexander Couzensc80a8742021-02-03 11:27:52 +0100769 * \param[out] result pointer to the created bind or if a bind with the name exists return the bind.
770 * \return 0 on success; negative on error. -EALREADY returned in case a bind with the name exists */
Alexander Couzens841817e2020-11-19 00:41:29 +0100771int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi,
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100772 const char *name,
Alexander Couzens841817e2020-11-19 00:41:29 +0100773 const char *netif,
774 struct osmo_fr_network *fr_network,
775 enum osmo_fr_role fr_role,
776 struct gprs_ns2_vc_bind **result)
777{
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100778 struct gprs_ns2_vc_bind *bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100779 struct priv_bind *priv;
780 struct osmo_fr_link *fr_link;
781 int rc = 0;
782
Harald Weltec3aa8f92021-01-31 11:41:34 +0100783 if (strlen(netif) > IFNAMSIZ)
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100784 return -EINVAL;
785
Alexander Couzensc80a8742021-02-03 11:27:52 +0100786 bind = gprs_ns2_bind_by_name(nsi, name);
787 if (bind) {
788 if (result)
789 *result = bind;
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100790 return -EALREADY;
Alexander Couzensc80a8742021-02-03 11:27:52 +0100791 }
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100792
Harald Weltec3aa8f92021-01-31 11:41:34 +0100793 rc = ns2_bind_alloc(nsi, name, &bind);
794 if (rc < 0)
795 return rc;
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100796
Alexander Couzens841817e2020-11-19 00:41:29 +0100797 bind->driver = &vc_driver_fr;
Alexander Couzensaac90162020-11-19 02:44:04 +0100798 bind->ll = GPRS_NS2_LL_FR;
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100799 /* 2 mbit */
800 bind->transfer_capability = 2;
Alexander Couzens841817e2020-11-19 00:41:29 +0100801 bind->send_vc = fr_vc_sendmsg;
802 bind->free_vc = free_vc;
803 bind->dump_vty = dump_vty;
Alexander Couzens841817e2020-11-19 00:41:29 +0100804 priv = bind->priv = talloc_zero(bind, struct priv_bind);
805 if (!priv) {
Harald Weltebdfb8b92021-01-31 11:44:57 +0100806 rc = -ENOMEM;
Harald Weltec3aa8f92021-01-31 11:41:34 +0100807 goto err_bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100808 }
809
Harald Weltece6e4b72021-02-11 15:58:40 +0100810 INIT_LLIST_HEAD(&priv->backlog.list);
Neels Hofmeyr8fef7612020-12-17 18:19:19 +0100811 OSMO_STRLCPY_ARRAY(priv->netif, netif);
Alexander Couzens841817e2020-11-19 00:41:29 +0100812
Alexander Couzens841817e2020-11-19 00:41:29 +0100813 /* FIXME: move fd handling into socket.c */
814 fr_link = osmo_fr_link_alloc(fr_network, fr_role, netif);
815 if (!fr_link) {
816 rc = -EINVAL;
Harald Weltec3aa8f92021-01-31 11:41:34 +0100817 goto err_bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100818 }
819
820 fr_link->tx_cb = fr_tx_cb;
Harald Welte2cc1d4d2021-01-31 18:33:31 +0100821 fr_link->cb_data = bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100822 priv->link = fr_link;
Harald Welte41b188b2020-12-10 22:00:23 +0100823
Alexander Couzens6f89c772020-12-17 03:06:39 +0100824 priv->ifindex = rc = devname2ifindex(netif);
825 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100826 LOGBIND(bind, LOGL_ERROR, "Can not get interface index for interface %s\n", netif);
Harald Welte41b188b2020-12-10 22:00:23 +0100827 goto err_fr;
828 }
829
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100830 /* set protocol frame relay and lmi */
Harald Weltef2949742021-01-20 14:54:14 +0100831 rc = setup_device(priv->netif, bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100832 if(rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100833 LOGBIND(bind, LOGL_ERROR, "Failed to setup the interface %s for frame relay and lmi\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100834 goto err_fr;
835 }
836
Harald Weltef2949742021-01-20 14:54:14 +0100837 rc = open_socket(priv->ifindex, bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100838 if (rc < 0)
839 goto err_fr;
Harald Welted06128d2021-01-30 21:17:21 +0100840 priv->backlog.retry_us = 2500; /* start with some non-zero value; this corrsponds to 496 bytes */
841 osmo_timer_setup(&priv->backlog.timer, fr_backlog_timer_cb, bind);
842 osmo_fd_setup(&priv->backlog.ofd, rc, OSMO_FD_READ, fr_netif_ofd_cb, bind, 0);
843 rc = osmo_fd_register(&priv->backlog.ofd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100844 if (rc < 0)
845 goto err_fd;
846
Harald Welte56f08a32020-12-01 23:07:32 +0100847#ifdef ENABLE_LIBMNL
848 if (!nsi->linkmon_mnl)
849 nsi->linkmon_mnl = osmo_mnl_init(nsi, NETLINK_ROUTE, RTMGRP_LINK, linkmon_mnl_cb, nsi);
850
851 /* we get a new full dump after every bind. which is a bit excessive. But that's just once
852 * at start-up, so we can get away with it */
853 if (nsi->linkmon_mnl)
854 linkmon_initial_dump(nsi->linkmon_mnl);
855#endif
856
Harald Weltec3aa8f92021-01-31 11:41:34 +0100857 if (result)
858 *result = bind;
859
Alexander Couzens841817e2020-11-19 00:41:29 +0100860 return rc;
861
862err_fd:
Harald Welted06128d2021-01-30 21:17:21 +0100863 close(priv->backlog.ofd.fd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100864err_fr:
865 osmo_fr_link_free(fr_link);
Alexander Couzens841817e2020-11-19 00:41:29 +0100866err_bind:
Harald Weltec3aa8f92021-01-31 11:41:34 +0100867 gprs_ns2_free_bind(bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100868
869 return rc;
870}
871
Alexander Couzensc782cec2020-12-10 04:10:25 +0100872/*! Return the frame relay role of a bind
873 * \param[in] bind The bind
874 * \return the frame relay role or -EINVAL if bind is not frame relay
875 */
876enum osmo_fr_role gprs_ns2_fr_bind_role(struct gprs_ns2_vc_bind *bind)
877{
878 struct priv_bind *priv;
879
880 if (bind->driver != &vc_driver_fr)
881 return -EINVAL;
882
883 priv = bind->priv;
884 return priv->link->role;
885}
886
Alexander Couzens841817e2020-11-19 00:41:29 +0100887/*! Return the network interface of the bind
888 * \param[in] bind The bind
889 * \return the network interface
890 */
891const char *gprs_ns2_fr_bind_netif(struct gprs_ns2_vc_bind *bind)
892{
893 struct priv_bind *priv;
894
895 if (bind->driver != &vc_driver_fr)
896 return NULL;
897
898 priv = bind->priv;
899 return priv->netif;
900}
901
902/*! Find NS bind for a given network interface
903 * \param[in] nsi NS instance
904 * \param[in] netif the network interface to search for
905 * \return the bind or NULL if not found
906 */
907struct gprs_ns2_vc_bind *gprs_ns2_fr_bind_by_netif(
908 struct gprs_ns2_inst *nsi,
909 const char *netif)
910{
911 struct gprs_ns2_vc_bind *bind;
912 const char *_netif;
913
914 OSMO_ASSERT(nsi);
915 OSMO_ASSERT(netif);
916
917 llist_for_each_entry(bind, &nsi->binding, list) {
918 if (!gprs_ns2_is_fr_bind(bind))
919 continue;
920
921 _netif = gprs_ns2_fr_bind_netif(bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100922 if (!strncmp(_netif, netif, IFNAMSIZ))
Alexander Couzens841817e2020-11-19 00:41:29 +0100923 return bind;
924 }
925
926 return NULL;
927}
928
929/*! Create, connect and activate a new FR-based NS-VC
930 * \param[in] bind bind in which the new NS-VC is to be created
931 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
932 * \param[in] dlci Data Link connection identifier
933 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
934struct gprs_ns2_vc *gprs_ns2_fr_connect(struct gprs_ns2_vc_bind *bind,
Alexander Couzensebcbd722020-12-03 06:11:39 +0100935 struct gprs_ns2_nse *nse,
936 uint16_t nsvci,
937 uint16_t dlci)
938{
939 struct gprs_ns2_vc *nsvc = NULL;
940 struct priv_vc *priv = NULL;
Harald Welte603f4042020-11-29 17:39:19 +0100941 struct priv_bind *bpriv = bind->priv;
942 char idbuf[64];
Alexander Couzensebcbd722020-12-03 06:11:39 +0100943
Alexander Couzens55bc8692021-01-18 18:39:57 +0100944 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzensebcbd722020-12-03 06:11:39 +0100945 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
946 if (nsvc) {
947 goto err;
948 }
949
Harald Welte603f4042020-11-29 17:39:19 +0100950 snprintf(idbuf, sizeof(idbuf), "%s-%s-DLCI%u-NSE%05u-NSVC%05u", gprs_ns2_lltype_str(nse->ll),
951 bpriv->netif, dlci, nse->nsei, nsvci);
Alexander Couzens138b96f2021-01-25 16:23:29 +0100952 nsvc = ns2_vc_alloc(bind, nse, true, GPRS_NS2_VC_MODE_BLOCKRESET, idbuf);
Alexander Couzensebcbd722020-12-03 06:11:39 +0100953 if (!nsvc)
954 goto err;
955
956 nsvc->priv = priv = fr_alloc_vc(bind, nsvc, dlci);
957 if (!priv)
958 goto err;
959
960 nsvc->nsvci = nsvci;
961 nsvc->nsvci_is_valid = true;
962
Alexander Couzensebcbd722020-12-03 06:11:39 +0100963 return nsvc;
964
965err:
966 gprs_ns2_free_nsvc(nsvc);
967 return NULL;
968}
969
970
971/*! Create, connect and activate a new FR-based NS-VC
972 * \param[in] bind bind in which the new NS-VC is to be created
973 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
974 * \param[in] dlci Data Link connection identifier
975 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
976struct gprs_ns2_vc *gprs_ns2_fr_connect2(struct gprs_ns2_vc_bind *bind,
Alexander Couzens841817e2020-11-19 00:41:29 +0100977 uint16_t nsei,
978 uint16_t nsvci,
979 uint16_t dlci)
980{
981 bool created_nse = false;
982 struct gprs_ns2_vc *nsvc = NULL;
Alexander Couzens55bc8692021-01-18 18:39:57 +0100983 struct gprs_ns2_nse *nse;
984
985 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
986 nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei);
Alexander Couzens841817e2020-11-19 00:41:29 +0100987 if (!nse) {
Alexander Couzens138b96f2021-01-25 16:23:29 +0100988 nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_FR, GPRS_NS2_DIALECT_STATIC_RESETBLOCK);
Alexander Couzens841817e2020-11-19 00:41:29 +0100989 if (!nse)
990 return NULL;
991 created_nse = true;
992 }
993
Harald Welte509047b2021-01-17 19:55:51 +0100994 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
Alexander Couzens841817e2020-11-19 00:41:29 +0100995 if (!nsvc)
996 goto err_nse;
997
Alexander Couzens841817e2020-11-19 00:41:29 +0100998 return nsvc;
999
Alexander Couzens841817e2020-11-19 00:41:29 +01001000err_nse:
1001 if (created_nse)
1002 gprs_ns2_free_nse(nse);
1003
1004 return NULL;
1005}
1006
1007/*! Return the nsvc by dlci.
1008 * \param[in] bind
1009 * \param[in] dlci Data Link connection identifier
1010 * \return the nsvc or NULL if not found
1011 */
1012struct gprs_ns2_vc *gprs_ns2_fr_nsvc_by_dlci(struct gprs_ns2_vc_bind *bind,
1013 uint16_t dlci)
1014{
1015 struct gprs_ns2_vc *nsvc;
1016 struct priv_vc *vcpriv;
1017
Alexander Couzens55bc8692021-01-18 18:39:57 +01001018 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +01001019 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
1020 vcpriv = nsvc->priv;
1021
1022 if (dlci == vcpriv->dlci)
1023 return nsvc;
1024 }
1025
1026 return NULL;
1027}
1028
1029/*! Return the dlci of the nsvc
1030 * \param[in] nsvc
1031 * \return the dlci or 0 on error. 0 is not a valid dlci.
1032 */
Alexander Couzens22c26e02020-12-10 04:10:07 +01001033uint16_t gprs_ns2_fr_nsvc_dlci(const struct gprs_ns2_vc *nsvc)
Alexander Couzens841817e2020-11-19 00:41:29 +01001034{
1035 struct priv_vc *vcpriv;
1036
1037 if (!nsvc->bind)
1038 return 0;
1039
1040 if (nsvc->bind->driver != &vc_driver_fr)
1041 return 0;
1042
1043 vcpriv = nsvc->priv;
1044 return vcpriv->dlci;
1045}