blob: 47d3a5dd0762ca87eb96d4ec66bb93ed6158b8e1 [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
55#include "common_vty.h"
56#include "gprs_ns2_internal.h"
57
58#define GRE_PTYPE_FR 0x6559
59#define GRE_PTYPE_IPv4 0x0800
60#define GRE_PTYPE_IPv6 0x86dd
61#define GRE_PTYPE_KAR 0x0000 /* keepalive response */
62
63#ifndef IPPROTO_GRE
64# define IPPROTO_GRE 47
65#endif
66
67struct gre_hdr {
68 uint16_t flags;
69 uint16_t ptype;
70} __attribute__ ((packed));
71
72static void free_bind(struct gprs_ns2_vc_bind *bind);
73static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg);
74
75struct gprs_ns2_vc_driver vc_driver_fr = {
76 .name = "GB frame relay",
77 .free_bind = free_bind,
78};
79
80struct priv_bind {
81 struct osmo_fd fd;
82 char netif[IF_NAMESIZE];
83 struct osmo_fr_link *link;
84};
85
86struct priv_vc {
87 struct osmo_sockaddr remote;
88 uint16_t dlci;
89 struct osmo_fr_dlc *dlc;
90};
91
92static void free_vc(struct gprs_ns2_vc *nsvc)
93{
94 OSMO_ASSERT(nsvc);
95
96 if (!nsvc->priv)
97 return;
98
99 talloc_free(nsvc->priv);
100 nsvc->priv = NULL;
101}
102
103static void dump_vty(const struct gprs_ns2_vc_bind *bind, struct vty *vty, bool _stats)
104{
105 struct priv_bind *priv;
106 struct gprs_ns2_vc *nsvc;
Harald Welte48bd76c2020-12-01 16:53:06 +0100107 struct osmo_fr_link *fr_link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100108
109 if (!bind)
110 return;
111
112 priv = bind->priv;
Harald Welte48bd76c2020-12-01 16:53:06 +0100113 fr_link = priv->link;
Alexander Couzens841817e2020-11-19 00:41:29 +0100114
Harald Welte48bd76c2020-12-01 16:53:06 +0100115 vty_out(vty, "FR bind: %s, role: %s%s", priv->netif,
116 osmo_fr_role_str(fr_link->role), VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +0100117
118 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
Harald Welte96ec84a2020-12-01 17:56:05 +0100119 vty_out(vty, " NSVCI %05u: %s%s", nsvc->nsvci, gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +0100120 }
121
122 priv = bind->priv;
123}
124
125/*! clean up all private driver state. Should be only called by gprs_ns2_free_bind() */
126static void free_bind(struct gprs_ns2_vc_bind *bind)
127{
128 struct priv_bind *priv;
129
130 if (!bind)
131 return;
132
133 priv = bind->priv;
134
135 OSMO_ASSERT(llist_empty(&bind->nsvc));
136
137 osmo_fr_link_free(priv->link);
138 osmo_fd_close(&priv->fd);
139 talloc_free(priv);
140}
141
142static struct priv_vc *fr_alloc_vc(struct gprs_ns2_vc_bind *bind,
143 struct gprs_ns2_vc *nsvc,
144 uint16_t dlci)
145{
146 struct priv_bind *privb = bind->priv;
147 struct priv_vc *priv = talloc_zero(bind, struct priv_vc);
148 if (!priv)
149 return NULL;
150
151 nsvc->priv = priv;
152 priv->dlci = dlci;
153 priv->dlc = osmo_fr_dlc_alloc(privb->link, dlci);
154 if (!priv->dlc) {
155 nsvc->priv = NULL;
156 talloc_free(priv);
157 return NULL;
158 }
159
160 priv->dlc->rx_cb_data = nsvc;
161 priv->dlc->rx_cb = fr_dlci_rx_cb;
162
163 return priv;
164}
165
166int gprs_ns2_find_vc_by_dlci(struct gprs_ns2_vc_bind *bind,
167 uint16_t dlci,
168 struct gprs_ns2_vc **result)
169{
170 struct gprs_ns2_vc *nsvc;
171 struct priv_vc *vcpriv;
172
173 if (!result)
174 return -EINVAL;
175
176 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
177 vcpriv = nsvc->priv;
178 if (vcpriv->dlci != dlci) {
179 *result = nsvc;
180 return 0;
181 }
182 }
183
184 return 1;
185}
186
187/* PDU from the network interface towards the fr layer (upwards) */
188static int handle_netif_read(struct osmo_fd *bfd)
189{
190 struct gprs_ns2_vc_bind *bind = bfd->data;
191 struct priv_bind *priv = bind->priv;
192 struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "Gb/NS/FR/GRE Rx");
193 int rc = 0;
194
195 if (!msg)
196 return -ENOMEM;
197
198 rc = read(bfd->fd, msg->data, NS_ALLOC_SIZE);
199 if (rc < 0) {
200 LOGP(DLNS, LOGL_ERROR, "recv error %s during NS-FR-GRE recv\n",
201 strerror(errno));
202 goto out_err;
203 } else if (rc == 0) {
204 goto out_err;
205 }
206
207 msgb_put(msg, rc);
208 msg->dst = priv->link;
209 return osmo_fr_rx(msg);
210
211out_err:
212 msgb_free(msg);
213 return rc;
214}
215
216/* PDU from the frame relay towards the NS-VC (upwards) */
217static int fr_dlci_rx_cb(void *cb_data, struct msgb *msg)
218{
219 int rc;
220 struct gprs_ns2_vc *nsvc = cb_data;
221
222 rc = ns2_recv_vc(nsvc, msg);
223
224 return rc;
225}
226
227static int handle_netif_write(struct osmo_fd *bfd)
228{
229 /* FIXME */
230 return -EIO;
231}
232
233static int fr_fd_cb(struct osmo_fd *bfd, unsigned int what)
234{
235 int rc = 0;
236
237 if (what & OSMO_FD_READ)
238 rc = handle_netif_read(bfd);
239 if (what & OSMO_FD_WRITE)
240 rc = handle_netif_write(bfd);
241
242 return rc;
243}
244
245/*! determine if given bind is for FR-GRE encapsulation. */
246int gprs_ns2_is_fr_bind(struct gprs_ns2_vc_bind *bind)
247{
248 return (bind->driver == &vc_driver_fr);
249}
250
251/* PDU from the NS-VC towards the frame relay layer (downwards) */
252static int fr_vc_sendmsg(struct gprs_ns2_vc *nsvc, struct msgb *msg)
253{
254 struct priv_vc *vcpriv = nsvc->priv;
255
256 msg->dst = vcpriv->dlc;
257 return osmo_fr_tx_dlc(msg);
258}
259
260/* PDU from the frame relay layer towards the network interface (downwards) */
261int fr_tx_cb(void *data, struct msgb *msg)
262{
263 struct gprs_ns2_vc_bind *bind = data;
264 struct priv_bind *priv = bind->priv;
265 int rc;
266
267 /* FIXME half writes */
268 rc = write(priv->fd.fd, msg->data, msg->len);
269 msgb_free(msg);
270
271 return rc;
272}
273
274static int devname2ifindex(const char *ifname)
275{
276 struct ifreq ifr;
277 int sk, rc;
278
279 sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
280 if (sk < 0)
281 return sk;
282
283
284 memset(&ifr, 0, sizeof(ifr));
285 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
286 ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0;
287
288 rc = ioctl(sk, SIOCGIFINDEX, &ifr);
289 close(sk);
290 if (rc < 0)
291 return rc;
292
293 return ifr.ifr_ifindex;
294}
295
296static int open_socket(const char *ifname)
297{
298 struct sockaddr_ll addr;
299 int ifindex;
300 int fd, rc, on = 1;
301
302 ifindex = devname2ifindex(ifname);
303 if (ifindex < 0) {
304 LOGP(DLNS, LOGL_ERROR, "Can not get interface index for interface %s\n", ifname);
305 return ifindex;
306 }
307
308 memset(&addr, 0, sizeof(addr));
309 addr.sll_family = AF_PACKET;
310 addr.sll_protocol = htons(ETH_P_ALL);
311 addr.sll_ifindex = ifindex;
312
313 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
314 if (fd < 0) {
315 LOGP(DLNS, LOGL_ERROR, "Can not get socket for interface %s. Are you root or have CAP_RAW_SOCKET?\n", ifname);
316 return fd;
317 }
318
319 if (ioctl(fd, FIONBIO, (unsigned char *)&on) < 0) {
320 LOGP(DLGLOBAL, LOGL_ERROR,
321 "cannot set this socket unblocking: %s\n",
322 strerror(errno));
323 close(fd);
Harald Welteb6b82da2020-11-26 09:30:37 +0100324 return -EINVAL;
Alexander Couzens841817e2020-11-19 00:41:29 +0100325 }
326
327 rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
328 if (rc < 0) {
329 LOGP(DLNS, LOGL_ERROR, "Can not bind for interface %s\n", ifname);
330 close(fd);
331 return rc;
332 }
333
334 return fd;
335}
336
337/*! Create a new bind for NS over FR.
338 * \param[in] nsi NS instance in which to create the bind
339 * \param[in] netif Network interface to bind to
340 * \param[in] fr_network
341 * \param[in] fr_role
342 * \param[out] result pointer to created bind
343 * \return 0 on success; negative on error */
344int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi,
345 const char *netif,
346 struct osmo_fr_network *fr_network,
347 enum osmo_fr_role fr_role,
348 struct gprs_ns2_vc_bind **result)
349{
350 struct gprs_ns2_vc_bind *bind = talloc_zero(nsi, struct gprs_ns2_vc_bind);
351 struct priv_bind *priv;
352 struct osmo_fr_link *fr_link;
353 int rc = 0;
354
355 if (!bind)
356 return -ENOSPC;
357
358 bind->driver = &vc_driver_fr;
Alexander Couzensaac90162020-11-19 02:44:04 +0100359 bind->ll = GPRS_NS2_LL_FR;
Alexander Couzens841817e2020-11-19 00:41:29 +0100360 bind->send_vc = fr_vc_sendmsg;
361 bind->free_vc = free_vc;
362 bind->dump_vty = dump_vty;
363 bind->nsi = nsi;
364 priv = bind->priv = talloc_zero(bind, struct priv_bind);
365 if (!priv) {
366 rc = -ENOSPC;
367 goto err_bind;
368 }
369
370 priv->fd.cb = fr_fd_cb;
371 priv->fd.data = bind;
372 if (strlen(netif) > IF_NAMESIZE) {
373 rc = -EINVAL;
374 goto err_priv;
375 }
376 strncpy(priv->netif, netif, sizeof(priv->netif));
377
378 ns2_vty_bind_apply(bind);
379 if (result)
380 *result = bind;
381
382 /* FIXME: move fd handling into socket.c */
383 fr_link = osmo_fr_link_alloc(fr_network, fr_role, netif);
384 if (!fr_link) {
385 rc = -EINVAL;
386 goto err_priv;
387 }
388
389 fr_link->tx_cb = fr_tx_cb;
390 fr_link->tx_cb_data = bind;
391 priv->link = fr_link;
392 priv->fd.fd = rc = open_socket(netif);
393 if (rc < 0)
394 goto err_fr;
395
396 priv->fd.when = OSMO_FD_READ;
397 rc = osmo_fd_register(&priv->fd);
398 if (rc < 0)
399 goto err_fd;
400
401 INIT_LLIST_HEAD(&bind->nsvc);
402 llist_add(&bind->list, &nsi->binding);
403
404 return rc;
405
406err_fd:
407 close(priv->fd.fd);
408err_fr:
409 osmo_fr_link_free(fr_link);
410err_priv:
411 talloc_free(priv);
412err_bind:
413 talloc_free(bind);
414
415 return rc;
416}
417
418/*! Return the network interface of the bind
419 * \param[in] bind The bind
420 * \return the network interface
421 */
422const char *gprs_ns2_fr_bind_netif(struct gprs_ns2_vc_bind *bind)
423{
424 struct priv_bind *priv;
425
426 if (bind->driver != &vc_driver_fr)
427 return NULL;
428
429 priv = bind->priv;
430 return priv->netif;
431}
432
433/*! Find NS bind for a given network interface
434 * \param[in] nsi NS instance
435 * \param[in] netif the network interface to search for
436 * \return the bind or NULL if not found
437 */
438struct gprs_ns2_vc_bind *gprs_ns2_fr_bind_by_netif(
439 struct gprs_ns2_inst *nsi,
440 const char *netif)
441{
442 struct gprs_ns2_vc_bind *bind;
443 const char *_netif;
444
445 OSMO_ASSERT(nsi);
446 OSMO_ASSERT(netif);
447
448 llist_for_each_entry(bind, &nsi->binding, list) {
449 if (!gprs_ns2_is_fr_bind(bind))
450 continue;
451
452 _netif = gprs_ns2_fr_bind_netif(bind);
453 if (!strncmp(_netif, netif, IF_NAMESIZE))
454 return bind;
455 }
456
457 return NULL;
458}
459
460/*! Create, connect and activate a new FR-based NS-VC
461 * \param[in] bind bind in which the new NS-VC is to be created
462 * \param[in] nsei NSEI of the NS Entity in which the NS-VC is to be created
463 * \param[in] dlci Data Link connection identifier
464 * \return pointer to newly-allocated, connected and activated NS-VC; NULL on error */
465struct gprs_ns2_vc *gprs_ns2_fr_connect(struct gprs_ns2_vc_bind *bind,
466 uint16_t nsei,
467 uint16_t nsvci,
468 uint16_t dlci)
469{
470 bool created_nse = false;
471 struct gprs_ns2_vc *nsvc = NULL;
472 struct priv_vc *priv = NULL;
473 struct gprs_ns2_nse *nse = gprs_ns2_nse_by_nsei(bind->nsi, nsei);
474 if (!nse) {
Alexander Couzensaac90162020-11-19 02:44:04 +0100475 nse = gprs_ns2_create_nse(bind->nsi, nsei, GPRS_NS2_LL_FR);
Alexander Couzens841817e2020-11-19 00:41:29 +0100476 if (!nse)
477 return NULL;
478 created_nse = true;
479 }
480
481 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
482 if (nsvc) {
483 goto err_nse;
484 }
485
486 nsvc = ns2_vc_alloc(bind, nse, true);
487 if (!nsvc)
488 goto err_nse;
489
490 nsvc->priv = priv = fr_alloc_vc(bind, nsvc, dlci);
491 if (!priv)
492 goto err;
493
494 nsvc->nsvci = nsvci;
495 nsvc->nsvci_is_valid = true;
Alexander Couzens841817e2020-11-19 00:41:29 +0100496
497 gprs_ns2_vc_fsm_start(nsvc);
498
499 return nsvc;
500
501err:
502 gprs_ns2_free_nsvc(nsvc);
503err_nse:
504 if (created_nse)
505 gprs_ns2_free_nse(nse);
506
507 return NULL;
508}
509
510/*! Return the nsvc by dlci.
511 * \param[in] bind
512 * \param[in] dlci Data Link connection identifier
513 * \return the nsvc or NULL if not found
514 */
515struct gprs_ns2_vc *gprs_ns2_fr_nsvc_by_dlci(struct gprs_ns2_vc_bind *bind,
516 uint16_t dlci)
517{
518 struct gprs_ns2_vc *nsvc;
519 struct priv_vc *vcpriv;
520
521 llist_for_each_entry(nsvc, &bind->nsvc, blist) {
522 vcpriv = nsvc->priv;
523
524 if (dlci == vcpriv->dlci)
525 return nsvc;
526 }
527
528 return NULL;
529}
530
531/*! Return the dlci of the nsvc
532 * \param[in] nsvc
533 * \return the dlci or 0 on error. 0 is not a valid dlci.
534 */
535uint16_t gprs_ns2_fr_nsvc_dlci(struct gprs_ns2_vc *nsvc)
536{
537 struct priv_vc *vcpriv;
538
539 if (!nsvc->bind)
540 return 0;
541
542 if (nsvc->bind->driver != &vc_driver_fr)
543 return 0;
544
545 vcpriv = nsvc->priv;
546 return vcpriv->dlci;
547}