blob: 782e5a36b5e391c3dc8d62ba887ddae228cf9151 [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
7/* (C) 2009-2010,2014,2017 by Harald Welte <laforge@gnumonks.org>
8 * (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>
39#include <net/if.h>
40
41#include <sys/ioctl.h>
42#include <netpacket/packet.h>
43#include <linux/if_ether.h>
44#include <linux/hdlc.h>
Alexander Couzens841817e2020-11-19 00:41:29 +010045
46#include <osmocom/gprs/frame_relay.h>
47#include <osmocom/core/byteswap.h>
48#include <osmocom/core/logging.h>
49#include <osmocom/core/msgb.h>
50#include <osmocom/core/select.h>
51#include <osmocom/core/socket.h>
52#include <osmocom/core/talloc.h>
53#include <osmocom/gprs/gprs_ns2.h>
54
Pau Espin Pedrold41800c2020-12-07 13:35:24 +010055#ifdef ENABLE_LIBMNL
56#include <osmocom/core/mnl.h>
57#endif
58
Harald Welte56f08a32020-12-01 23:07:32 +010059#include "config.h"
Alexander Couzens841817e2020-11-19 00:41:29 +010060#include "common_vty.h"
61#include "gprs_ns2_internal.h"
62
63#define GRE_PTYPE_FR 0x6559
64#define GRE_PTYPE_IPv4 0x0800
65#define GRE_PTYPE_IPv6 0x86dd
66#define GRE_PTYPE_KAR 0x0000 /* keepalive response */
67
68#ifndef IPPROTO_GRE
69# define IPPROTO_GRE 47
70#endif
71
72struct gre_hdr {
73 uint16_t flags;
74 uint16_t ptype;
75} __attribute__ ((packed));
76
77static void free_bind(struct gprs_ns2_vc_bind *bind);
78static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg);
79
80struct gprs_ns2_vc_driver vc_driver_fr = {
81 .name = "GB frame relay",
82 .free_bind = free_bind,
83};
84
85struct priv_bind {
86 struct osmo_fd fd;
87 char netif[IF_NAMESIZE];
88 struct osmo_fr_link *link;
Harald Welte41b188b2020-12-10 22:00:23 +010089 int ifindex;
Harald Welte56f08a32020-12-01 23:07:32 +010090 bool if_running;
Alexander Couzens841817e2020-11-19 00:41:29 +010091};
92
93struct priv_vc {
94 struct osmo_sockaddr remote;
95 uint16_t dlci;
96 struct osmo_fr_dlc *dlc;
97};
98
99static void free_vc(struct gprs_ns2_vc *nsvc)
100{
101 OSMO_ASSERT(nsvc);
102
103 if (!nsvc->priv)
104 return;
105
106 talloc_free(nsvc->priv);
107 nsvc->priv = NULL;
108}
109
110static void dump_vty(const struct gprs_ns2_vc_bind *bind, struct vty *vty, bool _stats)
111{
112 struct priv_bind *priv;
113 struct gprs_ns2_vc *nsvc;
Harald Welte48bd76c2020-12-01 16:53:06 +0100114 struct osmo_fr_link *fr_link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100115
116 if (!bind)
117 return;
118
119 priv = bind->priv;
Harald Welte48bd76c2020-12-01 16:53:06 +0100120 fr_link = priv->link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100121
Harald Welte56f08a32020-12-01 23:07:32 +0100122 vty_out(vty, "FR bind: %s, role: %s, link: %s%s", priv->netif,
123 osmo_fr_role_str(fr_link->role), priv->if_running ? "UP" : "DOWN", VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +0100124
125 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
Harald Welte96ec84a2020-12-01 17:56:05 +0100126 vty_out(vty, " NSVCI %05u: %s%s", nsvc->nsvci, gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +0100127 }
128
129 priv = bind->priv;
130}
131
132/*! clean up all private driver state. Should be only called by gprs_ns2_free_bind() */
133static void free_bind(struct gprs_ns2_vc_bind *bind)
134{
135 struct priv_bind *priv;
136
137 if (!bind)
138 return;
139
140 priv = bind->priv;
141
142 OSMO_ASSERT(llist_empty(&bind->nsvc));
143
144 osmo_fr_link_free(priv->link);
145 osmo_fd_close(&priv->fd);
146 talloc_free(priv);
147}
148
149static struct priv_vc *fr_alloc_vc(struct gprs_ns2_vc_bind *bind,
150 struct gprs_ns2_vc *nsvc,
151 uint16_t dlci)
152{
153 struct priv_bind *privb = bind->priv;
154 struct priv_vc *priv = talloc_zero(bind, struct priv_vc);
155 if (!priv)
156 return NULL;
157
158 nsvc->priv = priv;
159 priv->dlci = dlci;
160 priv->dlc = osmo_fr_dlc_alloc(privb->link, dlci);
161 if (!priv->dlc) {
162 nsvc->priv = NULL;
163 talloc_free(priv);
164 return NULL;
165 }
166
167 priv->dlc->rx_cb_data = nsvc;
168 priv->dlc->rx_cb = fr_dlci_rx_cb;
169
170 return priv;
171}
172
173int gprs_ns2_find_vc_by_dlci(struct gprs_ns2_vc_bind *bind,
174 uint16_t dlci,
175 struct gprs_ns2_vc **result)
176{
177 struct gprs_ns2_vc *nsvc;
178 struct priv_vc *vcpriv;
179
180 if (!result)
181 return -EINVAL;
182
183 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
184 vcpriv = nsvc->priv;
185 if (vcpriv->dlci != dlci) {
186 *result = nsvc;
187 return 0;
188 }
189 }
190
191 return 1;
192}
193
194/* PDU from the network interface towards the fr layer (upwards) */
195static int handle_netif_read(struct osmo_fd *bfd)
196{
197 struct gprs_ns2_vc_bind *bind = bfd->data;
198 struct priv_bind *priv = bind->priv;
199 struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "Gb/NS/FR/GRE Rx");
Harald Welte41b188b2020-12-10 22:00:23 +0100200 struct sockaddr_ll sll;
201 socklen_t sll_len = sizeof(sll);
Alexander Couzens841817e2020-11-19 00:41:29 +0100202 int rc = 0;
203
204 if (!msg)
205 return -ENOMEM;
206
Harald Welte41b188b2020-12-10 22:00:23 +0100207 rc = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0, (struct sockaddr *)&sll, &sll_len);
Alexander Couzens841817e2020-11-19 00:41:29 +0100208 if (rc < 0) {
209 LOGP(DLNS, LOGL_ERROR, "recv error %s during NS-FR-GRE recv\n",
210 strerror(errno));
211 goto out_err;
212 } else if (rc == 0) {
213 goto out_err;
214 }
215
Harald Welte41b188b2020-12-10 22:00:23 +0100216 /* ignore any packets that we might have received for a different interface, between
217 * the socket() and the bind() call */
218 if (sll.sll_ifindex != priv->ifindex)
219 goto out_err;
220
Alexander Couzens841817e2020-11-19 00:41:29 +0100221 msgb_put(msg, rc);
222 msg->dst = priv->link;
223 return osmo_fr_rx(msg);
224
225out_err:
226 msgb_free(msg);
227 return rc;
228}
229
230/* PDU from the frame relay towards the NS-VC (upwards) */
231static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg)
232{
233 int rc;
234 struct gprs_ns2_vc *nsvc = cb_data;
235
236 rc = ns2_recv_vc(nsvc, msg);
237
238 return rc;
239}
240
241static int handle_netif_write(struct osmo_fd *bfd)
242{
243 /* FIXME */
244 return -EIO;
245}
246
247static int fr_fd_cb(struct osmo_fd *bfd, unsigned int what)
248{
249 int rc = 0;
250
251 if (what & OSMO_FD_READ)
252 rc = handle_netif_read(bfd);
253 if (what & OSMO_FD_WRITE)
254 rc = handle_netif_write(bfd);
255
256 return rc;
257}
258
259/*! determine if given bind is for FR-GRE encapsulation. */
260int gprs_ns2_is_fr_bind(struct gprs_ns2_vc_bind *bind)
261{
262 return (bind->driver == &vc_driver_fr);
263}
264
265/* PDU from the NS-VC towards the frame relay layer (downwards) */
266static int fr_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
267{
268 struct priv_vc *vcpriv = nsvc->priv;
269
270 msg->dst = vcpriv->dlc;
271 return osmo_fr_tx_dlc(msg);
272}
273
274/* PDU from the frame relay layer towards the network interface (downwards) */
275int fr_tx_cb(void *data, struct msgb *msg)
276{
277 struct gprs_ns2_vc_bind *bind = data;
278 struct priv_bind *priv = bind->priv;
279 int rc;
280
281 /* FIXME half writes */
282 rc = write(priv->fd.fd, msg->data, msg->len);
283 msgb_free(msg);
284
285 return rc;
286}
287
288static int devname2ifindex(const char *ifname)
289{
290 struct ifreq ifr;
291 int sk, rc;
292
293 sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
294 if (sk < 0)
295 return sk;
296
297
298 memset(&ifr, 0, sizeof(ifr));
Neels Hofmeyr475a0ac2020-12-17 18:10:34 +0100299 OSMO_STRLCPY_ARRAY(ifr.ifr_name, ifname);
Alexander Couzens841817e2020-11-19 00:41:29 +0100300
301 rc = ioctl(sk, SIOCGIFINDEX, &ifr);
302 close(sk);
303 if (rc < 0)
304 return rc;
305
306 return ifr.ifr_ifindex;
307}
308
Harald Welte41b188b2020-12-10 22:00:23 +0100309static int open_socket(int ifindex)
Alexander Couzens841817e2020-11-19 00:41:29 +0100310{
311 struct sockaddr_ll addr;
Harald Welte4ed0f4e2020-12-10 21:50:32 +0100312 int fd, rc;
Alexander Couzens841817e2020-11-19 00:41:29 +0100313
Alexander Couzens841817e2020-11-19 00:41:29 +0100314 memset(&addr, 0, sizeof(addr));
315 addr.sll_family = AF_PACKET;
316 addr.sll_protocol = htons(ETH_P_ALL);
317 addr.sll_ifindex = ifindex;
318
Harald Welte5bea72e2020-12-10 22:06:21 +0100319 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_HDLC));
Alexander Couzens841817e2020-11-19 00:41:29 +0100320 if (fd < 0) {
Harald Welte41b188b2020-12-10 22:00:23 +0100321 LOGP(DLNS, LOGL_ERROR, "Can not create AF_PACKET socket. Are you root or have CAP_RAW_SOCKET?\n");
Alexander Couzens841817e2020-11-19 00:41:29 +0100322 return fd;
323 }
324
Harald Welte41b188b2020-12-10 22:00:23 +0100325 /* there's a race condition between the above syscall and the bind() call below,
326 * causing other packets to be received in between */
327
Alexander Couzens841817e2020-11-19 00:41:29 +0100328 rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
329 if (rc < 0) {
Harald Welte41b188b2020-12-10 22:00:23 +0100330 LOGP(DLNS, LOGL_ERROR, "Can not bind AF_PACKET socket to ifindex %d\n", ifindex);
Alexander Couzens841817e2020-11-19 00:41:29 +0100331 close(fd);
332 return rc;
333 }
334
335 return fd;
336}
337
Harald Welte56f08a32020-12-01 23:07:32 +0100338#ifdef ENABLE_LIBMNL
339
340#include <osmocom/core/mnl.h>
Harald Welte56f08a32020-12-01 23:07:32 +0100341#include <linux/if_link.h>
342#include <linux/rtnetlink.h>
343
344#ifndef ARPHRD_FRAD
345#define ARPHRD_FRAD 770
346#endif
347
348/* validate the netlink attributes */
349static int data_attr_cb(const struct nlattr *attr, void *data)
350{
351 const struct nlattr **tb = data;
352 int type = mnl_attr_get_type(attr);
353
354 if (mnl_attr_type_valid(attr, IFLA_MAX) < 0)
355 return MNL_CB_OK;
356
357 switch (type) {
358 case IFLA_MTU:
359 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
360 return MNL_CB_ERROR;
361 break;
362 case IFLA_IFNAME:
363 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
364 return MNL_CB_ERROR;
365 break;
366 }
367 tb[type] = attr;
368 return MNL_CB_OK;
369}
370
371/* find the bind for the netdev (if any) */
372static struct gprs_ns2_vc_bind *bind4netdev(struct gprs_ns2_inst *nsi, const char *ifname)
373{
374 struct gprs_ns2_vc_bind *bind;
375
376 llist_for_each_entry(bind, &nsi->binding, list) {
377 struct priv_bind *bpriv = bind->priv;
378 if (!strcmp(bpriv->netif, ifname))
379 return bind;
380 }
381
382 return NULL;
383}
384
385/* handle a single netlink message received via libmnl */
386static int linkmon_mnl_cb(const struct nlmsghdr *nlh, void *data)
387{
388 struct osmo_mnl *omnl = data;
389 struct gprs_ns2_vc_bind *bind;
390 struct nlattr *tb[IFLA_MAX+1] = {};
391 struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh);
392 struct gprs_ns2_inst *nsi;
393 const char *ifname;
394 bool if_running;
395
396 OSMO_ASSERT(omnl);
397 OSMO_ASSERT(ifm);
398
399 nsi = omnl->priv;
400
401 if (ifm->ifi_type != ARPHRD_FRAD)
402 return MNL_CB_OK;
403
404 mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, tb);
405
406 if (!tb[IFLA_IFNAME])
407 return MNL_CB_OK;
408 ifname = mnl_attr_get_str(tb[IFLA_IFNAME]);
409 if_running = !!(ifm->ifi_flags & IFF_RUNNING);
410
411 bind = bind4netdev(nsi, ifname);
412 if (bind) {
413 struct priv_bind *bpriv = bind->priv;
414 if (bpriv->if_running != if_running) {
415 /* update running state */
416 LOGP(DLNS, LOGL_NOTICE, "FR net-device '%s': Physical link state changed: %s\n",
417 ifname, if_running ? "UP" : "DOWN");
418 bpriv->if_running = if_running;
419 }
420 }
421
422 return MNL_CB_OK;
423}
424
425/* trigger one initial dump of all link information */
426static void linkmon_initial_dump(struct osmo_mnl *omnl)
427{
428 char buf[MNL_SOCKET_BUFFER_SIZE];
429 struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
430 struct rtgenmsg *rt;
431
432 nlh->nlmsg_type = RTM_GETLINK;
433 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
434 nlh->nlmsg_seq = time(NULL);
435 rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
436 rt->rtgen_family = AF_PACKET;
437
438 if (mnl_socket_sendto(omnl->mnls, nlh, nlh->nlmsg_len) < 0) {
439 LOGP(DLNS, LOGL_ERROR, "linkmon: Cannot send rtnetlink message: %s\n", strerror(errno));
440 }
441
442 /* the response[s] will be handled just like the events */
443}
444#endif /* LIBMNL */
445
446
Alexander Couzens841817e2020-11-19 00:41:29 +0100447/*! Create a new bind for NS over FR.
448 * \param[in] nsi NS instance in which to create the bind
449 * \param[in] netif Network interface to bind to
450 * \param[in] fr_network
451 * \param[in] fr_role
452 * \param[out] result pointer to created bind
453 * \return 0 on success; negative on error */
454int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi,
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100455 const char *name,
Alexander Couzens841817e2020-11-19 00:41:29 +0100456 const char *netif,
457 struct osmo_fr_network *fr_network,
458 enum osmo_fr_role fr_role,
459 struct gprs_ns2_vc_bind **result)
460{
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100461 struct gprs_ns2_vc_bind *bind;
Alexander Couzens841817e2020-11-19 00:41:29 +0100462 struct priv_bind *priv;
463 struct osmo_fr_link *fr_link;
464 int rc = 0;
465
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100466 if (!name)
467 return -EINVAL;
468
469 if (gprs_ns2_bind_by_name(nsi, name))
470 return -EALREADY;
471
472 bind = talloc_zero(nsi, struct gprs_ns2_vc_bind);
Alexander Couzens841817e2020-11-19 00:41:29 +0100473 if (!bind)
474 return -ENOSPC;
475
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100476 bind->name = talloc_strdup(bind, name);
477 if (!bind->name) {
478 rc = -ENOSPC;
479 goto err_bind;
480 }
481
Alexander Couzens841817e2020-11-19 00:41:29 +0100482 bind->driver = &vc_driver_fr;
Alexander Couzensaac90162020-11-19 02:44:04 +0100483 bind->ll = GPRS_NS2_LL_FR;
Alexander Couzens841817e2020-11-19 00:41:29 +0100484 bind->send_vc = fr_vc_sendmsg;
485 bind->free_vc = free_vc;
486 bind->dump_vty = dump_vty;
487 bind->nsi = nsi;
488 priv = bind->priv = talloc_zero(bind, struct priv_bind);
489 if (!priv) {
490 rc = -ENOSPC;
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100491 goto err_name;
Alexander Couzens841817e2020-11-19 00:41:29 +0100492 }
493
494 priv->fd.cb = fr_fd_cb;
495 priv->fd.data = bind;
496 if (strlen(netif) > IF_NAMESIZE) {
497 rc = -EINVAL;
498 goto err_priv;
499 }
Neels Hofmeyr8fef7612020-12-17 18:19:19 +0100500 OSMO_STRLCPY_ARRAY(priv->netif, netif);
Alexander Couzens841817e2020-11-19 00:41:29 +0100501
Alexander Couzens841817e2020-11-19 00:41:29 +0100502 if (result)
503 *result = bind;
504
505 /* FIXME: move fd handling into socket.c */
506 fr_link = osmo_fr_link_alloc(fr_network, fr_role, netif);
507 if (!fr_link) {
508 rc = -EINVAL;
509 goto err_priv;
510 }
511
512 fr_link->tx_cb = fr_tx_cb;
513 fr_link->tx_cb_data = bind;
514 priv->link = fr_link;
Harald Welte41b188b2020-12-10 22:00:23 +0100515
Alexander Couzens6f89c772020-12-17 03:06:39 +0100516 priv->ifindex = rc = devname2ifindex(netif);
517 if (rc < 0) {
Harald Welte41b188b2020-12-10 22:00:23 +0100518 LOGP(DLNS, LOGL_ERROR, "Can not get interface index for interface %s\n", netif);
519 goto err_fr;
520 }
521
522 priv->fd.fd = rc = open_socket(priv->ifindex);
Alexander Couzens841817e2020-11-19 00:41:29 +0100523 if (rc < 0)
524 goto err_fr;
525
526 priv->fd.when = OSMO_FD_READ;
527 rc = osmo_fd_register(&priv->fd);
528 if (rc < 0)
529 goto err_fd;
530
531 INIT_LLIST_HEAD(&bind->nsvc);
532 llist_add(&bind->list, &nsi->binding);
533
Harald Welte56f08a32020-12-01 23:07:32 +0100534#ifdef ENABLE_LIBMNL
535 if (!nsi->linkmon_mnl)
536 nsi->linkmon_mnl = osmo_mnl_init(nsi, NETLINK_ROUTE, RTMGRP_LINK, linkmon_mnl_cb, nsi);
537
538 /* we get a new full dump after every bind. which is a bit excessive. But that's just once
539 * at start-up, so we can get away with it */
540 if (nsi->linkmon_mnl)
541 linkmon_initial_dump(nsi->linkmon_mnl);
542#endif
543
Alexander Couzens841817e2020-11-19 00:41:29 +0100544 return rc;
545
546err_fd:
547 close(priv->fd.fd);
548err_fr:
549 osmo_fr_link_free(fr_link);
550err_priv:
551 talloc_free(priv);
Alexander Couzensaaa55a62020-12-03 06:02:03 +0100552err_name:
553 talloc_free((char *)bind->name);
Alexander Couzens841817e2020-11-19 00:41:29 +0100554err_bind:
555 talloc_free(bind);
556
557 return rc;
558}
559
Alexander Couzensc782cec2020-12-10 04:10:25 +0100560/*! Return the frame relay role of a bind
561 * \param[in] bind The bind
562 * \return the frame relay role or -EINVAL if bind is not frame relay
563 */
564enum osmo_fr_role gprs_ns2_fr_bind_role(struct gprs_ns2_vc_bind *bind)
565{
566 struct priv_bind *priv;
567
568 if (bind->driver != &vc_driver_fr)
569 return -EINVAL;
570
571 priv = bind->priv;
572 return priv->link->role;
573}
574
Alexander Couzens841817e2020-11-19 00:41:29 +0100575/*! Return the network interface of the bind
576 * \param[in] bind The bind
577 * \return the network interface
578 */
579const char *gprs_ns2_fr_bind_netif(struct gprs_ns2_vc_bind *bind)
580{
581 struct priv_bind *priv;
582
583 if (bind->driver != &vc_driver_fr)
584 return NULL;
585
586 priv = bind->priv;
587 return priv->netif;
588}
589
590/*! Find NS bind for a given network interface
591 * \param[in] nsi NS instance
592 * \param[in] netif the network interface to search for
593 * \return the bind or NULL if not found
594 */
595struct gprs_ns2_vc_bind *gprs_ns2_fr_bind_by_netif(
596 struct gprs_ns2_inst *nsi,
597 const char *netif)
598{
599 struct gprs_ns2_vc_bind *bind;
600 const char *_netif;
601
602 OSMO_ASSERT(nsi);
603 OSMO_ASSERT(netif);
604
605 llist_for_each_entry(bind, &nsi->binding, list) {
606 if (!gprs_ns2_is_fr_bind(bind))
607 continue;
608
609 _netif = gprs_ns2_fr_bind_netif(bind);
610 if (!strncmp(_netif, netif, IF_NAMESIZE))
611 return bind;
612 }
613
614 return NULL;
615}
616
617/*! Create, connect and activate a new FR-based NS-VC
618 * \param[in] bind bind in which the new NS-VC is to be created
619 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
620 * \param[in] dlci Data Link connection identifier
621 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
622struct gprs_ns2_vc *gprs_ns2_fr_connect(struct gprs_ns2_vc_bind *bind,
Alexander Couzensebcbd722020-12-03 06:11:39 +0100623 struct gprs_ns2_nse *nse,
624 uint16_t nsvci,
625 uint16_t dlci)
626{
627 struct gprs_ns2_vc *nsvc = NULL;
628 struct priv_vc *priv = NULL;
629
630 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
631 if (nsvc) {
632 goto err;
633 }
634
635 nsvc = ns2_vc_alloc(bind, nse, true, NS2_VC_MODE_BLOCKRESET);
636 if (!nsvc)
637 goto err;
638
639 nsvc->priv = priv = fr_alloc_vc(bind, nsvc, dlci);
640 if (!priv)
641 goto err;
642
643 nsvc->nsvci = nsvci;
644 nsvc->nsvci_is_valid = true;
645
646 gprs_ns2_vc_fsm_start(nsvc);
647
648 return nsvc;
649
650err:
651 gprs_ns2_free_nsvc(nsvc);
652 return NULL;
653}
654
655
656/*! Create, connect and activate a new FR-based NS-VC
657 * \param[in] bind bind in which the new NS-VC is to be created
658 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
659 * \param[in] dlci Data Link connection identifier
660 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
661struct gprs_ns2_vc *gprs_ns2_fr_connect2(struct gprs_ns2_vc_bind *bind,
Alexander Couzens841817e2020-11-19 00:41:29 +0100662 uint16_t nsei,
663 uint16_t nsvci,
664 uint16_t dlci)
665{
666 bool created_nse = false;
667 struct gprs_ns2_vc *nsvc = NULL;
668 struct priv_vc *priv = NULL;
669 struct gprs_ns2_nse *nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei);
670 if (!nse) {
Alexander Couzensd923cff2020-12-01 01:03:52 +0100671 nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_FR, NS2_DIALECT_STATIC_RESETBLOCK);
Alexander Couzens841817e2020-11-19 00:41:29 +0100672 if (!nse)
673 return NULL;
674 created_nse = true;
675 }
676
677 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
678 if (nsvc) {
679 goto err_nse;
680 }
681
Alexander Couzensd923cff2020-12-01 01:03:52 +0100682 nsvc = ns2_vc_alloc(bind, nse, true, NS2_VC_MODE_BLOCKRESET);
Alexander Couzens841817e2020-11-19 00:41:29 +0100683 if (!nsvc)
684 goto err_nse;
685
686 nsvc->priv = priv = fr_alloc_vc(bind, nsvc, dlci);
687 if (!priv)
688 goto err;
689
690 nsvc->nsvci = nsvci;
691 nsvc->nsvci_is_valid = true;
Alexander Couzens841817e2020-11-19 00:41:29 +0100692
693 gprs_ns2_vc_fsm_start(nsvc);
694
695 return nsvc;
696
697err:
698 gprs_ns2_free_nsvc(nsvc);
699err_nse:
700 if (created_nse)
701 gprs_ns2_free_nse(nse);
702
703 return NULL;
704}
705
706/*! Return the nsvc by dlci.
707 * \param[in] bind
708 * \param[in] dlci Data Link connection identifier
709 * \return the nsvc or NULL if not found
710 */
711struct gprs_ns2_vc *gprs_ns2_fr_nsvc_by_dlci(struct gprs_ns2_vc_bind *bind,
712 uint16_t dlci)
713{
714 struct gprs_ns2_vc *nsvc;
715 struct priv_vc *vcpriv;
716
717 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
718 vcpriv = nsvc->priv;
719
720 if (dlci == vcpriv->dlci)
721 return nsvc;
722 }
723
724 return NULL;
725}
726
727/*! Return the dlci of the nsvc
728 * \param[in] nsvc
729 * \return the dlci or 0 on error. 0 is not a valid dlci.
730 */
Alexander Couzens22c26e02020-12-10 04:10:07 +0100731uint16_t gprs_ns2_fr_nsvc_dlci(const struct gprs_ns2_vc *nsvc)
Alexander Couzens841817e2020-11-19 00:41:29 +0100732{
733 struct priv_vc *vcpriv;
734
735 if (!nsvc->bind)
736 return 0;
737
738 if (nsvc->bind->driver != &vc_driver_fr)
739 return 0;
740
741 vcpriv = nsvc->priv;
742 return vcpriv->dlci;
743}