blob: 35e0dd9ececc312523d4c62ed8cf40ed01cd7ff7 [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
Alexander Couzens75b61882021-03-21 16:18:17 +0100138static void dump_vty(const struct gprs_ns2_vc_bind *bind, struct vty *vty, bool stats)
Alexander Couzens841817e2020-11-19 00:41:29 +0100139{
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) {
Alexander Couzens75b61882021-03-21 16:18:17 +0100154 ns2_vty_dump_nsvc(vty, nsvc, stats);
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);
Pau Espin Pedrol7b894a72021-06-04 18:17:12 +0200350 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 +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);
Pau Espin Pedrol7b894a72021-06-04 18:17:12 +0200358 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 +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 }
Pau Espin Pedrol7b894a72021-06-04 18:17:12 +0200442 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 +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
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100599static void mtu_change(struct gprs_ns2_vc_bind *bind, uint32_t mtu)
600{
601 struct priv_bind *bpriv = bind->priv;
602 struct gprs_ns2_nse *nse;
603
Alexander Couzensa6096ad2021-07-02 16:23:06 +0200604 /* 2 byte DLCI header */
605 if (mtu <= 2)
606 return;
607 mtu -= 2;
608
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100609 if (mtu == bind->mtu)
610 return;
611
612 LOGBIND(bind, LOGL_INFO, "MTU changed from %d to %d.\n",
Alexander Couzensa6096ad2021-07-02 16:23:06 +0200613 bind->mtu + 2, mtu + 2);
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100614
Alexander Couzensa6096ad2021-07-02 16:23:06 +0200615 bind->mtu = mtu;
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100616 if (!bpriv->if_running)
617 return;
618
619 llist_for_each_entry(nse, &bind->nsi->nse, list) {
620 ns2_nse_update_mtu(nse);
621 }
622}
623
Harald Welte56f08a32020-12-01 23:07:32 +0100624/* handle a single netlink message received via libmnl */
625static int linkmon_mnl_cb(const struct nlmsghdr *nlh, void *data)
626{
627 struct osmo_mnl *omnl = data;
628 struct gprs_ns2_vc_bind *bind;
629 struct nlattr *tb[IFLA_MAX+1] = {};
630 struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh);
631 struct gprs_ns2_inst *nsi;
632 const char *ifname;
633 bool if_running;
634
635 OSMO_ASSERT(omnl);
636 OSMO_ASSERT(ifm);
637
638 nsi = omnl->priv;
639
640 if (ifm->ifi_type != ARPHRD_FRAD)
641 return MNL_CB_OK;
642
643 mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, tb);
644
645 if (!tb[IFLA_IFNAME])
646 return MNL_CB_OK;
647 ifname = mnl_attr_get_str(tb[IFLA_IFNAME]);
648 if_running = !!(ifm->ifi_flags & IFF_RUNNING);
649
650 bind = bind4netdev(nsi, ifname);
Alexander Couzens3de1cb02021-02-15 02:58:22 +0100651 if (!bind)
652 return MNL_CB_OK;
653
654 if (tb[IFLA_MTU]) {
655 mtu_change(bind, mnl_attr_get_u32(tb[IFLA_MTU]));
656 }
657
658 link_state_change(bind, if_running);
Harald Welte56f08a32020-12-01 23:07:32 +0100659
660 return MNL_CB_OK;
661}
662
663/* trigger one initial dump of all link information */
664static void linkmon_initial_dump(struct osmo_mnl *omnl)
665{
666 char buf[MNL_SOCKET_BUFFER_SIZE];
667 struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
668 struct rtgenmsg *rt;
669
670 nlh->nlmsg_type = RTM_GETLINK;
671 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
672 nlh->nlmsg_seq = time(NULL);
673 rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
674 rt->rtgen_family = AF_PACKET;
675
676 if (mnl_socket_sendto(omnl->mnls, nlh, nlh->nlmsg_len) < 0) {
677 LOGP(DLNS, LOGL_ERROR, "linkmon: Cannot send rtnetlink message: %s\n", strerror(errno));
678 }
679
680 /* the response[s] will be handled just like the events */
681}
682#endif /* LIBMNL */
683
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100684static int set_ifupdown(const char *netif, bool up)
685{
686 int sock, rc;
687 struct ifreq req;
688
689 sock = socket(AF_INET, SOCK_DGRAM, 0);
690 if (sock < 0)
691 return sock;
692
693 memset(&req, 0, sizeof req);
Harald Welte7f01b682020-12-21 12:39:38 +0100694 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100695
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100696 rc = ioctl(sock, SIOCGIFFLAGS, &req);
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100697 if (rc < 0) {
698 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100699 return rc;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100700 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100701
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100702 if ((req.ifr_flags & IFF_UP) == up) {
703 close(sock);
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100704 return 0;
Vadim Yanitskiy222e8442021-01-05 14:33:29 +0100705 }
Alexander Couzensfdea03b2020-12-29 23:13:23 +0100706
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100707 if (up)
708 req.ifr_flags |= IFF_UP;
709
710 rc = ioctl(sock, SIOCSIFFLAGS, &req);
711 close(sock);
712 return rc;
713}
714
Harald Weltef2949742021-01-20 14:54:14 +0100715static int setup_device(const char *netif, const struct gprs_ns2_vc_bind *bind)
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100716{
717 int sock, rc;
718 char buffer[128];
719 fr_proto *fr = (void*)buffer;
720 struct ifreq req;
721
722 sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
723 if (sock < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100724 LOGBIND(bind, LOGL_ERROR, "%s: Unable to create socket: %s\n",
725 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100726 return sock;
727 }
728
729 memset(&req, 0, sizeof(struct ifreq));
730 memset(&buffer, 0, sizeof(buffer));
Harald Welteb8de1882020-12-21 12:40:45 +0100731 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100732 req.ifr_settings.ifs_ifsu.sync = (void*)buffer;
733 req.ifr_settings.size = sizeof(buffer);
734 req.ifr_settings.type = IF_GET_PROTO;
735
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100736 /* EINVAL is returned when no protocol has been set */
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100737 rc = ioctl(sock, SIOCWANDEV, &req);
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100738 if (rc < 0 && errno != EINVAL) {
Harald Weltef2949742021-01-20 14:54:14 +0100739 LOGBIND(bind, LOGL_ERROR, "%s: Unable to get FR protocol information: %s\n",
740 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100741 goto err;
742 }
743
744 /* check if the device is good */
Alexander Couzens8c33d4a2020-12-22 15:42:01 +0100745 if (rc == 0 && req.ifr_settings.type == IF_PROTO_FR && fr->lmi == LMI_NONE) {
Harald Weltef2949742021-01-20 14:54:14 +0100746 LOGBIND(bind, LOGL_NOTICE, "%s: has correct frame relay mode and lmi\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100747 goto ifup;
748 }
749
750 /* modify the device to match */
751 rc = set_ifupdown(netif, false);
752 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100753 LOGBIND(bind, LOGL_ERROR, "Unable to bring down the device %s: %s\n",
754 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100755 goto err;
756 }
757
758 memset(&req, 0, sizeof(struct ifreq));
759 memset(fr, 0, sizeof(fr_proto));
Harald Welteb8de1882020-12-21 12:40:45 +0100760 OSMO_STRLCPY_ARRAY(req.ifr_name, netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100761 req.ifr_settings.type = IF_PROTO_FR;
762 req.ifr_settings.size = sizeof(fr_proto);
763 req.ifr_settings.ifs_ifsu.fr = fr;
764 fr->lmi = LMI_NONE;
765 /* even those settings aren't used, they must be in the range */
766 /* polling verification timer*/
767 fr->t391 = 10;
768 /* link integrity verification polling timer */
769 fr->t392 = 15;
770 /* full status polling counter*/
771 fr->n391 = 6;
772 /* error threshold */
773 fr->n392 = 3;
774 /* monitored events count */
775 fr->n393 = 4;
776
Harald Weltef2949742021-01-20 14:54:14 +0100777 LOGBIND(bind, LOGL_INFO, "%s: Setting frame relay related parameters\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100778 rc = ioctl(sock, SIOCWANDEV, &req);
779 if (rc) {
Harald Weltef2949742021-01-20 14:54:14 +0100780 LOGBIND(bind, LOGL_ERROR, "%s: Unable to set FR protocol on information: %s\n",
781 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100782 goto err;
783 }
784
785ifup:
786 rc = set_ifupdown(netif, true);
787 if (rc)
Harald Weltef2949742021-01-20 14:54:14 +0100788 LOGBIND(bind, LOGL_ERROR, "Unable to bring up the device %s: %s\n",
789 netif, strerror(errno));
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100790err:
791 close(sock);
792 return rc;
793}
Harald Welte56f08a32020-12-01 23:07:32 +0100794
Alexander Couzens841817e2020-11-19 00:41:29 +0100795/*! Create a new bind for NS over FR.
796 * \param[in] nsi NS instance in which to create the bind
797 * \param[in] netif Network interface to bind to
798 * \param[in] fr_network
799 * \param[in] fr_role
Alexander Couzensc80a8742021-02-03 11:27:52 +0100800 * \param[out] result pointer to the created bind or if a bind with the name exists return the bind.
801 * \return 0 on success; negative on error. -EALREADY returned in case a bind with the name exists */
Alexander Couzens841817e2020-11-19 00:41:29 +0100802int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi,
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100803 const char *name,
Alexander Couzens841817e2020-11-19 00:41:29 +0100804 const char *netif,
805 struct osmo_fr_network *fr_network,
806 enum osmo_fr_role fr_role,
807 struct gprs_ns2_vc_bind **result)
808{
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100809 struct gprs_ns2_vc_bind *bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100810 struct priv_bind *priv;
811 struct osmo_fr_link *fr_link;
812 int rc = 0;
813
Harald Weltec3aa8f92021-01-31 11:41:34 +0100814 if (strlen(netif) > IFNAMSIZ)
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100815 return -EINVAL;
816
Alexander Couzensc80a8742021-02-03 11:27:52 +0100817 bind = gprs_ns2_bind_by_name(nsi, name);
818 if (bind) {
819 if (result)
820 *result = bind;
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100821 return -EALREADY;
Alexander Couzensc80a8742021-02-03 11:27:52 +0100822 }
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100823
Harald Weltec3aa8f92021-01-31 11:41:34 +0100824 rc = ns2_bind_alloc(nsi, name, &bind);
825 if (rc < 0)
826 return rc;
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100827
Alexander Couzens841817e2020-11-19 00:41:29 +0100828 bind->driver = &vc_driver_fr;
Alexander Couzensaac90162020-11-19 02:44:04 +0100829 bind->ll = GPRS_NS2_LL_FR;
Alexander Couzens1c8785d2020-12-17 06:58:53 +0100830 /* 2 mbit */
831 bind->transfer_capability = 2;
Alexander Couzens841817e2020-11-19 00:41:29 +0100832 bind->send_vc = fr_vc_sendmsg;
833 bind->free_vc = free_vc;
834 bind->dump_vty = dump_vty;
Alexander Couzens4f1128f2021-01-20 17:42:48 +0100835 bind->mtu = FRAME_RELAY_SDU;
Alexander Couzens841817e2020-11-19 00:41:29 +0100836 priv = bind->priv = talloc_zero(bind, struct priv_bind);
837 if (!priv) {
Harald Weltebdfb8b92021-01-31 11:44:57 +0100838 rc = -ENOMEM;
Harald Weltec3aa8f92021-01-31 11:41:34 +0100839 goto err_bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100840 }
841
Harald Weltece6e4b72021-02-11 15:58:40 +0100842 INIT_LLIST_HEAD(&priv->backlog.list);
Neels Hofmeyr8fef7612020-12-17 18:19:19 +0100843 OSMO_STRLCPY_ARRAY(priv->netif, netif);
Alexander Couzens841817e2020-11-19 00:41:29 +0100844
Alexander Couzens841817e2020-11-19 00:41:29 +0100845 /* FIXME: move fd handling into socket.c */
846 fr_link = osmo_fr_link_alloc(fr_network, fr_role, netif);
847 if (!fr_link) {
848 rc = -EINVAL;
Harald Weltec3aa8f92021-01-31 11:41:34 +0100849 goto err_bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100850 }
851
852 fr_link->tx_cb = fr_tx_cb;
Harald Welte2cc1d4d2021-01-31 18:33:31 +0100853 fr_link->cb_data = bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100854 priv->link = fr_link;
Harald Welte41b188b2020-12-10 22:00:23 +0100855
Alexander Couzens6f89c772020-12-17 03:06:39 +0100856 priv->ifindex = rc = devname2ifindex(netif);
857 if (rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100858 LOGBIND(bind, LOGL_ERROR, "Can not get interface index for interface %s\n", netif);
Harald Welte41b188b2020-12-10 22:00:23 +0100859 goto err_fr;
860 }
861
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100862 /* set protocol frame relay and lmi */
Harald Weltef2949742021-01-20 14:54:14 +0100863 rc = setup_device(priv->netif, bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100864 if(rc < 0) {
Harald Weltef2949742021-01-20 14:54:14 +0100865 LOGBIND(bind, LOGL_ERROR, "Failed to setup the interface %s for frame relay and lmi\n", netif);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100866 goto err_fr;
867 }
868
Harald Weltef2949742021-01-20 14:54:14 +0100869 rc = open_socket(priv->ifindex, bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100870 if (rc < 0)
871 goto err_fr;
Harald Welted06128d2021-01-30 21:17:21 +0100872 priv->backlog.retry_us = 2500; /* start with some non-zero value; this corrsponds to 496 bytes */
873 osmo_timer_setup(&priv->backlog.timer, fr_backlog_timer_cb, bind);
874 osmo_fd_setup(&priv->backlog.ofd, rc, OSMO_FD_READ, fr_netif_ofd_cb, bind, 0);
875 rc = osmo_fd_register(&priv->backlog.ofd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100876 if (rc < 0)
877 goto err_fd;
878
Harald Welte56f08a32020-12-01 23:07:32 +0100879#ifdef ENABLE_LIBMNL
880 if (!nsi->linkmon_mnl)
881 nsi->linkmon_mnl = osmo_mnl_init(nsi, NETLINK_ROUTE, RTMGRP_LINK, linkmon_mnl_cb, nsi);
882
883 /* we get a new full dump after every bind. which is a bit excessive. But that's just once
884 * at start-up, so we can get away with it */
885 if (nsi->linkmon_mnl)
886 linkmon_initial_dump(nsi->linkmon_mnl);
887#endif
888
Harald Weltec3aa8f92021-01-31 11:41:34 +0100889 if (result)
890 *result = bind;
891
Alexander Couzens841817e2020-11-19 00:41:29 +0100892 return rc;
893
894err_fd:
Harald Welted06128d2021-01-30 21:17:21 +0100895 close(priv->backlog.ofd.fd);
Alexander Couzens841817e2020-11-19 00:41:29 +0100896err_fr:
897 osmo_fr_link_free(fr_link);
Harald Welte855155c2021-02-11 16:07:18 +0100898 priv->link = NULL;
Alexander Couzens841817e2020-11-19 00:41:29 +0100899err_bind:
Harald Weltec3aa8f92021-01-31 11:41:34 +0100900 gprs_ns2_free_bind(bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100901
902 return rc;
903}
904
Alexander Couzensc782cec2020-12-10 04:10:25 +0100905/*! Return the frame relay role of a bind
906 * \param[in] bind The bind
907 * \return the frame relay role or -EINVAL if bind is not frame relay
908 */
909enum osmo_fr_role gprs_ns2_fr_bind_role(struct gprs_ns2_vc_bind *bind)
910{
911 struct priv_bind *priv;
912
913 if (bind->driver != &vc_driver_fr)
914 return -EINVAL;
915
916 priv = bind->priv;
917 return priv->link->role;
918}
919
Alexander Couzens841817e2020-11-19 00:41:29 +0100920/*! Return the network interface of the bind
921 * \param[in] bind The bind
922 * \return the network interface
923 */
924const char *gprs_ns2_fr_bind_netif(struct gprs_ns2_vc_bind *bind)
925{
926 struct priv_bind *priv;
927
928 if (bind->driver != &vc_driver_fr)
929 return NULL;
930
931 priv = bind->priv;
932 return priv->netif;
933}
934
935/*! Find NS bind for a given network interface
936 * \param[in] nsi NS instance
937 * \param[in] netif the network interface to search for
938 * \return the bind or NULL if not found
939 */
940struct gprs_ns2_vc_bind *gprs_ns2_fr_bind_by_netif(
941 struct gprs_ns2_inst *nsi,
942 const char *netif)
943{
944 struct gprs_ns2_vc_bind *bind;
945 const char *_netif;
946
947 OSMO_ASSERT(nsi);
948 OSMO_ASSERT(netif);
949
950 llist_for_each_entry(bind, &nsi->binding, list) {
951 if (!gprs_ns2_is_fr_bind(bind))
952 continue;
953
954 _netif = gprs_ns2_fr_bind_netif(bind);
Alexander Couzens5c96f5d2020-12-17 04:45:03 +0100955 if (!strncmp(_netif, netif, IFNAMSIZ))
Alexander Couzens841817e2020-11-19 00:41:29 +0100956 return bind;
957 }
958
959 return NULL;
960}
961
962/*! Create, connect and activate a new FR-based NS-VC
963 * \param[in] bind bind in which the new NS-VC is to be created
964 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
965 * \param[in] dlci Data Link connection identifier
966 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
967struct gprs_ns2_vc *gprs_ns2_fr_connect(struct gprs_ns2_vc_bind *bind,
Alexander Couzensebcbd722020-12-03 06:11:39 +0100968 struct gprs_ns2_nse *nse,
969 uint16_t nsvci,
970 uint16_t dlci)
971{
972 struct gprs_ns2_vc *nsvc = NULL;
973 struct priv_vc *priv = NULL;
Harald Welte603f4042020-11-29 17:39:19 +0100974 struct priv_bind *bpriv = bind->priv;
975 char idbuf[64];
Alexander Couzensebcbd722020-12-03 06:11:39 +0100976
Alexander Couzens55bc8692021-01-18 18:39:57 +0100977 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzensebcbd722020-12-03 06:11:39 +0100978 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
979 if (nsvc) {
980 goto err;
981 }
982
Alexander Couzensd7948062021-06-03 20:35:47 +0200983 snprintf(idbuf, sizeof(idbuf), "NSE%05u-NSVC%05u-%s-%s-DLCI%u", nse->nsei, nsvci,
984 gprs_ns2_lltype_str(nse->ll), bpriv->netif, dlci);
985 osmo_identifier_sanitize_buf(idbuf, NULL, '_');
Alexander Couzens138b96f2021-01-25 16:23:29 +0100986 nsvc = ns2_vc_alloc(bind, nse, true, GPRS_NS2_VC_MODE_BLOCKRESET, idbuf);
Alexander Couzensebcbd722020-12-03 06:11:39 +0100987 if (!nsvc)
988 goto err;
989
990 nsvc->priv = priv = fr_alloc_vc(bind, nsvc, dlci);
991 if (!priv)
992 goto err;
993
994 nsvc->nsvci = nsvci;
995 nsvc->nsvci_is_valid = true;
996
Alexander Couzensebcbd722020-12-03 06:11:39 +0100997 return nsvc;
998
999err:
1000 gprs_ns2_free_nsvc(nsvc);
1001 return NULL;
1002}
1003
1004
1005/*! Create, connect and activate a new FR-based NS-VC
1006 * \param[in] bind bind in which the new NS-VC is to be created
1007 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
1008 * \param[in] dlci Data Link connection identifier
1009 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
1010struct gprs_ns2_vc *gprs_ns2_fr_connect2(struct gprs_ns2_vc_bind *bind,
Alexander Couzens841817e2020-11-19 00:41:29 +01001011 uint16_t nsei,
1012 uint16_t nsvci,
1013 uint16_t dlci)
1014{
1015 bool created_nse = false;
1016 struct gprs_ns2_vc *nsvc = NULL;
Alexander Couzens55bc8692021-01-18 18:39:57 +01001017 struct gprs_ns2_nse *nse;
1018
1019 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
1020 nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei);
Alexander Couzens841817e2020-11-19 00:41:29 +01001021 if (!nse) {
Alexander Couzens138b96f2021-01-25 16:23:29 +01001022 nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_FR, GPRS_NS2_DIALECT_STATIC_RESETBLOCK);
Alexander Couzens841817e2020-11-19 00:41:29 +01001023 if (!nse)
1024 return NULL;
1025 created_nse = true;
1026 }
1027
Harald Welte509047b2021-01-17 19:55:51 +01001028 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
Alexander Couzens841817e2020-11-19 00:41:29 +01001029 if (!nsvc)
1030 goto err_nse;
1031
Alexander Couzens841817e2020-11-19 00:41:29 +01001032 return nsvc;
1033
Alexander Couzens841817e2020-11-19 00:41:29 +01001034err_nse:
1035 if (created_nse)
1036 gprs_ns2_free_nse(nse);
1037
1038 return NULL;
1039}
1040
1041/*! Return the nsvc by dlci.
1042 * \param[in] bind
1043 * \param[in] dlci Data Link connection identifier
1044 * \return the nsvc or NULL if not found
1045 */
1046struct gprs_ns2_vc *gprs_ns2_fr_nsvc_by_dlci(struct gprs_ns2_vc_bind *bind,
1047 uint16_t dlci)
1048{
1049 struct gprs_ns2_vc *nsvc;
1050 struct priv_vc *vcpriv;
1051
Alexander Couzens55bc8692021-01-18 18:39:57 +01001052 OSMO_ASSERT(gprs_ns2_is_fr_bind(bind));
Alexander Couzens841817e2020-11-19 00:41:29 +01001053 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
1054 vcpriv = nsvc->priv;
1055
1056 if (dlci == vcpriv->dlci)
1057 return nsvc;
1058 }
1059
1060 return NULL;
1061}
1062
1063/*! Return the dlci of the nsvc
1064 * \param[in] nsvc
1065 * \return the dlci or 0 on error. 0 is not a valid dlci.
1066 */
Alexander Couzens22c26e02020-12-10 04:10:07 +01001067uint16_t gprs_ns2_fr_nsvc_dlci(const struct gprs_ns2_vc *nsvc)
Alexander Couzens841817e2020-11-19 00:41:29 +01001068{
1069 struct priv_vc *vcpriv;
1070
1071 if (!nsvc->bind)
1072 return 0;
1073
1074 if (nsvc->bind->driver != &vc_driver_fr)
1075 return 0;
1076
1077 vcpriv = nsvc->priv;
1078 return vcpriv->dlci;
1079}