blob: 0a0a5d3589951dc2f697e8974a17aac0b54c2d04 [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
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01004/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
Alexander Couzens6a161492020-07-12 13:45:50 +02005 * Author: Alexander Couzens <lynxis@fe80.eu>
6 *
7 * All Rights Reserved
8 *
9 * SPDX-License-Identifier: GPL-2.0+
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 *
24 */
25
26#include <stdlib.h>
27#include <unistd.h>
28#include <errno.h>
29#include <stdint.h>
30
31#include <arpa/inet.h>
Alexander Couzens841817e2020-11-19 00:41:29 +010032#include <net/if.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020033
Alexander Couzens6a161492020-07-12 13:45:50 +020034#include <osmocom/core/byteswap.h>
Daniel Willmanndbab7142020-11-18 14:19:56 +010035#include <osmocom/core/fsm.h>
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010036#include <osmocom/core/linuxlist.h>
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010037#include <osmocom/core/msgb.h>
38#include <osmocom/core/rate_ctr.h>
39#include <osmocom/core/select.h>
40#include <osmocom/core/talloc.h>
41#include <osmocom/core/sockaddr_str.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020042#include <osmocom/core/socket.h>
Alexander Couzens841817e2020-11-19 00:41:29 +010043#include <osmocom/gprs/frame_relay.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020044#include <osmocom/gprs/gprs_ns2.h>
45#include <osmocom/gsm/tlv.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020046#include <osmocom/vty/command.h>
47#include <osmocom/vty/logging.h>
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010048#include <osmocom/vty/misc.h>
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010049#include <osmocom/vty/telnet_interface.h>
50#include <osmocom/vty/vty.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020051
52#include "gprs_ns2_internal.h"
53
Daniel Willmanncb3e9b52020-12-02 15:50:22 +010054#define SHOW_NS_STR "Display information about the NS protocol\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010055#define NSVCI_STR "NS Virtual Connection ID (NS-VCI)\n"
56#define DLCI_STR "Data Link connection identifier\n"
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010057
58static struct gprs_ns2_inst *vty_nsi = NULL;
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010059static struct osmo_fr_network *vty_fr_network = NULL;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010060static struct llist_head binds;
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010061
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010062struct vty_bind {
63 struct llist_head list;
64 const char *name;
65 enum gprs_ns2_ll ll;
66 int dscp;
67 bool accept_ipaccess;
68 bool accept_sns;
Alexander Couzensc4704762021-02-08 23:13:12 +010069 uint8_t ip_sns_sig_weight;
70 uint8_t ip_sns_data_weight;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010071};
72
73/* TODO: this should into osmo timer */
Alexander Couzens6a161492020-07-12 13:45:50 +020074static const struct value_string gprs_ns_timer_strs[] = {
75 { 0, "tns-block" },
76 { 1, "tns-block-retries" },
77 { 2, "tns-reset" },
78 { 3, "tns-reset-retries" },
79 { 4, "tns-test" },
80 { 5, "tns-alive" },
81 { 6, "tns-alive-retries" },
82 { 7, "tsns-prov" },
Harald Welte33c3c062020-12-16 11:59:19 +010083 { 8, "tsns-size-retries" },
84 { 9, "tsns-config-retries" },
Alexander Couzens6a161492020-07-12 13:45:50 +020085 { 0, NULL }
86};
87
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010088const struct value_string vty_fr_role_names[] = {
89 { FR_ROLE_USER_EQUIPMENT, "fr" },
90 { FR_ROLE_NETWORK_EQUIPMENT, "frnet" },
91 { 0, NULL }
92};
93
94const struct value_string vty_ll_names[] = {
95 { GPRS_NS2_LL_FR, "fr" },
96 { GPRS_NS2_LL_FR_GRE, "frgre" },
97 { GPRS_NS2_LL_UDP, "udp" },
98 { 0, NULL }
99};
100
101static struct vty_bind *vty_bind_by_name(const char *name)
Daniel Willmann751977b2020-12-02 18:59:44 +0100102{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100103 struct vty_bind *vbind;
104 llist_for_each_entry(vbind, &binds, list) {
Alexander Couzensb7921732021-02-12 03:08:42 +0100105 if (!strcmp(vbind->name, name))
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100106 return vbind;
Daniel Willmann751977b2020-12-02 18:59:44 +0100107 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100108 return NULL;
Daniel Willmann751977b2020-12-02 18:59:44 +0100109}
110
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100111static struct vty_bind *vty_bind_alloc(const char *name)
Alexander Couzens6a161492020-07-12 13:45:50 +0200112{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100113 struct vty_bind *vbind = talloc_zero(vty_nsi, struct vty_bind);
114 if (!vbind)
115 return NULL;
116
117 vbind->name = talloc_strdup(vty_nsi, name);
118 if (!vbind->name) {
119 talloc_free(vbind);
120 return NULL;
Alexander Couzens6a161492020-07-12 13:45:50 +0200121 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100122
Alexander Couzensc4704762021-02-08 23:13:12 +0100123 vbind->ip_sns_sig_weight = 1;
124 vbind->ip_sns_data_weight = 1;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100125 llist_add(&vbind->list, &binds);
126 return vbind;
127}
128
129static void vty_bind_free(struct vty_bind *vbind)
130{
131 if (!vbind)
132 return;
133
134 llist_del(&vbind->list);
Alexander Couzens3e2e4a02021-02-09 16:15:06 +0100135 talloc_free(vbind);
Alexander Couzens6a161492020-07-12 13:45:50 +0200136}
137
138static struct cmd_node ns_node = {
139 L_NS_NODE,
140 "%s(config-ns)# ",
141 1,
142};
143
Alexander Couzens6a161492020-07-12 13:45:50 +0200144DEFUN(cfg_ns, cfg_ns_cmd,
145 "ns",
146 "Configure the GPRS Network Service")
147{
148 vty->node = L_NS_NODE;
149 return CMD_SUCCESS;
150}
151
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100152DEFUN(cfg_ns_timer, cfg_ns_timer_cmd,
153 "timer " NS_TIMERS " <0-65535>",
154 "Network Service Timer\n"
155 NS_TIMERS_HELP "Timer Value\n")
156{
157 int idx = get_string_value(gprs_ns_timer_strs, argv[0]);
158 int val = atoi(argv[1]);
159
160 if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout))
161 return CMD_WARNING;
162
163 vty_nsi->timeout[idx] = val;
164
165 return CMD_SUCCESS;
166}
167
168DEFUN(cfg_ns_nsei, cfg_ns_nsei_cmd,
169 "nse <0-65535>",
170 "Persistent NS Entity\n"
171 "NS Entity ID (NSEI)\n"
172 )
173{
174 struct gprs_ns2_nse *nse;
175 uint16_t nsei = atoi(argv[0]);
176
177 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
178 if (!nse) {
179 nse = gprs_ns2_create_nse(vty_nsi, nsei, GPRS_NS2_LL_UNDEF, GPRS_NS2_DIALECT_UNDEF);
180 if (!nse) {
181 vty_out(vty, "Failed to create NSE!%s", VTY_NEWLINE);
182 return CMD_ERR_INCOMPLETE;
183 }
184 nse->persistent = true;
185 }
186
187 if (!nse->persistent) {
188 /* TODO: should the dynamic NSE removed? */
189 vty_out(vty, "A dynamic NSE with the specified NSEI already exists%s", VTY_NEWLINE);
190 return CMD_ERR_INCOMPLETE;
191 }
192
193 vty->node = L_NS_NSE_NODE;
194 vty->index = nse;
195
196 return CMD_SUCCESS;
197}
198
199DEFUN(cfg_no_ns_nsei, cfg_no_ns_nsei_cmd,
200 "no nse <0-65535>",
201 NO_STR
202 "Delete a Persistent NS Entity\n"
203 "NS Entity ID (NSEI)\n"
204 )
205{
206 struct gprs_ns2_nse *nse;
207 uint16_t nsei = atoi(argv[0]);
208
209 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
210 if (!nse) {
211 vty_out(vty, "Can not find NS Entity %s%s", argv[0], VTY_NEWLINE);
212 return CMD_ERR_NOTHING_TODO;
213 }
214
215 if (!nse->persistent) {
216 vty_out(vty, "Ignoring non-persistent NS Entity%s", VTY_NEWLINE);
217 return CMD_WARNING;
218 }
219
220 vty_out(vty, "Deleting NS Entity %u%s", nse->nsei, VTY_NEWLINE);
221 gprs_ns2_free_nse(nse);
222 return CMD_SUCCESS;
223}
224
225/* TODO: add fr/gre */
226DEFUN(cfg_ns_bind, cfg_ns_bind_cmd,
227 "bind (fr|udp) ID",
228 "Binding\n"
229 "Frame Relay\n" "UDP/IP\n"
230 "a unique identifier for this bind to reference NS-VCs\n"
231 )
232{
233 const char *nstype = argv[0];
234 const char *name = argv[1];
235 struct vty_bind *vbind;
236 enum gprs_ns2_ll ll;
237 int rc;
238
239 rc = get_string_value(vty_ll_names, nstype);
240 if (rc < 0)
241 return CMD_WARNING;
242 ll = (enum gprs_ns2_ll) rc;
243
244 if (!osmo_identifier_valid(name)) {
245 vty_out(vty, "Invalid ID. The ID should be only alphanumeric.%s", VTY_NEWLINE);
246 return CMD_WARNING;
247 }
248
249 vbind = vty_bind_by_name(name);
250 if (vbind) {
251 if (vbind->ll != ll) {
252 vty_out(vty, "A bind with the specified ID already exists with a different type (fr|frgre|udp)!%s",
253 VTY_NEWLINE);
254 return CMD_WARNING;
255 }
256 } else {
257 vbind = vty_bind_alloc(name);
258 if (!vbind) {
259 vty_out(vty, "Can not create bind - out of memory%s", VTY_NEWLINE);
260 return CMD_WARNING;
261 }
262 vbind->ll = ll;
263 }
264
265 vty->index = vbind;
266 vty->node = L_NS_BIND_NODE;
267
268 return CMD_SUCCESS;
269}
270
271DEFUN(cfg_no_ns_bind, cfg_no_ns_bind_cmd,
272 "no bind ID",
273 NO_STR
274 "Delete a binding\n"
275 "a unique identifier for this bind to reference NS-VCs\n"
276 )
277{
278 struct vty_bind *vbind;
279 struct gprs_ns2_vc_bind *bind;
280 const char *name = argv[0];
281
282 vbind = vty_bind_by_name(name);
283 if (!vbind) {
284 vty_out(vty, "bind %s does not exist!%s", name, VTY_NEWLINE);
285 return CMD_WARNING;
286 }
287 vty_bind_free(vbind);
288 bind = gprs_ns2_bind_by_name(vty_nsi, name);
289 if (bind)
290 bind->driver->free_bind(bind);
291 return CMD_SUCCESS;
292}
293
294
295static void config_write_vbind(struct vty *vty, struct vty_bind *vbind)
296{
297 struct gprs_ns2_vc_bind *bind;
298 const struct osmo_sockaddr *addr;
299 struct osmo_sockaddr_str addr_str;
300 const char *netif, *frrole_str, *llstr;
301 enum osmo_fr_role frrole;
302
303 llstr = get_value_string_or_null(vty_ll_names, vbind->ll);
304 if (!llstr)
305 return;
306 vty_out(vty, " bind %s %s%s", llstr, vbind->name, VTY_NEWLINE);
307
308 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
309 switch (vbind->ll) {
310 case GPRS_NS2_LL_FR:
311 if (bind) {
312 netif = gprs_ns2_fr_bind_netif(bind);
313 if (!netif)
314 return;
315 frrole = gprs_ns2_fr_bind_role(bind);
316 if ((int) frrole == -1)
317 return;
318 frrole_str = get_value_string_or_null(vty_fr_role_names, frrole);
319 if (netif && frrole_str)
320 vty_out(vty, " fr %s %s%s", netif, frrole_str, VTY_NEWLINE);
321 }
322 break;
323 case GPRS_NS2_LL_UDP:
324 if (bind) {
325 addr = gprs_ns2_ip_bind_sockaddr(bind);
326 if (!osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas)) {
327 vty_out(vty, " listen %s %u%s", addr_str.ip, addr_str.port,
328 VTY_NEWLINE);
329 }
330 }
331 if (vbind->accept_ipaccess)
332 vty_out(vty, " accept-ipaccess%s", VTY_NEWLINE);
333 if (vbind->dscp)
334 vty_out(vty, " dscp %u%s", vbind->dscp, VTY_NEWLINE);
Alexander Couzensc4704762021-02-08 23:13:12 +0100335 vty_out(vty, " ip-sns signalling-weight %u data-weight %u%s",
336 vbind->ip_sns_sig_weight, vbind->ip_sns_data_weight, VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100337 break;
338 default:
339 return;
340 }
341}
342
343static void config_write_nsvc(struct vty *vty, const struct gprs_ns2_vc *nsvc)
344{
345 const char *netif;
346 uint16_t dlci;
347 const struct osmo_sockaddr *addr;
348 struct osmo_sockaddr_str addr_str;
349
350 switch (nsvc->nse->ll) {
351 case GPRS_NS2_LL_UNDEF:
352 break;
353 case GPRS_NS2_LL_UDP:
354 switch (nsvc->nse->dialect) {
355 case GPRS_NS2_DIALECT_IPACCESS:
356 addr = gprs_ns2_ip_vc_remote(nsvc);
357 if (!addr)
358 break;
359 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas))
360 break;
361 vty_out(vty, " nsvc ipa %s %s %u nsvci %u%s",
362 nsvc->bind->name, addr_str.ip, addr_str.port,
363 nsvc->nsvci, VTY_NEWLINE);
364 break;
365 case GPRS_NS2_DIALECT_STATIC_ALIVE:
366 addr = gprs_ns2_ip_vc_remote(nsvc);
367 if (!addr)
368 break;
369 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas))
370 break;
371 vty_out(vty, " nsvc udp %s %s %u%s",
372 nsvc->bind->name, addr_str.ip, addr_str.port, VTY_NEWLINE);
373 break;
374 default:
375 break;
376 }
377 break;
378 case GPRS_NS2_LL_FR:
379 netif = gprs_ns2_fr_bind_netif(nsvc->bind);
380 if (!netif)
381 break;
382 dlci = gprs_ns2_fr_nsvc_dlci(nsvc);
383 if (!dlci)
384 break;
385 OSMO_ASSERT(nsvc->nsvci_is_valid);
386 vty_out(vty, " nsvc fr %s dlci %u nsvci %u%s",
387 netif, dlci, nsvc->nsvci, VTY_NEWLINE);
388 break;
389 case GPRS_NS2_LL_FR_GRE:
390 break;
391 }
392}
393
394static void _config_write_ns_nse(struct vty *vty, struct gprs_ns2_nse *nse)
395{
396 struct gprs_ns2_vc *nsvc;
397
398 vty_out(vty, " nse %u%s", nse->nsei, VTY_NEWLINE);
399 switch (nse->dialect) {
400 case GPRS_NS2_DIALECT_SNS:
401 ns2_sns_write_vty(vty, nse);
402 break;
403 default:
404 llist_for_each_entry(nsvc, &nse->nsvc, list) {
405 config_write_nsvc(vty, nsvc);
406 }
407 break;
408 }
409}
410
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100411static int config_write_ns_nse(struct vty *vty)
412{
413 struct gprs_ns2_nse *nse;
414
415 llist_for_each_entry(nse, &vty_nsi->nse, list) {
416 if (!nse->persistent)
417 continue;
418
419 _config_write_ns_nse(vty, nse);
420 }
421
422 return 0;
423}
424
425static int config_write_ns_bind(struct vty *vty)
426{
427 struct vty_bind *vbind;
428
429 llist_for_each_entry(vbind, &binds, list) {
430 config_write_vbind(vty, vbind);
431 }
432
433 return 0;
434}
435
Alexander Couzens260cd522021-01-28 20:31:31 +0100436static int config_write_ns(struct vty *vty)
437{
438 unsigned int i;
439 int ret;
440
441 vty_out(vty, "ns%s", VTY_NEWLINE);
442
443 for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++)
444 vty_out(vty, " timer %s %u%s",
445 get_value_string(gprs_ns_timer_strs, i),
446 vty_nsi->timeout[i], VTY_NEWLINE);
447
448 ret = config_write_ns_bind(vty);
449 if (ret)
450 return ret;
451
452 ret = config_write_ns_nse(vty);
453 if (ret)
454 return ret;
455
456 return 0;
457}
458
459
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100460static struct cmd_node ns_bind_node = {
461 L_NS_BIND_NODE,
462 "%s(config-ns-bind)# ",
463 1,
464};
465
466DEFUN(cfg_ns_bind_listen, cfg_ns_bind_listen_cmd,
467 "listen " VTY_IPV46_CMD " <1-65535>",
468 "Binding\n"
469 "IPv4 Address\n" "IPv6 Address\n"
470 "Port\n"
471 )
472{
473 struct vty_bind *vbind = vty->index;
474 struct gprs_ns2_vc_bind *bind;
475
476 const char *addr_str = argv[0];
477 unsigned int port = atoi(argv[1]);
478 struct osmo_sockaddr_str sockaddr_str;
479 struct osmo_sockaddr sockaddr;
480
481 if (vbind->ll != GPRS_NS2_LL_UDP) {
482 vty_out(vty, "listen can be only used with UDP bind%s",
483 VTY_NEWLINE);
484 return CMD_WARNING;
485 }
486
487 if (osmo_sockaddr_str_from_str(&sockaddr_str, addr_str, port)) {
488 vty_out(vty, "Can not parse the Address %s %s%s", argv[0], argv[1], VTY_NEWLINE);
489 return CMD_WARNING;
490 }
491 osmo_sockaddr_str_to_sockaddr(&sockaddr_str, &sockaddr.u.sas);
492 if (gprs_ns2_ip_bind_by_sockaddr(vty_nsi, &sockaddr)) {
493 vty_out(vty, "A bind with the specified address already exists!%s", VTY_NEWLINE);
494 return CMD_WARNING;
495 }
496
497 if (gprs_ns2_ip_bind(vty_nsi, vbind->name, &sockaddr, vbind->dscp, &bind) != 0) {
498 vty_out(vty, "Failed to create the bind!%s", VTY_NEWLINE);
499 return CMD_WARNING;
500 }
501
502 bind->accept_ipaccess = vbind->accept_ipaccess;
503 bind->accept_sns = vbind->accept_sns;
504
505 return CMD_SUCCESS;
506}
507
508DEFUN(cfg_no_ns_bind_listen, cfg_no_ns_bind_listen_cmd,
509 "no listen",
510 NO_STR
511 "Delete a IP/Port assignment\n"
512 )
513{
514 struct vty_bind *vbind = vty->index;
515 struct gprs_ns2_vc_bind *bind;
516
517 if (vbind->ll != GPRS_NS2_LL_UDP) {
518 vty_out(vty, "no listen can be only used with UDP bind%s", VTY_NEWLINE);
519 return CMD_WARNING;
520 }
521
522 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
523 if (!bind)
524 return CMD_ERR_NOTHING_TODO;
525
Daniel Willmann90432052021-01-26 16:09:18 +0100526 OSMO_ASSERT(bind->ll == GPRS_NS2_LL_UDP);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100527 bind->driver->free_bind(bind);
528 return CMD_SUCCESS;
529}
530
531DEFUN(cfg_ns_bind_dscp, cfg_ns_bind_dscp_cmd,
532 "dscp <0-255>",
533 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
534{
535 struct vty_bind *vbind = vty->index;
536 struct gprs_ns2_vc_bind *bind;
537 uint16_t dscp = atoi(argv[0]);
538
539 if (vbind->ll != GPRS_NS2_LL_UDP) {
540 vty_out(vty, "dscp can be only used with UDP bind%s",
541 VTY_NEWLINE);
542 return CMD_WARNING;
543 }
544
545 vbind->dscp = dscp;
546 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
547 if (bind)
548 gprs_ns2_ip_bind_set_dscp(bind, dscp);
549
550 return CMD_SUCCESS;
551}
552
553DEFUN(cfg_no_ns_bind_dscp, cfg_no_ns_bind_dscp_cmd,
554 "no dscp",
555 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
556{
557 struct vty_bind *vbind = vty->index;
558 struct gprs_ns2_vc_bind *bind;
559 uint16_t dscp = 0;
560
561 if (vbind->ll != GPRS_NS2_LL_UDP) {
562 vty_out(vty, "dscp can be only used with UDP bind%s",
563 VTY_NEWLINE);
564 return CMD_WARNING;
565 }
566
567 vbind->dscp = dscp;
568 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
569 if (bind)
570 gprs_ns2_ip_bind_set_dscp(bind, dscp);
571
572 return CMD_SUCCESS;
573}
574
575DEFUN(cfg_ns_bind_ipaccess, cfg_ns_bind_ipaccess_cmd,
576 "accept-ipaccess",
577 "Allow to create dynamic NS Entity by NS Reset PDU on UDP (ip.access style)\n"
578 )
579{
580 struct vty_bind *vbind = vty->index;
581 struct gprs_ns2_vc_bind *bind;
582
583 if (vbind->ll != GPRS_NS2_LL_UDP) {
584 vty_out(vty, "accept-ipaccess can be only used with UDP bind%s",
585 VTY_NEWLINE);
586 return CMD_WARNING;
587 }
588
589 vbind->accept_ipaccess = true;
590 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
591 if (bind)
592 bind->accept_ipaccess = true;
593
594 return CMD_SUCCESS;
595}
596
597DEFUN(cfg_no_ns_bind_ipaccess, cfg_no_ns_bind_ipaccess_cmd,
598 "no accept-ipaccess",
599 NO_STR
600 "Reject NS Reset PDU on UDP (ip.access style)\n"
601 )
602{
603 struct vty_bind *vbind = vty->index;
604 struct gprs_ns2_vc_bind *bind;
605
606 if (vbind->ll != GPRS_NS2_LL_UDP) {
607 vty_out(vty, "no accept-ipaccess can be only used with UDP bind%s",
608 VTY_NEWLINE);
609 return CMD_WARNING;
610 }
611
612 vbind->accept_ipaccess = false;
613 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
614 if (bind)
615 bind->accept_ipaccess = false;
616
617 return CMD_SUCCESS;
618}
619
Alexander Couzensc4704762021-02-08 23:13:12 +0100620DEFUN(cfg_ns_bind_ip_sns_weight, cfg_ns_bind_ip_sns_weight_cmd,
621 "ip-sns signalling-weight <0-254> data-weight <0-254>",
622 "IP SNS\n"
623 "signalling weight used by IP-SNS dynamic configuration\n"
624 "signalling weight used by IP-SNS dynamic configuration\n"
625 "data weight used by IP-SNS dynamic configuration\n"
626 "data weight used by IP-SNS dynamic configuration\n")
627{
628 struct vty_bind *vbind = vty->index;
629 struct gprs_ns2_vc_bind *bind;
630
631 int signalling = atoi(argv[0]);
632 int data = atoi(argv[1]);
633
634 if (vbind->ll != GPRS_NS2_LL_UDP) {
635 vty_out(vty, "ip-sns signalling-weight <0-254> data-weight <0-254> can be only used with UDP bind%s",
636 VTY_NEWLINE);
637 return CMD_WARNING;
638 }
639
640 vbind->ip_sns_data_weight = data;
641 vbind->ip_sns_sig_weight = signalling;
642 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
643 if (bind)
644 gprs_ns2_ip_bind_set_sns_weight(bind, signalling, data);
645
646 return CMD_SUCCESS;
647}
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100648
649DEFUN(cfg_ns_bind_fr, cfg_ns_bind_fr_cmd,
650 "fr NETIF (fr|frnet)",
651 "frame relay\n"
652 IFNAME_STR
653 "fr (user) is used by BSS or SGSN attached to UNI of a FR network\n"
654 "frnet (network) is used by SGSN if BSS is directly attached\n"
655 )
656{
657 struct vty_bind *vbind = vty->index;
658 struct gprs_ns2_vc_bind *bind;
659 const char *netif = argv[0];
660 const char *role = argv[1];
661
662 int rc = 0;
663 enum osmo_fr_role frrole;
664
665 if (vbind->ll != GPRS_NS2_LL_FR) {
666 vty_out(vty, "fr can be only used with frame relay bind%s", VTY_NEWLINE);
667 return CMD_WARNING;
668 }
669
670 if (!strcmp(role, "fr"))
671 frrole = FR_ROLE_USER_EQUIPMENT;
672 else if (!strcmp(role, "frnet"))
673 frrole = FR_ROLE_NETWORK_EQUIPMENT;
674 else
675 return CMD_WARNING;
676
677 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
678 if (bind) {
679 vty_out(vty, "Interface %s already used.%s", netif, VTY_NEWLINE);
680 return CMD_WARNING;
681 }
682
683 rc = gprs_ns2_fr_bind(vty_nsi, vbind->name, netif, vty_fr_network, frrole, &bind);
684 if (rc < 0) {
685 LOGP(DLNS, LOGL_ERROR, "Failed to bind interface %s on fr. Err: %d\n", netif, rc);
686 return CMD_WARNING;
687 }
688
689 return CMD_SUCCESS;
690}
691
692DEFUN(cfg_no_ns_bind_fr, cfg_no_ns_bind_fr_cmd,
693 "no fr NETIF",
694 NO_STR
695 "Delete a frame relay link\n"
696 "Delete a frame relay link\n"
697 IFNAME_STR
698 )
699{
700 struct vty_bind *vbind = vty->index;
701 struct gprs_ns2_vc_bind *bind;
702 const char *netif = argv[0];
703
704 if (vbind->ll != GPRS_NS2_LL_FR) {
705 vty_out(vty, "fr can be only used with frame relay bind%s",
706 VTY_NEWLINE);
707 return CMD_WARNING;
708 }
709
710 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
711 if (!bind) {
712 vty_out(vty, "Interface not found.%s", VTY_NEWLINE);
713 return CMD_WARNING;
714 }
715
716 if (strcmp(bind->name, vbind->name)) {
717 vty_out(vty, "The specified interface is not bound to this bind.%s", VTY_NEWLINE);
718 return CMD_WARNING;
719 }
720
721 bind->driver->free_bind(bind);
722 return CMD_SUCCESS;
723}
724
725
726static struct cmd_node ns_nse_node = {
727 L_NS_NSE_NODE,
728 "%s(config-ns-nse)# ",
729 1,
730};
731
732DEFUN(cfg_ns_nse_nsvc_fr, cfg_ns_nse_nsvc_fr_cmd,
733 "nsvc fr NETIF dlci <16-1007> nsvci <0-65535>",
734 "NS Virtual Connection\n"
735 "frame relay\n"
736 "frame relay interface. Must be registered via fr vty\n"
737 NSVCI_STR
738 NSVCI_STR
739 DLCI_STR
740 DLCI_STR
741 )
742{
743 struct gprs_ns2_vc_bind *bind;
744 struct gprs_ns2_vc *nsvc;
745 struct gprs_ns2_nse *nse = vty->index;
746 const char *netif = argv[0];
747 uint16_t dlci = atoi(argv[1]);
748 uint16_t nsvci = atoi(argv[2]);
749 bool dialect_modified = false;
750 bool ll_modified = false;
751
752 if (nse->ll != GPRS_NS2_LL_FR && nse->ll != GPRS_NS2_LL_UNDEF) {
753 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
754 goto err;
755 }
756
757 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_RESETBLOCK && nse->dialect != GPRS_NS2_DIALECT_UNDEF) {
758 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
759 goto err;
760 }
761
762 if (nse->ll == GPRS_NS2_LL_UNDEF) {
763 nse->ll = GPRS_NS2_LL_FR;
764 ll_modified = true;
765 }
766
767 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
768 nse->dialect = GPRS_NS2_DIALECT_STATIC_RESETBLOCK;
769 dialect_modified = true;
770 }
771
772
773 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
774 if (!bind) {
775 vty_out(vty, "Can not find fr interface \"%s\". Please configure it via fr vty.%s",
776 netif, VTY_NEWLINE);
777 goto err;
778 }
779
780 if (gprs_ns2_fr_nsvc_by_dlci(bind, dlci)) {
781 vty_out(vty, "A NS-VC with the specified DLCI already exist!%s", VTY_NEWLINE);
782 goto err;
783 }
784
785 if (gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci)) {
786 vty_out(vty, "A NS-VC with the specified NS-VCI already exist!%s", VTY_NEWLINE);
787 goto err;
788 }
789
790 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
791 if (!nsvc) {
792 /* Could not create NS-VC, connect failed */
793 vty_out(vty, "Failed to create the NS-VC%s", VTY_NEWLINE);
794 goto err;
795 }
796 nsvc->persistent = true;
797 return CMD_SUCCESS;
798
799err:
800 if (ll_modified)
801 nse->ll = GPRS_NS2_LL_UNDEF;
802 if (dialect_modified)
803 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
804
805 return CMD_WARNING;
806}
807
808DEFUN(cfg_no_ns_nse_nsvc_fr_dlci, cfg_no_ns_nse_nsvc_fr_dlci_cmd,
809 "no nsvc fr NETIF dlci <16-1007>",
810 NO_STR
811 "Delete frame relay NS-VC\n"
812 "frame relay\n"
813 "frame relay interface. Must be registered via fr vty\n"
814 DLCI_STR
815 DLCI_STR
816 )
817{
818 struct gprs_ns2_vc_bind *bind;
819 struct gprs_ns2_vc *nsvc;
820 struct gprs_ns2_nse *nse = vty->index;
821 const char *netif = argv[0];
822 uint16_t dlci = atoi(argv[1]);
823
824 if (nse->ll != GPRS_NS2_LL_FR) {
825 vty_out(vty, "This NSE doesn't support frame relay.%s", VTY_NEWLINE);
826 return CMD_WARNING;
827 }
828
829 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
830 if (!bind) {
831 vty_out(vty, "Can not find fr interface \"%s\"%s",
832 netif, VTY_NEWLINE);
833 return CMD_ERR_NOTHING_TODO;
834 }
835
836 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
837 if (!nsvc) {
838 vty_out(vty, "Can not find a NS-VC on fr interface %s with dlci %u%s",
839 netif, dlci, VTY_NEWLINE);
840 return CMD_WARNING;
841 }
842
843 if (nse != nsvc->nse) {
844 vty_out(vty, "The specified NS-VC is not a part of the NSE %u!%s"
845 "To remove this NS-VC go to the vty node 'nse %u'%s",
846 nse->nsei, VTY_NEWLINE,
847 nsvc->nse->nsei, VTY_NEWLINE);
848 return CMD_WARNING;
849 }
850
851 gprs_ns2_free_nsvc(nsvc);
852 if (llist_empty(&nse->nsvc)) {
853 nse->ll = GPRS_NS2_LL_UNDEF;
854 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
855 }
856
857 return CMD_SUCCESS;
858}
859
860DEFUN(cfg_no_ns_nse_nsvci, cfg_no_ns_nse_nsvci_cmd,
861 "no nsvc nsvci <0-65535>",
862 NO_STR
863 "Delete NSVC\n"
864 NSVCI_STR
865 NSVCI_STR
866 )
867{
868 struct gprs_ns2_vc *nsvc;
869 struct gprs_ns2_nse *nse = vty->index;
870 uint16_t nsvci = atoi(argv[0]);
871
872 switch (nse->dialect) {
873 case GPRS_NS2_DIALECT_SNS:
874 case GPRS_NS2_DIALECT_STATIC_ALIVE:
875 vty_out(vty, "NSE doesn't support NSVCI.%s", VTY_NEWLINE);
876 return CMD_WARNING;
877 case GPRS_NS2_DIALECT_UNDEF:
878 vty_out(vty, "No NSVCs configured%s", VTY_NEWLINE);
879 return CMD_WARNING;
880 case GPRS_NS2_DIALECT_IPACCESS:
881 case GPRS_NS2_DIALECT_STATIC_RESETBLOCK:
882 break;
883 }
884
885 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci);
886 if (!nsvc) {
887 vty_out(vty, "Can not find NS-VC with NS-VCI %u%s", nsvci, VTY_NEWLINE);
888 return CMD_WARNING;
889 }
890
891 if (nse != nsvc->nse) {
892 vty_out(vty, "NS-VC with NS-VCI %u is not part of this NSE!%s",
893 nsvci, VTY_NEWLINE);
894 return CMD_WARNING;
895 }
896
897 gprs_ns2_free_nsvc(nsvc);
898 if (llist_empty(&nse->nsvc)) {
899 nse->ll = GPRS_NS2_LL_UNDEF;
900 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
901 }
902
903 return CMD_SUCCESS;
904}
905
906DEFUN(cfg_ns_nse_nsvc_udp, cfg_ns_nse_nsvc_udp_cmd,
907 "nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
908 "NS Virtual Connection\n"
909 "NS over UDP\n"
910 "A unique bind identifier created by ns bind\n"
911 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
912 "Remote UDP Port\n"
913 )
914{
915 struct gprs_ns2_vc_bind *bind;
916 struct gprs_ns2_vc *nsvc;
917 struct gprs_ns2_nse *nse = vty->index;
918 bool dialect_modified = false;
919 bool ll_modified = false;
920
921 const char *bind_name = argv[0];
922 struct osmo_sockaddr_str remote_str;
923 struct osmo_sockaddr remote;
924 uint16_t port = atoi(argv[2]);
925
926 if (nse->ll == GPRS_NS2_LL_UNDEF) {
927 nse->ll = GPRS_NS2_LL_UDP;
928 ll_modified = true;
929 }
930
931 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
932 nse->dialect = GPRS_NS2_DIALECT_STATIC_ALIVE;
933 dialect_modified = true;
934 }
935
936 if (nse->ll != GPRS_NS2_LL_UDP) {
937 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
938 goto err;
939 }
940
941 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
942 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
943 goto err;
944 }
945
946 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
947 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
948 goto err;
949 }
950
951 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
952 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
953 goto err;
954 }
955
956 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
957 if (!bind) {
958 vty_out(vty, "Can not find bind with name %s%s",
959 bind_name, VTY_NEWLINE);
960 goto err;
961 }
962
963 if (bind->ll != GPRS_NS2_LL_UDP) {
964 vty_out(vty, "Bind %s is not an UDP bind.%s",
965 bind_name, VTY_NEWLINE);
966 goto err;
967 }
968
969 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, 0);
970 if (!nsvc) {
971 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
972 goto err;
973 }
974 nsvc->persistent = true;
975
976 return CMD_SUCCESS;
977
978err:
979 if (ll_modified)
980 nse->ll = GPRS_NS2_LL_UNDEF;
981 if (dialect_modified)
982 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
983 return CMD_WARNING;
984}
985
986DEFUN(cfg_no_ns_nse_nsvc_udp, cfg_no_ns_nse_nsvc_udp_cmd,
987 "no nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
988 NO_STR
989 "Delete a NS Virtual Connection\n"
990 "NS over UDP\n"
991 "A unique bind identifier created by ns bind\n"
992 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
993 "Remote UDP Port\n"
994 )
995{
996 struct gprs_ns2_vc_bind *bind;
997 struct gprs_ns2_vc *nsvc;
998 struct gprs_ns2_nse *nse = vty->index;
999 const char *bind_name = argv[0];
1000 struct osmo_sockaddr_str remote_str;
1001 struct osmo_sockaddr remote;
1002 uint16_t port = atoi(argv[2]);
1003
1004 if (nse->ll != GPRS_NS2_LL_UDP) {
1005 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1006 return CMD_WARNING;
1007 }
1008
1009 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
1010 vty_out(vty, "This NSE doesn't support UDP with dialect static alive.%s", VTY_NEWLINE);
1011 return CMD_WARNING;
1012 }
1013
1014 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1015 if (!bind) {
1016 vty_out(vty, "Can not find bind with name %s%s",
1017 bind_name, VTY_NEWLINE);
1018 return CMD_WARNING;
1019 }
1020
1021 if (bind->ll != GPRS_NS2_LL_UDP) {
1022 vty_out(vty, "Bind %s is not an UDP bind.%s",
1023 bind_name, VTY_NEWLINE);
1024 return CMD_WARNING;
1025 }
1026
1027 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1028 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1029 return CMD_WARNING;
1030 }
1031
1032 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1033 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1034 return CMD_WARNING;
1035 }
1036
1037 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1038 if (!nsvc) {
1039 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1040 remote_str.ip, remote_str.port, VTY_NEWLINE);
1041 return CMD_WARNING;
1042 }
1043
1044 if (!nsvc->persistent) {
1045 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1046 remote_str.ip, remote_str.port, VTY_NEWLINE);
1047 return CMD_WARNING;
1048 }
1049
1050 if (nsvc->nse != nse) {
1051 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1052 return CMD_WARNING;
1053 }
1054
1055 gprs_ns2_free_nsvc(nsvc);
1056 if (llist_empty(&nse->nsvc)) {
1057 nse->ll = GPRS_NS2_LL_UNDEF;
1058 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1059 }
1060
1061 return CMD_SUCCESS;
1062}
1063
1064DEFUN(cfg_ns_nse_nsvc_ipa, cfg_ns_nse_nsvc_ipa_cmd,
1065 "nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>" ,
1066 "NS Virtual Connection\n"
1067 "NS over UDP ip.access style (uses RESET/BLOCK)\n"
1068 "A unique bind identifier created by ns bind\n"
1069 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1070 "Remote UDP Port\n"
1071 NSVCI_STR
1072 NSVCI_STR
1073 )
1074{
1075 struct gprs_ns2_vc_bind *bind;
1076 struct gprs_ns2_vc *nsvc;
1077 struct gprs_ns2_nse *nse = vty->index;
1078 bool dialect_modified = false;
1079 bool ll_modified = false;
1080
1081 const char *bind_name = argv[0];
1082 struct osmo_sockaddr_str remote_str;
1083 struct osmo_sockaddr remote;
1084 uint16_t port = atoi(argv[2]);
1085 uint16_t nsvci = atoi(argv[3]);
1086
1087 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1088 nse->ll = GPRS_NS2_LL_UDP;
1089 ll_modified = true;
1090 }
1091
1092 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
1093 nse->dialect = GPRS_NS2_DIALECT_IPACCESS;
1094 dialect_modified = true;
1095 }
1096
1097 if (nse->ll != GPRS_NS2_LL_UDP) {
1098 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1099 goto err;
1100 }
1101
1102 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1103 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1104 goto err;
1105 }
1106
1107 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1108 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1109 goto err;
1110 }
1111
1112 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1113 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1114 goto err;
1115 }
1116
1117 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1118 if (!bind) {
1119 vty_out(vty, "Can not find bind with name %s%s",
1120 bind_name, VTY_NEWLINE);
1121 goto err;
1122 }
1123
1124 if (bind->ll != GPRS_NS2_LL_UDP) {
1125 vty_out(vty, "Bind %s is not an UDP bind.%s",
1126 bind_name, VTY_NEWLINE);
1127 goto err;
1128 }
1129
1130 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, nsvci);
1131 if (!nsvc) {
1132 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
1133 goto err;
1134 }
1135 nsvc->persistent = true;
1136
1137 return CMD_SUCCESS;
1138
1139err:
1140 if (ll_modified)
1141 nse->ll = GPRS_NS2_LL_UNDEF;
1142 if (dialect_modified)
1143 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1144 return CMD_WARNING;
1145}
1146
1147DEFUN(cfg_no_ns_nse_nsvc_ipa, cfg_no_ns_nse_nsvc_ipa_cmd,
1148 "no nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>",
1149 NO_STR
1150 "Delete a NS Virtual Connection\n"
1151 "NS over UDP\n"
1152 "A unique bind identifier created by ns bind\n"
1153 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1154 "Remote UDP Port\n"
1155 NSVCI_STR
1156 NSVCI_STR
1157 )
1158{
1159 struct gprs_ns2_vc_bind *bind;
1160 struct gprs_ns2_vc *nsvc;
1161 struct gprs_ns2_nse *nse = vty->index;
1162 const char *bind_name = argv[0];
1163 struct osmo_sockaddr_str remote_str;
1164 struct osmo_sockaddr remote;
1165 uint16_t port = atoi(argv[2]);
1166 uint16_t nsvci = atoi(argv[3]);
1167
1168 if (nse->ll != GPRS_NS2_LL_UDP) {
1169 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1170 return CMD_WARNING;
1171 }
1172
1173 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1174 vty_out(vty, "This NSE doesn't support UDP with dialect ipaccess.%s", VTY_NEWLINE);
1175 return CMD_WARNING;
1176 }
1177
1178 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1179 if (!bind) {
1180 vty_out(vty, "Can not find bind with name %s%s",
1181 bind_name, VTY_NEWLINE);
1182 return CMD_WARNING;
1183 }
1184
1185 if (bind->ll != GPRS_NS2_LL_UDP) {
1186 vty_out(vty, "Bind %s is not an UDP bind.%s",
1187 bind_name, VTY_NEWLINE);
1188 return CMD_WARNING;
1189 }
1190
1191 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1192 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1193 return CMD_WARNING;
1194 }
1195
1196 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1197 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1198 return CMD_WARNING;
1199 }
1200
1201 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1202 if (!nsvc) {
1203 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1204 remote_str.ip, remote_str.port, VTY_NEWLINE);
1205 return CMD_WARNING;
1206 }
1207
1208 if (!nsvc->persistent) {
1209 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1210 remote_str.ip, remote_str.port, VTY_NEWLINE);
1211 return CMD_WARNING;
1212 }
1213
1214 if (nsvc->nse != nse) {
1215 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1216 return CMD_WARNING;
1217 }
1218
1219 if (!nsvc->nsvci_is_valid) {
1220 vty_out(vty, "NS-VC doesn't have a nsvci!%s", VTY_NEWLINE);
1221 return CMD_WARNING;
1222 }
1223
1224 if (nsvc->nsvci != nsvci) {
1225 vty_out(vty, "NS-VC has a different nsvci (%u)!%s",
1226 nsvc->nsvci, VTY_NEWLINE);
1227 return CMD_WARNING;
1228 }
1229
1230 gprs_ns2_free_nsvc(nsvc);
1231 if (llist_empty(&nse->nsvc)) {
1232 nse->ll = GPRS_NS2_LL_UNDEF;
1233 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1234 }
1235
1236 return CMD_SUCCESS;
1237}
1238
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001239DEFUN(cfg_ns_nse_ip_sns_remote, cfg_ns_nse_ip_sns_remote_cmd,
1240 "ip-sns-remote " VTY_IPV46_CMD " <1-65535>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001241 "SNS Initial Endpoint\n"
1242 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1243 "SGSN UDP Port\n"
1244 )
1245{
1246 struct gprs_ns2_nse *nse = vty->index;
1247 bool dialect_modified = false;
1248 bool ll_modified = false;
1249 int rc;
1250
1251 /* argv[0] */
1252 struct osmo_sockaddr_str remote_str;
1253 struct osmo_sockaddr remote;
1254 uint16_t port = atoi(argv[1]);
1255
1256 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1257 nse->ll = GPRS_NS2_LL_UDP;
1258 ll_modified = true;
1259 }
1260
1261 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
1262 char sns[16];
1263 snprintf(sns, sizeof(sns), "NSE%05u-SNS", nse->nsei);
1264 nse->bss_sns_fi = ns2_sns_bss_fsm_alloc(nse, sns);
1265 if (!nse->bss_sns_fi)
1266 goto err;
1267 nse->dialect = GPRS_NS2_DIALECT_SNS;
1268 dialect_modified = true;
1269 }
1270
1271 if (nse->ll != GPRS_NS2_LL_UDP) {
1272 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1273 goto err;
1274 }
1275
1276 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1277 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1278 goto err;
1279 }
1280
1281 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1282 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1283 goto err;
1284 }
1285
1286 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1287 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1288 goto err;
1289 }
1290
1291 rc = gprs_ns2_sns_add_endpoint(nse, &remote);
1292 switch (rc) {
1293 case 0:
1294 return CMD_SUCCESS;
1295 case -EADDRINUSE:
1296 vty_out(vty, "Specified SNS endpoint already part of the NSE.%s", VTY_NEWLINE);
1297 return CMD_WARNING;
1298 default:
1299 vty_out(vty, "Can not add specified SNS endpoint.%s", VTY_NEWLINE);
1300 return CMD_WARNING;
1301 }
1302
1303err:
1304 if (ll_modified)
1305 nse->ll = GPRS_NS2_LL_UNDEF;
1306 if (dialect_modified)
1307 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1308 return CMD_WARNING;
1309}
1310
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001311DEFUN(cfg_no_ns_nse_ip_sns_remote, cfg_no_ns_nse_ip_sns_remote_cmd,
1312 "no ip-sns-remote " VTY_IPV46_CMD " <1-65535>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001313 NO_STR
1314 "Delete a SNS Initial Endpoint\n"
1315 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1316 "SGSN UDP Port\n"
1317 )
1318{
1319 struct gprs_ns2_nse *nse = vty->index;
1320 struct osmo_sockaddr_str remote_str; /* argv[0] */
1321 struct osmo_sockaddr remote;
1322 uint16_t port = atoi(argv[1]);
1323 int count;
1324
1325 if (nse->ll != GPRS_NS2_LL_UDP) {
1326 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1327 return CMD_WARNING;
1328 }
1329
1330 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1331 vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%s", VTY_NEWLINE);
1332 return CMD_WARNING;
1333 }
1334
1335 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1336 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1337 return CMD_WARNING;
1338 }
1339
1340 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1341 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1342 return CMD_WARNING;
1343 }
1344
1345 if (gprs_ns2_sns_del_endpoint(nse, &remote)) {
1346 vty_out(vty, "Can not remove specified SNS endpoint.%s", VTY_NEWLINE);
1347 return CMD_WARNING;
1348 }
1349
1350 count = gprs_ns2_sns_count(nse);
1351 if (count > 0) {
1352 /* there are other sns endpoints */
1353 return CMD_SUCCESS;
1354 } else if (count < 0) {
1355 OSMO_ASSERT(0);
1356 } else {
1357 /* clean up nse to allow other nsvc commands */
1358 osmo_fsm_inst_term(nse->bss_sns_fi, OSMO_FSM_TERM_REQUEST, NULL);
1359 nse->bss_sns_fi = NULL;
1360 nse->ll = GPRS_NS2_LL_UNDEF;
1361 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1362 }
1363
1364 return CMD_SUCCESS;
1365}
1366
1367
1368/* non-config commands */
Alexander Couzens6a161492020-07-12 13:45:50 +02001369static void dump_nsvc(struct vty *vty, struct gprs_ns2_vc *nsvc, bool stats)
1370{
Harald Weltedc2d0802020-12-01 18:17:28 +01001371 char nsvci_str[32];
1372
1373 if (nsvc->nsvci_is_valid)
1374 snprintf(nsvci_str, sizeof(nsvci_str), "%05u", nsvc->nsvci);
1375 else
1376 snprintf(nsvci_str, sizeof(nsvci_str), "none");
1377
1378 vty_out(vty, " NSVCI %s: %s %s data_weight=%u sig_weight=%u %s%s", nsvci_str,
1379 osmo_fsm_inst_state_name(nsvc->fi),
1380 nsvc->persistent ? "PERSIST" : "DYNAMIC",
1381 nsvc->data_weight, nsvc->sig_weight,
1382 gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001383
1384 if (stats) {
Harald Welte7aa60992020-12-01 17:53:17 +01001385 vty_out_rate_ctr_group(vty, " ", nsvc->ctrg);
1386 vty_out_stat_item_group(vty, " ", nsvc->statg);
Alexander Couzens6a161492020-07-12 13:45:50 +02001387 }
1388}
1389
1390static void dump_nse(struct vty *vty, const struct gprs_ns2_nse *nse, bool stats, bool persistent_only)
1391{
1392 struct gprs_ns2_vc *nsvc;
1393
Harald Welte0ff12ad2020-12-01 17:51:07 +01001394 vty_out(vty, "NSEI %05u: %s, %s%s", nse->nsei, gprs_ns2_lltype_str(nse->ll),
1395 nse->alive ? "ALIVE" : "DEAD", VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001396
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001397 ns2_sns_dump_vty(vty, " ", nse, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001398 llist_for_each_entry(nsvc, &nse->nsvc, list) {
1399 if (persistent_only) {
1400 if (nsvc->persistent)
1401 dump_nsvc(vty, nsvc, stats);
1402 } else {
1403 dump_nsvc(vty, nsvc, stats);
1404 }
1405 }
1406}
1407
Alexander Couzens22f34712020-10-02 02:34:39 +02001408static void dump_bind(struct vty *vty, const struct gprs_ns2_vc_bind *bind, bool stats)
1409{
1410 if (bind->dump_vty)
1411 bind->dump_vty(bind, vty, stats);
Harald Welte76346072021-01-31 11:54:02 +01001412
1413 if (stats) {
1414 vty_out_stat_item_group(vty, " ", bind->statg);
1415 }
Alexander Couzens22f34712020-10-02 02:34:39 +02001416}
1417
Harald Welte2fce19a2020-12-01 17:52:55 +01001418static void dump_ns_bind(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats)
Alexander Couzens6a161492020-07-12 13:45:50 +02001419{
Alexander Couzens22f34712020-10-02 02:34:39 +02001420 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6a161492020-07-12 13:45:50 +02001421
Alexander Couzens22f34712020-10-02 02:34:39 +02001422 llist_for_each_entry(bind, &nsi->binding, list) {
1423 dump_bind(vty, bind, stats);
1424 }
Harald Welte2fce19a2020-12-01 17:52:55 +01001425}
1426
1427
1428static void dump_ns_entities(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats, bool persistent_only)
1429{
1430 struct gprs_ns2_nse *nse;
Alexander Couzens22f34712020-10-02 02:34:39 +02001431
Alexander Couzens6a161492020-07-12 13:45:50 +02001432 llist_for_each_entry(nse, &nsi->nse, list) {
1433 dump_nse(vty, nse, stats, persistent_only);
Alexander Couzens6a161492020-07-12 13:45:50 +02001434 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001435}
1436
Harald Welte25ee7552020-12-02 22:14:00 +01001437/* Backwards compatibility, among other things for the TestVTYGbproxy which expects
1438 * 'show ns' to output something about binds */
1439DEFUN_HIDDEN(show_ns, show_ns_cmd, "show ns",
1440 SHOW_STR SHOW_NS_STR)
1441{
1442 dump_ns_entities(vty, vty_nsi, false, false);
1443 dump_ns_bind(vty, vty_nsi, false);
1444 return CMD_SUCCESS;
1445}
1446
1447
Harald Welte2fce19a2020-12-01 17:52:55 +01001448DEFUN(show_ns_binds, show_ns_binds_cmd, "show ns binds [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001449 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01001450 "Display information about the NS protocol binds\n"
1451 "Include statistic\n")
Alexander Couzens6a161492020-07-12 13:45:50 +02001452{
Harald Welte2fce19a2020-12-01 17:52:55 +01001453 bool stats = false;
1454 if (argc > 0)
1455 stats = true;
1456
1457 dump_ns_bind(vty, vty_nsi, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001458 return CMD_SUCCESS;
1459}
1460
Harald Welte2fce19a2020-12-01 17:52:55 +01001461DEFUN(show_ns_entities, show_ns_entities_cmd, "show ns entities [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001462 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01001463 "Display information about the NS protocol entities (NSEs)\n"
Alexander Couzens6a161492020-07-12 13:45:50 +02001464 "Include statistics\n")
1465{
Harald Welte2fce19a2020-12-01 17:52:55 +01001466 bool stats = false;
1467 if (argc > 0)
1468 stats = true;
1469
1470 dump_ns_entities(vty, vty_nsi, stats, false);
Alexander Couzens6a161492020-07-12 13:45:50 +02001471 return CMD_SUCCESS;
1472}
1473
1474DEFUN(show_ns_pers, show_ns_pers_cmd, "show ns persistent",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001475 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02001476 "Show only persistent NS\n")
1477{
Harald Welte2fce19a2020-12-01 17:52:55 +01001478 dump_ns_entities(vty, vty_nsi, true, true);
Alexander Couzens6a161492020-07-12 13:45:50 +02001479 return CMD_SUCCESS;
1480}
1481
1482DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001483 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02001484 "Select one NSE by its NSE Identifier\n"
1485 "Select one NSE by its NS-VC Identifier\n"
1486 "The Identifier of selected type\n"
1487 "Include Statistics\n")
1488{
1489 struct gprs_ns2_inst *nsi = vty_nsi;
1490 struct gprs_ns2_nse *nse;
1491 struct gprs_ns2_vc *nsvc;
1492 uint16_t id = atoi(argv[1]);
1493 bool show_stats = false;
1494
1495 if (argc >= 3)
1496 show_stats = true;
1497
1498 if (!strcmp(argv[0], "nsei")) {
1499 nse = gprs_ns2_nse_by_nsei(nsi, id);
1500 if (!nse) {
1501 return CMD_WARNING;
1502 }
1503
1504 dump_nse(vty, nse, show_stats, false);
1505 } else {
1506 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
1507
1508 if (!nsvc) {
1509 vty_out(vty, "No such NS Entity%s", VTY_NEWLINE);
1510 return CMD_WARNING;
1511 }
1512
1513 dump_nsvc(vty, nsvc, show_stats);
1514 }
1515
1516 return CMD_SUCCESS;
1517}
1518
Daniel Willmanndbab7142020-11-18 14:19:56 +01001519static int nsvc_force_unconf_cb(struct gprs_ns2_vc *nsvc, void *ctx)
1520{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001521 ns2_vc_force_unconfigured(nsvc);
Harald Welte7fe8d712021-01-31 18:40:54 +01001522 ns2_vc_fsm_start(nsvc);
Daniel Willmanndbab7142020-11-18 14:19:56 +01001523 return 0;
1524}
1525
1526DEFUN_HIDDEN(nsvc_force_unconf, nsvc_force_unconf_cmd,
1527 "nsvc nsei <0-65535> force-unconfigured",
1528 "NS Virtual Connection\n"
1529 "The NSEI\n"
1530 "Reset the NSVCs back to initial state\n"
1531 )
1532{
1533 struct gprs_ns2_inst *nsi = vty_nsi;
1534 struct gprs_ns2_nse *nse;
1535
1536 uint16_t id = atoi(argv[0]);
1537
1538 nse = gprs_ns2_nse_by_nsei(nsi, id);
1539 if (!nse) {
1540 vty_out(vty, "Could not find NSE for NSEI %u%s", id, VTY_NEWLINE);
1541 return CMD_WARNING;
1542 }
1543
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001544 if (!nse->persistent) {
1545 gprs_ns2_free_nse(nse);
1546 } else if (nse->dialect == GPRS_NS2_DIALECT_SNS) {
Alexander Couzens280ed782020-12-21 18:25:41 +01001547 gprs_ns2_free_nsvcs(nse);
1548 } else {
1549 /* Perform the operation for all nsvc */
1550 gprs_ns2_nse_foreach_nsvc(nse, nsvc_force_unconf_cb, NULL);
1551 }
Daniel Willmanndbab7142020-11-18 14:19:56 +01001552
1553 return CMD_SUCCESS;
1554}
1555
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001556DEFUN(nsvc_block, nsvc_block_cmd,
1557 "nsvc <0-65535> (block|unblock)",
1558 "NS Virtual Connection\n"
1559 NSVCI_STR
1560 "Block a NSVC. As cause code O&M intervention will be used.\n"
1561 "Unblock a NSVC. As cause code O&M intervention will be used.\n")
Alexander Couzens841817e2020-11-19 00:41:29 +01001562{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001563 struct gprs_ns2_inst *nsi = vty_nsi;
1564 struct gprs_ns2_vc *nsvc;
Alexander Couzens841817e2020-11-19 00:41:29 +01001565
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001566 uint16_t id = atoi(argv[0]);
Alexander Couzens841817e2020-11-19 00:41:29 +01001567
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001568 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
1569 if (!nsvc) {
1570 vty_out(vty, "Could not find NSVCI %05u%s", id, VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +01001571 return CMD_WARNING;
1572 }
1573
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001574 if (!strcmp(argv[1], "block")) {
1575 ns2_vc_block(nsvc);
1576 } else {
1577 ns2_vc_unblock(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +02001578 }
1579
1580 return CMD_SUCCESS;
1581}
1582
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001583static void log_set_nse_filter(struct log_target *target,
1584 struct gprs_ns2_nse *nse)
Alexander Couzens6a161492020-07-12 13:45:50 +02001585{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001586 if (nse) {
1587 target->filter_map |= (1 << LOG_FLT_GB_NSE);
1588 target->filter_data[LOG_FLT_GB_NSE] = nse;
1589 } else if (target->filter_data[LOG_FLT_GB_NSE]) {
1590 target->filter_map = ~(1 << LOG_FLT_GB_NSE);
1591 target->filter_data[LOG_FLT_GB_NSE] = NULL;
1592 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001593}
1594
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001595static void log_set_nsvc_filter(struct log_target *target,
1596 struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +02001597{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001598 if (nsvc) {
1599 target->filter_map |= (1 << LOG_FLT_GB_NSVC);
1600 target->filter_data[LOG_FLT_GB_NSVC] = nsvc;
1601 } else if (target->filter_data[LOG_FLT_GB_NSVC]) {
1602 target->filter_map = ~(1 << LOG_FLT_GB_NSVC);
1603 target->filter_data[LOG_FLT_GB_NSVC] = NULL;
1604 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001605}
1606
Daniel Willmann751977b2020-12-02 18:59:44 +01001607DEFUN(logging_fltr_nse,
1608 logging_fltr_nse_cmd,
1609 "logging filter nse nsei <0-65535>",
1610 LOGGING_STR FILTER_STR
1611 "Filter based on NS Entity\n"
1612 "Identify NSE by NSEI\n"
1613 "Numeric identifier\n")
1614{
1615 struct log_target *tgt;
1616 struct gprs_ns2_nse *nse;
Daniel Willmann89106522020-12-04 01:36:59 +01001617 uint16_t id = atoi(argv[0]);
Daniel Willmann751977b2020-12-02 18:59:44 +01001618
1619 log_tgt_mutex_lock();
1620 tgt = osmo_log_vty2tgt(vty);
1621 if (!tgt) {
1622 log_tgt_mutex_unlock();
1623 return CMD_WARNING;
1624 }
1625
1626 nse = gprs_ns2_nse_by_nsei(vty_nsi, id);
1627 if (!nse) {
1628 vty_out(vty, "No NSE by that identifier%s", VTY_NEWLINE);
1629 log_tgt_mutex_unlock();
1630 return CMD_WARNING;
1631 }
1632
1633 log_set_nse_filter(tgt, nse);
1634 log_tgt_mutex_unlock();
1635 return CMD_SUCCESS;
1636}
1637
Alexander Couzens6a161492020-07-12 13:45:50 +02001638/* TODO: add filter for single connection by description */
1639DEFUN(logging_fltr_nsvc,
1640 logging_fltr_nsvc_cmd,
1641 "logging filter nsvc nsvci <0-65535>",
1642 LOGGING_STR FILTER_STR
1643 "Filter based on NS Virtual Connection\n"
1644 "Identify NS-VC by NSVCI\n"
1645 "Numeric identifier\n")
1646{
1647 struct log_target *tgt;
1648 struct gprs_ns2_vc *nsvc;
Daniel Willmann89106522020-12-04 01:36:59 +01001649 uint16_t id = atoi(argv[0]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001650
1651 log_tgt_mutex_lock();
1652 tgt = osmo_log_vty2tgt(vty);
1653 if (!tgt) {
1654 log_tgt_mutex_unlock();
1655 return CMD_WARNING;
1656 }
1657
1658 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, id);
1659 if (!nsvc) {
1660 vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE);
1661 log_tgt_mutex_unlock();
1662 return CMD_WARNING;
1663 }
1664
1665 log_set_nsvc_filter(tgt, nsvc);
1666 log_tgt_mutex_unlock();
1667 return CMD_SUCCESS;
1668}
1669
Alexander Couzense43b46e2021-01-27 21:52:08 +01001670/*! initialized a reduced vty interface which excludes the configuration nodes besides timeouts.
1671 * This can be used by the PCU which can be only configured by the BTS/BSC and not by the vty.
1672 * \param[in] nsi NS instance on which we operate
1673 * \return 0 on success.
1674 */
1675int gprs_ns2_vty_init_reduced(struct gprs_ns2_inst *nsi)
Alexander Couzens6a161492020-07-12 13:45:50 +02001676{
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01001677 vty_nsi = nsi;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001678 INIT_LLIST_HEAD(&binds);
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01001679
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001680 vty_fr_network = osmo_fr_network_alloc(nsi);
1681 if (!vty_fr_network)
1682 return -ENOMEM;
Alexander Couzens6a161492020-07-12 13:45:50 +02001683
Harald Welte25ee7552020-12-02 22:14:00 +01001684 install_lib_element_ve(&show_ns_cmd);
Harald Welte2fce19a2020-12-01 17:52:55 +01001685 install_lib_element_ve(&show_ns_binds_cmd);
1686 install_lib_element_ve(&show_ns_entities_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07001687 install_lib_element_ve(&show_ns_pers_cmd);
1688 install_lib_element_ve(&show_nse_cmd);
Daniel Willmann751977b2020-12-02 18:59:44 +01001689 install_lib_element_ve(&logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07001690 install_lib_element_ve(&logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02001691
Daniel Willmanndbab7142020-11-18 14:19:56 +01001692 install_lib_element(ENABLE_NODE, &nsvc_force_unconf_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001693 install_lib_element(ENABLE_NODE, &nsvc_block_cmd);
Daniel Willmanndbab7142020-11-18 14:19:56 +01001694
Daniel Willmann751977b2020-12-02 18:59:44 +01001695 install_lib_element(CFG_LOG_NODE, &logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07001696 install_lib_element(CFG_LOG_NODE, &logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02001697
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07001698 install_lib_element(CONFIG_NODE, &cfg_ns_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001699
Alexander Couzens6a161492020-07-12 13:45:50 +02001700 install_node(&ns_node, config_write_ns);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001701 /* TODO: convert into osmo timer */
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07001702 install_lib_element(L_NS_NODE, &cfg_ns_timer_cmd);
Alexander Couzense43b46e2021-01-27 21:52:08 +01001703
1704 return 0;
1705}
1706
1707int gprs_ns2_vty_init(struct gprs_ns2_inst *nsi)
1708{
1709 int rc = gprs_ns2_vty_init_reduced(nsi);
1710 if (rc)
1711 return rc;
1712
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001713 install_lib_element(L_NS_NODE, &cfg_ns_nsei_cmd);
1714 install_lib_element(L_NS_NODE, &cfg_no_ns_nsei_cmd);
1715 install_lib_element(L_NS_NODE, &cfg_ns_bind_cmd);
1716 install_lib_element(L_NS_NODE, &cfg_no_ns_bind_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02001717
Alexander Couzens260cd522021-01-28 20:31:31 +01001718 install_node(&ns_bind_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001719 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_listen_cmd);
1720 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_listen_cmd);
1721 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_dscp_cmd);
1722 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_dscp_cmd);
Alexander Couzensc4704762021-02-08 23:13:12 +01001723 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_ip_sns_weight_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001724 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_ipaccess_cmd);
1725 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_ipaccess_cmd);
1726 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_fr_cmd);
1727 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_fr_cmd);
1728 /* TODO: accept-ip-sns when SGSN SNS has been implemented */
Alexander Couzens6a161492020-07-12 13:45:50 +02001729
Alexander Couzens260cd522021-01-28 20:31:31 +01001730 install_node(&ns_nse_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001731 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_fr_cmd);
1732 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvci_cmd);
1733 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_fr_dlci_cmd);
1734 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_udp_cmd);
1735 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_udp_cmd);
1736 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_ipa_cmd);
1737 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_ipa_cmd);
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001738 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_remote_cmd);
1739 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_remote_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02001740
1741 return 0;
1742}