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