blob: 65fe88ee24ad542c04918f41d43155278b8f048c [file] [log] [blame]
Alexander Couzens6a161492020-07-12 13:45:50 +02001/*! \file gprs_ns2_vty.c
2 * VTY interface for our GPRS Networks Service (NS) implementation. */
3
4/* (C) 2009-2014 by Harald Welte <laforge@gnumonks.org>
5 * (C) 2016-2017 by sysmocom - s.f.m.c. GmbH
6 * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
7 * Author: Alexander Couzens <lynxis@fe80.eu>
8 *
9 * All Rights Reserved
10 *
11 * SPDX-License-Identifier: GPL-2.0+
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 *
26 */
27
28#include <stdlib.h>
29#include <unistd.h>
30#include <errno.h>
31#include <stdint.h>
32
33#include <arpa/inet.h>
34
35#include <osmocom/core/msgb.h>
36#include <osmocom/core/byteswap.h>
37#include <osmocom/core/talloc.h>
38#include <osmocom/core/select.h>
39#include <osmocom/core/rate_ctr.h>
40#include <osmocom/core/socket.h>
41#include <osmocom/core/sockaddr_str.h>
42#include <osmocom/core/linuxlist.h>
43#include <osmocom/core/socket.h>
44#include <osmocom/gprs/gprs_ns2.h>
45#include <osmocom/gsm/tlv.h>
46#include <osmocom/vty/vty.h>
47#include <osmocom/vty/command.h>
48#include <osmocom/vty/logging.h>
49#include <osmocom/vty/telnet_interface.h>
50#include <osmocom/vty/misc.h>
51
52#include "gprs_ns2_internal.h"
53
54struct ns2_vty_priv {
55 /* global listen */
56 struct osmo_sockaddr_str udp;
57 struct osmo_sockaddr_str frgreaddr;
58 int dscp;
59 enum gprs_ns2_vc_mode vc_mode;
60 /* force vc mode if another configuration forces
61 * the vc mode. E.g. SNS configuration */
62 bool force_vc_mode;
Daniel Willmann4fb27a82020-09-25 15:39:46 +020063 const char *force_vc_mode_reason;
Alexander Couzens6a161492020-07-12 13:45:50 +020064 bool frgre;
65
66 struct llist_head vtyvc;
67};
68
69struct ns2_vty_vc {
70 struct llist_head list;
71
72 struct osmo_sockaddr_str remote;
73 enum gprs_ns_ll ll;
74
75 /* old vty code doesnt support multiple NSVCI per NSEI */
76 uint16_t nsei;
77 uint16_t nsvci;
78 uint16_t frdlci;
79
80 bool remote_end_is_sgsn;
81 bool configured;
82};
83
84static struct gprs_ns2_inst *vty_nsi = NULL;
85static struct ns2_vty_priv priv;
86
87/* FIXME: this should go to some common file as it is copied
88 * in vty_interface.c of the BSC */
89static const struct value_string gprs_ns_timer_strs[] = {
90 { 0, "tns-block" },
91 { 1, "tns-block-retries" },
92 { 2, "tns-reset" },
93 { 3, "tns-reset-retries" },
94 { 4, "tns-test" },
95 { 5, "tns-alive" },
96 { 6, "tns-alive-retries" },
97 { 7, "tsns-prov" },
98 { 0, NULL }
99};
100
101static void log_set_nsvc_filter(struct log_target *target,
102 struct gprs_ns2_vc *nsvc)
103{
104 if (nsvc) {
105 target->filter_map |= (1 << LOG_FLT_GB_NSVC);
106 target->filter_data[LOG_FLT_GB_NSVC] = nsvc;
107 } else if (target->filter_data[LOG_FLT_GB_NSVC]) {
108 target->filter_map = ~(1 << LOG_FLT_GB_NSVC);
109 target->filter_data[LOG_FLT_GB_NSVC] = NULL;
110 }
111}
112
113static struct cmd_node ns_node = {
114 L_NS_NODE,
115 "%s(config-ns)# ",
116 1,
117};
118
119static struct ns2_vty_vc *vtyvc_alloc(uint16_t nsei) {
120 struct ns2_vty_vc *vtyvc = talloc_zero(vty_nsi, struct ns2_vty_vc);
121 if (!vtyvc)
122 return vtyvc;
123
124 vtyvc->nsei = nsei;
125
126 llist_add(&vtyvc->list, &priv.vtyvc);
127
128 return vtyvc;
129}
130
131static void ns2_vc_free(struct ns2_vty_vc *vtyvc) {
132 if (!vtyvc)
133 return;
134
135 llist_del(&vtyvc->list);
136 talloc_free(vtyvc);
137}
138
139static struct ns2_vty_vc *vtyvc_by_nsei(uint16_t nsei, bool alloc_missing) {
140 struct ns2_vty_vc *vtyvc;
Alexander Couzens1f0625f2020-09-23 18:22:20 +0200141
Alexander Couzens6a161492020-07-12 13:45:50 +0200142 llist_for_each_entry(vtyvc, &priv.vtyvc, list) {
143 if (vtyvc->nsei == nsei)
144 return vtyvc;
145 }
146
Alexander Couzens1f0625f2020-09-23 18:22:20 +0200147 if (!alloc_missing)
148 return NULL;
Alexander Couzens6a161492020-07-12 13:45:50 +0200149
Alexander Couzens1f0625f2020-09-23 18:22:20 +0200150 vtyvc = vtyvc_alloc(nsei);
151 if (!vtyvc)
152 return vtyvc;
Alexander Couzens6a161492020-07-12 13:45:50 +0200153
Alexander Couzens1f0625f2020-09-23 18:22:20 +0200154 vtyvc->nsei = nsei;
155 return vtyvc;
Alexander Couzens6a161492020-07-12 13:45:50 +0200156}
157
158static int config_write_ns(struct vty *vty)
159{
160 struct ns2_vty_vc *vtyvc;
161 unsigned int i;
162 struct osmo_sockaddr_str sockstr;
163
164 vty_out(vty, "ns%s", VTY_NEWLINE);
165
166 /* global configuration must be written first, as some of it may be
167 * relevant when creating the NSE/NSVC later below */
168
169 vty_out(vty, " encapsulation framerelay-gre enabled %u%s",
170 priv.frgre ? 1 : 0, VTY_NEWLINE);
171
172 if (priv.frgre) {
173 if (strlen(priv.frgreaddr.ip)) {
174 vty_out(vty, " encapsulation framerelay-gre local-ip %s%s",
175 sockstr.ip, VTY_NEWLINE);
176 }
177 } else {
178 if (strlen(priv.udp.ip)) {
179 vty_out(vty, " encapsulation udp local-ip %s%s",
180 priv.udp.ip, VTY_NEWLINE);
181 }
182
183 if (priv.udp.port)
184 vty_out(vty, " encapsulation udp local-port %u%s",
185 priv.udp.port, VTY_NEWLINE);
186 }
187
188 if (priv.dscp)
189 vty_out(vty, " encapsulation udp dscp %d%s",
190 priv.dscp, VTY_NEWLINE);
191
192 vty_out(vty, " encapsulation udp use-reset-block-unblock %s%s",
193 priv.vc_mode == NS2_VC_MODE_BLOCKRESET ? "enabled" : "disabled", VTY_NEWLINE);
194
195 llist_for_each_entry(vtyvc, &priv.vtyvc, list) {
196 vty_out(vty, " nse %u nsvci %u%s",
197 vtyvc->nsei, vtyvc->nsvci, VTY_NEWLINE);
198
199 vty_out(vty, " nse %u remote-role %s%s",
200 vtyvc->nsei, vtyvc->remote_end_is_sgsn ? "sgsn" : "bss",
201 VTY_NEWLINE);
202
203 switch (vtyvc->ll) {
204 case GPRS_NS_LL_UDP:
205 vty_out(vty, " nse %u encapsulation udp%s", vtyvc->nsei, VTY_NEWLINE);
206 vty_out(vty, " nse %u remote-ip %s%s",
207 vtyvc->nsei,
208 vtyvc->remote.ip,
209 VTY_NEWLINE);
210 vty_out(vty, " nse %u remote-port %u%s",
211 vtyvc->nsei, vtyvc->remote.port,
212 VTY_NEWLINE);
213 break;
214 case GPRS_NS_LL_FR_GRE:
215 vty_out(vty, " nse %u encapsulation framerelay-gre%s",
216 vtyvc->nsei, VTY_NEWLINE);
217 vty_out(vty, " nse %u remote-ip %s%s",
218 vtyvc->nsei,
219 vtyvc->remote.ip,
220 VTY_NEWLINE);
221 vty_out(vty, " nse %u fr-dlci %u%s",
222 vtyvc->nsei, vtyvc->frdlci,
223 VTY_NEWLINE);
224 break;
225 default:
226 break;
227 }
228 }
229
230 for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++)
231 vty_out(vty, " timer %s %u%s",
232 get_value_string(gprs_ns_timer_strs, i),
233 vty_nsi->timeout[i], VTY_NEWLINE);
234
235 return CMD_SUCCESS;
236}
237
238DEFUN(cfg_ns, cfg_ns_cmd,
239 "ns",
240 "Configure the GPRS Network Service")
241{
242 vty->node = L_NS_NODE;
243 return CMD_SUCCESS;
244}
245
246static void dump_nsvc(struct vty *vty, struct gprs_ns2_vc *nsvc, bool stats)
247{
Daniel Willmanned1fa012020-11-06 15:40:27 +0100248 vty_out(vty, " %s%s", gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +0200249
250 if (stats) {
251 vty_out_rate_ctr_group(vty, " ", nsvc->ctrg);
252 vty_out_stat_item_group(vty, " ", nsvc->statg);
253 }
254}
255
256static void dump_nse(struct vty *vty, const struct gprs_ns2_nse *nse, bool stats, bool persistent_only)
257{
258 struct gprs_ns2_vc *nsvc;
259
260 vty_out(vty, "NSEI %5u%s",
261 nse->nsei, VTY_NEWLINE);
262
263 gprs_ns2_sns_dump_vty(vty, nse, stats);
264 llist_for_each_entry(nsvc, &nse->nsvc, list) {
265 if (persistent_only) {
266 if (nsvc->persistent)
267 dump_nsvc(vty, nsvc, stats);
268 } else {
269 dump_nsvc(vty, nsvc, stats);
270 }
271 }
272}
273
Alexander Couzens22f34712020-10-02 02:34:39 +0200274static void dump_bind(struct vty *vty, const struct gprs_ns2_vc_bind *bind, bool stats)
275{
276 if (bind->dump_vty)
277 bind->dump_vty(bind, vty, stats);
278}
279
Alexander Couzens6a161492020-07-12 13:45:50 +0200280static void dump_ns(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats, bool persistent_only)
281{
Alexander Couzens22f34712020-10-02 02:34:39 +0200282 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6a161492020-07-12 13:45:50 +0200283 struct gprs_ns2_nse *nse;
284
Alexander Couzens22f34712020-10-02 02:34:39 +0200285 llist_for_each_entry(bind, &nsi->binding, list) {
286 dump_bind(vty, bind, stats);
287 }
288
Alexander Couzens6a161492020-07-12 13:45:50 +0200289 llist_for_each_entry(nse, &nsi->nse, list) {
290 dump_nse(vty, nse, stats, persistent_only);
Alexander Couzens6a161492020-07-12 13:45:50 +0200291 }
292
293}
294
295DEFUN(show_ns, show_ns_cmd, "show ns",
296 SHOW_STR "Display information about the NS protocol")
297{
298 dump_ns(vty, vty_nsi, false, false);
299 return CMD_SUCCESS;
300}
301
302DEFUN(show_ns_stats, show_ns_stats_cmd, "show ns stats",
303 SHOW_STR
304 "Display information about the NS protocol\n"
305 "Include statistics\n")
306{
307 dump_ns(vty, vty_nsi, true, false);
308 return CMD_SUCCESS;
309}
310
311DEFUN(show_ns_pers, show_ns_pers_cmd, "show ns persistent",
312 SHOW_STR
313 "Display information about the NS protocol\n"
314 "Show only persistent NS\n")
315{
316 dump_ns(vty, vty_nsi, true, true);
317 return CMD_SUCCESS;
318}
319
320DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]",
321 SHOW_STR "Display information about the NS protocol\n"
322 "Select one NSE by its NSE Identifier\n"
323 "Select one NSE by its NS-VC Identifier\n"
324 "The Identifier of selected type\n"
325 "Include Statistics\n")
326{
327 struct gprs_ns2_inst *nsi = vty_nsi;
328 struct gprs_ns2_nse *nse;
329 struct gprs_ns2_vc *nsvc;
330 uint16_t id = atoi(argv[1]);
331 bool show_stats = false;
332
333 if (argc >= 3)
334 show_stats = true;
335
336 if (!strcmp(argv[0], "nsei")) {
337 nse = gprs_ns2_nse_by_nsei(nsi, id);
338 if (!nse) {
339 return CMD_WARNING;
340 }
341
342 dump_nse(vty, nse, show_stats, false);
343 } else {
344 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
345
346 if (!nsvc) {
347 vty_out(vty, "No such NS Entity%s", VTY_NEWLINE);
348 return CMD_WARNING;
349 }
350
351 dump_nsvc(vty, nsvc, show_stats);
352 }
353
354 return CMD_SUCCESS;
355}
356
357#define NSE_CMD_STR "Persistent NS Entity\n" "NS Entity ID (NSEI)\n"
358
359DEFUN(cfg_nse_nsvc, cfg_nse_nsvci_cmd,
360 "nse <0-65535> nsvci <0-65535>",
361 NSE_CMD_STR
362 "NS Virtual Connection\n"
363 "NS Virtual Connection ID (NSVCI)\n"
364 )
365{
366 struct ns2_vty_vc *vtyvc;
367
368 uint16_t nsei = atoi(argv[0]);
369 uint16_t nsvci = atoi(argv[1]);
370
371 vtyvc = vtyvc_by_nsei(nsei, true);
372 if (!vtyvc) {
373 vty_out(vty, "Can not allocate space %s", VTY_NEWLINE);
374 return CMD_WARNING;
375 }
376
377 vtyvc->nsvci = nsvci;
378
379 return CMD_SUCCESS;
380}
381
382DEFUN(cfg_nse_remoteip, cfg_nse_remoteip_cmd,
383 "nse <0-65535> remote-ip " VTY_IPV46_CMD,
384 NSE_CMD_STR
385 "Remote IP Address\n"
Alexander Couzensc82c40a2020-09-24 05:55:48 +0200386 "Remote IPv4 Address\n"
387 "Remote IPv6 Address\n")
Alexander Couzens6a161492020-07-12 13:45:50 +0200388{
389 uint16_t nsei = atoi(argv[0]);
390 struct ns2_vty_vc *vtyvc;
391
392 vtyvc = vtyvc_by_nsei(nsei, true);
393 if (!vtyvc) {
394 vty_out(vty, "Can not allocate space %s", VTY_NEWLINE);
395 return CMD_WARNING;
396 }
397
398 osmo_sockaddr_str_from_str2(&vtyvc->remote, argv[1]);
399
400 return CMD_SUCCESS;
401}
402
403DEFUN(cfg_nse_remoteport, cfg_nse_remoteport_cmd,
404 "nse <0-65535> remote-port <0-65535>",
405 NSE_CMD_STR
406 "Remote UDP Port\n"
407 "Remote UDP Port Number\n")
408{
409 uint16_t nsei = atoi(argv[0]);
410 uint16_t port = atoi(argv[1]);
411 struct ns2_vty_vc *vtyvc;
412
413 vtyvc = vtyvc_by_nsei(nsei, true);
414 if (!vtyvc) {
415 vty_out(vty, "Can not allocate space %s", VTY_NEWLINE);
416 return CMD_WARNING;
417 }
418
419 vtyvc->remote.port = port;
420
421 return CMD_SUCCESS;
422}
423
424DEFUN(cfg_nse_fr_dlci, cfg_nse_fr_dlci_cmd,
425 "nse <0-65535> fr-dlci <16-1007>",
426 NSE_CMD_STR
427 "Frame Relay DLCI\n"
428 "Frame Relay DLCI Number\n")
429{
430 uint16_t nsei = atoi(argv[0]);
431 uint16_t dlci = atoi(argv[1]);
432 struct ns2_vty_vc *vtyvc;
433
434 vtyvc = vtyvc_by_nsei(nsei, true);
435 if (!vtyvc) {
436 vty_out(vty, "Can not allocate space %s", VTY_NEWLINE);
437 return CMD_WARNING;
438 }
439
440 if (vtyvc->ll != GPRS_NS_LL_FR_GRE) {
441 vty_out(vty, "Warning: seting FR DLCI on non-FR NSE%s",
442 VTY_NEWLINE);
443 }
444
445 vtyvc->frdlci = dlci;
446
447 return CMD_SUCCESS;
448}
449
450DEFUN(cfg_nse_encaps, cfg_nse_encaps_cmd,
451 "nse <0-65535> encapsulation (udp|framerelay-gre)",
452 NSE_CMD_STR
453 "Encapsulation for NS\n"
454 "UDP/IP Encapsulation\n" "Frame-Relay/GRE/IP Encapsulation\n")
455{
456 uint16_t nsei = atoi(argv[0]);
457 struct ns2_vty_vc *vtyvc;
458
459 vtyvc = vtyvc_by_nsei(nsei, true);
460 if (!vtyvc) {
461 vty_out(vty, "Can not allocate space %s", VTY_NEWLINE);
462 return CMD_WARNING;
463 }
464
465 if (!strcmp(argv[1], "udp"))
466 vtyvc->ll = GPRS_NS_LL_UDP;
467 else
468 vtyvc->ll = GPRS_NS_LL_FR_GRE;
469
470 return CMD_SUCCESS;
471}
472
473DEFUN(cfg_nse_remoterole, cfg_nse_remoterole_cmd,
474 "nse <0-65535> remote-role (sgsn|bss)",
475 NSE_CMD_STR
476 "Remote NSE Role\n"
477 "Remote Peer is SGSN\n"
478 "Remote Peer is BSS\n")
479{
480 uint16_t nsei = atoi(argv[0]);
481 struct ns2_vty_vc *vtyvc;
482
483 vtyvc = vtyvc_by_nsei(nsei, true);
484 if (!vtyvc) {
485 vty_out(vty, "Can not allocate space %s", VTY_NEWLINE);
486 return CMD_WARNING;
487 }
488
489 if (!strcmp(argv[1], "sgsn"))
490 vtyvc->remote_end_is_sgsn = 1;
491 else
492 vtyvc->remote_end_is_sgsn = 0;
493
494 return CMD_SUCCESS;
495}
496
497DEFUN(cfg_no_nse, cfg_no_nse_cmd,
498 "no nse <0-65535>",
499 "Delete Persistent NS Entity\n"
500 "Delete " NSE_CMD_STR)
501{
502 uint16_t nsei = atoi(argv[0]);
503 struct ns2_vty_vc *vtyvc;
504
505 vtyvc = vtyvc_by_nsei(nsei, false);
506 if (!vtyvc) {
507 vty_out(vty, "The NSE %d does not exists.%s", nsei, VTY_NEWLINE);
508 return CMD_WARNING;
509 }
510
511 ns2_vc_free(vtyvc);
512
513 return CMD_SUCCESS;
514}
515
516DEFUN(cfg_ns_timer, cfg_ns_timer_cmd,
517 "timer " NS_TIMERS " <0-65535>",
518 "Network Service Timer\n"
519 NS_TIMERS_HELP "Timer Value\n")
520{
521 int idx = get_string_value(gprs_ns_timer_strs, argv[0]);
522 int val = atoi(argv[1]);
523
524 if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout))
525 return CMD_WARNING;
526
527 vty_nsi->timeout[idx] = val;
528
529 return CMD_SUCCESS;
530}
531
532#define ENCAPS_STR "NS encapsulation options\n"
533
534DEFUN(cfg_nsip_local_ip, cfg_nsip_local_ip_cmd,
535 "encapsulation udp local-ip " VTY_IPV46_CMD,
536 ENCAPS_STR "NS over UDP Encapsulation\n"
537 "Set the IP address on which we listen for NS/UDP\n"
Alexander Couzensc82c40a2020-09-24 05:55:48 +0200538 "IPv4 Address\n"
539 "IPv6 Address\n")
Alexander Couzens6a161492020-07-12 13:45:50 +0200540{
541 osmo_sockaddr_str_from_str2(&priv.udp, argv[0]);
542
543 return CMD_SUCCESS;
544}
545
546DEFUN(cfg_nsip_local_port, cfg_nsip_local_port_cmd,
547 "encapsulation udp local-port <0-65535>",
548 ENCAPS_STR "NS over UDP Encapsulation\n"
549 "Set the UDP port on which we listen for NS/UDP\n"
550 "UDP port number\n")
551{
552 unsigned int port = atoi(argv[0]);
553
554 priv.udp.port = port;
555
556 return CMD_SUCCESS;
557}
558
559DEFUN(cfg_nsip_dscp, cfg_nsip_dscp_cmd,
560 "encapsulation udp dscp <0-255>",
561 ENCAPS_STR "NS over UDP Encapsulation\n"
562 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
563{
564 int dscp = atoi(argv[0]);
565 struct gprs_ns2_vc_bind *bind;
566
567 priv.dscp = dscp;
568
569 llist_for_each_entry(bind, &vty_nsi->binding, list) {
570 if (gprs_ns2_is_ip_bind(bind))
571 gprs_ns2_ip_bind_set_dscp(bind, dscp);
572 }
573
574 return CMD_SUCCESS;
575}
576
577DEFUN(cfg_nsip_res_block_unblock, cfg_nsip_res_block_unblock_cmd,
578 "encapsulation udp use-reset-block-unblock (enabled|disabled)",
579 ENCAPS_STR "NS over UDP Encapsulation\n"
580 "Use NS-{RESET,BLOCK,UNBLOCK} procedures in violation of 3GPP TS 48.016\n"
581 "Enable NS-{RESET,BLOCK,UNBLOCK}\n"
582 "Disable NS-{RESET,BLOCK,UNBLOCK}\n")
583{
584 enum gprs_ns2_vc_mode vc_mode;
585 struct gprs_ns2_vc_bind *bind;
586
587 if (!strcmp(argv[0], "enabled"))
588 vc_mode = NS2_VC_MODE_BLOCKRESET;
589 else
590 vc_mode = NS2_VC_MODE_ALIVE;
591
592 if (priv.force_vc_mode) {
593 if (priv.vc_mode != vc_mode)
594 {
595 vty_out(vty, "Ignoring use-reset-block because it's already set by %s.%s",
596 priv.force_vc_mode_reason, VTY_NEWLINE);
597 return CMD_WARNING;
598 }
599
600 return CMD_SUCCESS;
601 }
602
603 priv.vc_mode = vc_mode;
604
605 llist_for_each_entry(bind, &vty_nsi->binding, list) {
606 gprs_ns2_bind_set_mode(bind, priv.vc_mode);
607 }
608
609 return CMD_SUCCESS;
610}
611
612DEFUN(cfg_frgre_local_ip, cfg_frgre_local_ip_cmd,
613 "encapsulation framerelay-gre local-ip " VTY_IPV46_CMD,
614 ENCAPS_STR "NS over Frame Relay over GRE Encapsulation\n"
615 "Set the IP address on which we listen for NS/FR/GRE\n"
Alexander Couzensc82c40a2020-09-24 05:55:48 +0200616 "IPv4 Address\n"
617 "IPv6 Address\n")
Alexander Couzens6a161492020-07-12 13:45:50 +0200618{
619 osmo_sockaddr_str_from_str2(&priv.frgreaddr, argv[0]);
620
621 return CMD_SUCCESS;
622}
623
624DEFUN(cfg_frgre_enable, cfg_frgre_enable_cmd,
625 "encapsulation framerelay-gre enabled (1|0)",
626 ENCAPS_STR "NS over Frame Relay over GRE Encapsulation\n"
627 "Enable or disable Frame Relay over GRE\n"
628 "Enable\n" "Disable\n")
629{
630 int enabled = atoi(argv[0]);
631
632 priv.frgre = enabled;
633
634 return CMD_SUCCESS;
635}
636
637/* TODO: allow vty to reset/block/unblock nsvc/nsei */
638
639/* TODO: add filter for NSEI as ns1 code does */
640/* TODO: add filter for single connection by description */
641DEFUN(logging_fltr_nsvc,
642 logging_fltr_nsvc_cmd,
643 "logging filter nsvc nsvci <0-65535>",
644 LOGGING_STR FILTER_STR
645 "Filter based on NS Virtual Connection\n"
646 "Identify NS-VC by NSVCI\n"
647 "Numeric identifier\n")
648{
649 struct log_target *tgt;
650 struct gprs_ns2_vc *nsvc;
651 uint16_t id = atoi(argv[1]);
652
653 log_tgt_mutex_lock();
654 tgt = osmo_log_vty2tgt(vty);
655 if (!tgt) {
656 log_tgt_mutex_unlock();
657 return CMD_WARNING;
658 }
659
660 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, id);
661 if (!nsvc) {
662 vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE);
663 log_tgt_mutex_unlock();
664 return CMD_WARNING;
665 }
666
667 log_set_nsvc_filter(tgt, nsvc);
668 log_tgt_mutex_unlock();
669 return CMD_SUCCESS;
670}
671
Alexander Couzens1fac6f72020-10-01 19:08:38 +0200672/**
673 * gprs_ns2_vty_init initialize the vty
674 * \param[inout] nsi
675 * \param[in] default_bind set the default address to bind to. Can be NULL.
676 * \return 0 on success
677 */
Vadim Yanitskiya07f25e2020-10-09 21:47:01 +0700678int gprs_ns2_vty_init(struct gprs_ns2_inst *nsi,
679 const struct osmo_sockaddr_str *default_bind)
Alexander Couzens6a161492020-07-12 13:45:50 +0200680{
681 static bool vty_elements_installed = false;
682
683 vty_nsi = nsi;
684 memset(&priv, 0, sizeof(struct ns2_vty_priv));
685 INIT_LLIST_HEAD(&priv.vtyvc);
686 priv.vc_mode = NS2_VC_MODE_BLOCKRESET;
Alexander Couzens1fac6f72020-10-01 19:08:38 +0200687 if (default_bind)
688 memcpy(&priv.udp, default_bind, sizeof(*default_bind));
Alexander Couzens6a161492020-07-12 13:45:50 +0200689
690 /* Regression test code may call this function repeatedly, so make sure
691 * that VTY elements are not duplicated, which would assert. */
692 if (vty_elements_installed)
693 return 0;
694 vty_elements_installed = true;
695
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +0700696 install_lib_element_ve(&show_ns_cmd);
697 install_lib_element_ve(&show_ns_stats_cmd);
698 install_lib_element_ve(&show_ns_pers_cmd);
699 install_lib_element_ve(&show_nse_cmd);
700 install_lib_element_ve(&logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +0200701
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +0700702 install_lib_element(CFG_LOG_NODE, &logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +0200703
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +0700704 install_lib_element(CONFIG_NODE, &cfg_ns_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +0200705 install_node(&ns_node, config_write_ns);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +0700706 install_lib_element(L_NS_NODE, &cfg_nse_nsvci_cmd);
707 install_lib_element(L_NS_NODE, &cfg_nse_remoteip_cmd);
708 install_lib_element(L_NS_NODE, &cfg_nse_remoteport_cmd);
709 install_lib_element(L_NS_NODE, &cfg_nse_fr_dlci_cmd);
710 install_lib_element(L_NS_NODE, &cfg_nse_encaps_cmd);
711 install_lib_element(L_NS_NODE, &cfg_nse_remoterole_cmd);
712 install_lib_element(L_NS_NODE, &cfg_no_nse_cmd);
713 install_lib_element(L_NS_NODE, &cfg_ns_timer_cmd);
714 install_lib_element(L_NS_NODE, &cfg_nsip_local_ip_cmd);
715 install_lib_element(L_NS_NODE, &cfg_nsip_local_port_cmd);
716 install_lib_element(L_NS_NODE, &cfg_nsip_dscp_cmd);
717 install_lib_element(L_NS_NODE, &cfg_nsip_res_block_unblock_cmd);
718 install_lib_element(L_NS_NODE, &cfg_frgre_enable_cmd);
719 install_lib_element(L_NS_NODE, &cfg_frgre_local_ip_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +0200720
721 /* TODO: nsvc/nsei command to reset states or reset/block/unblock nsei/nsvcs */
722
723 return 0;
724}
725
726/*!
727 * \brief gprs_ns2_vty_create parse the vty tree into ns nodes
728 * It has to be in different steps to ensure the bind is created before creating VCs.
729 * \return 0 on success
730 */
731int gprs_ns2_vty_create() {
732 struct ns2_vty_vc *vtyvc;
733 struct gprs_ns2_vc_bind *bind;
734 struct gprs_ns2_nse *nse;
735 struct gprs_ns2_vc *nsvc;
736 struct osmo_sockaddr sockaddr;
737
738 if (!vty_nsi)
739 return -1;
740
741 /* create binds, only support a single bind. either FR or UDP */
742 if (priv.frgre) {
743 /* TODO not yet supported !*/
744 return -1;
745 } else {
746 /* UDP */
747 osmo_sockaddr_str_to_sockaddr(&priv.udp, &sockaddr.u.sas);
Alexander Couzens477ffb02020-10-01 19:05:28 +0200748 if (gprs_ns2_ip_bind(vty_nsi, &sockaddr, priv.dscp, &bind)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200749 /* TODO: could not bind on the specific address */
750 return -1;
751 }
752 gprs_ns2_bind_set_mode(bind, priv.vc_mode);
753 }
754
755 /* create vcs */
756 llist_for_each_entry(vtyvc, &priv.vtyvc, list) {
757 if (strlen(vtyvc->remote.ip) == 0) {
758 /* Invalid IP for VC */
759 continue;
760 }
761
762 if (!vtyvc->remote.port) {
763 /* Invalid port for VC */
764 continue;
765 }
766
767 if (osmo_sockaddr_str_to_sockaddr(&vtyvc->remote, &sockaddr.u.sas)) {
768 /* Invalid sockaddr for VC */
769 continue;
770 }
771
772 nse = gprs_ns2_nse_by_nsei(vty_nsi, vtyvc->nsei);
773 if (!nse) {
774 nse = gprs_ns2_create_nse(vty_nsi, vtyvc->nsei);
775 if (!nse) {
776 /* Could not create NSE for VTY */
777 continue;
778 }
779 }
780 nse->persistent = true;
781
Alexander Couzensd745a0e2020-10-07 00:50:00 +0200782 nsvc = gprs_ns2_ip_connect(bind,
783 &sockaddr,
784 nse,
785 vtyvc->nsvci);
786 if (!nsvc) {
787 /* Could not create NSVC, connect failed */
788 continue;
Alexander Couzens6a161492020-07-12 13:45:50 +0200789 }
Alexander Couzensd745a0e2020-10-07 00:50:00 +0200790 nsvc->persistent = true;
Alexander Couzens6a161492020-07-12 13:45:50 +0200791 }
792
793
794 return 0;
795}
796
797/*!
798 * \brief ns2_vty_bind_apply will be called when a new bind is created to apply vty settings
799 * \param bind
800 * \return
801 */
802void ns2_vty_bind_apply(struct gprs_ns2_vc_bind *bind)
803{
804 gprs_ns2_bind_set_mode(bind, priv.vc_mode);
805}
806
807/*!
808 * \brief ns2_vty_force_vc_mode force a mode and prevents the vty from overwriting it.
809 * \param force if true mode and reason will be set. false to allow modification via vty.
810 * \param mode
811 * \param reason A description shown to the user when a vty command wants to change the mode.
812 */
Daniel Willmann4fb27a82020-09-25 15:39:46 +0200813void gprs_ns2_vty_force_vc_mode(bool force, enum gprs_ns2_vc_mode mode, const char *reason)
Alexander Couzens6a161492020-07-12 13:45:50 +0200814{
815 priv.force_vc_mode = force;
816
817 if (force) {
818 priv.vc_mode = mode;
819 priv.force_vc_mode_reason = reason;
820 }
821}