blob: c2b9bd9a4461155213d5db7bd1de2e0db7081112 [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;
69};
70
71/* TODO: this should into osmo timer */
Alexander Couzens6a161492020-07-12 13:45:50 +020072static const struct value_string gprs_ns_timer_strs[] = {
73 { 0, "tns-block" },
74 { 1, "tns-block-retries" },
75 { 2, "tns-reset" },
76 { 3, "tns-reset-retries" },
77 { 4, "tns-test" },
78 { 5, "tns-alive" },
79 { 6, "tns-alive-retries" },
80 { 7, "tsns-prov" },
Harald Welte33c3c062020-12-16 11:59:19 +010081 { 8, "tsns-size-retries" },
82 { 9, "tsns-config-retries" },
Alexander Couzens6a161492020-07-12 13:45:50 +020083 { 0, NULL }
84};
85
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010086const struct value_string vty_fr_role_names[] = {
87 { FR_ROLE_USER_EQUIPMENT, "fr" },
88 { FR_ROLE_NETWORK_EQUIPMENT, "frnet" },
89 { 0, NULL }
90};
91
92const struct value_string vty_ll_names[] = {
93 { GPRS_NS2_LL_FR, "fr" },
94 { GPRS_NS2_LL_FR_GRE, "frgre" },
95 { GPRS_NS2_LL_UDP, "udp" },
96 { 0, NULL }
97};
98
99static struct vty_bind *vty_bind_by_name(const char *name)
Daniel Willmann751977b2020-12-02 18:59:44 +0100100{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100101 struct vty_bind *vbind;
102 llist_for_each_entry(vbind, &binds, list) {
103 if (!strncmp(vbind->name, name, strlen(vbind->name)))
104 return vbind;
Daniel Willmann751977b2020-12-02 18:59:44 +0100105 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100106 return NULL;
Daniel Willmann751977b2020-12-02 18:59:44 +0100107}
108
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100109static struct vty_bind *vty_bind_alloc(const char *name)
Alexander Couzens6a161492020-07-12 13:45:50 +0200110{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100111 struct vty_bind *vbind = talloc_zero(vty_nsi, struct vty_bind);
112 if (!vbind)
113 return NULL;
114
115 vbind->name = talloc_strdup(vty_nsi, name);
116 if (!vbind->name) {
117 talloc_free(vbind);
118 return NULL;
Alexander Couzens6a161492020-07-12 13:45:50 +0200119 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100120
121 llist_add(&vbind->list, &binds);
122 return vbind;
123}
124
125static void vty_bind_free(struct vty_bind *vbind)
126{
127 if (!vbind)
128 return;
129
130 llist_del(&vbind->list);
Alexander Couzens6a161492020-07-12 13:45:50 +0200131}
132
133static struct cmd_node ns_node = {
134 L_NS_NODE,
135 "%s(config-ns)# ",
136 1,
137};
138
Alexander Couzens6a161492020-07-12 13:45:50 +0200139DEFUN(cfg_ns, cfg_ns_cmd,
140 "ns",
141 "Configure the GPRS Network Service")
142{
143 vty->node = L_NS_NODE;
144 return CMD_SUCCESS;
145}
146
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100147DEFUN(cfg_ns_timer, cfg_ns_timer_cmd,
148 "timer " NS_TIMERS " <0-65535>",
149 "Network Service Timer\n"
150 NS_TIMERS_HELP "Timer Value\n")
151{
152 int idx = get_string_value(gprs_ns_timer_strs, argv[0]);
153 int val = atoi(argv[1]);
154
155 if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout))
156 return CMD_WARNING;
157
158 vty_nsi->timeout[idx] = val;
159
160 return CMD_SUCCESS;
161}
162
163DEFUN(cfg_ns_nsei, cfg_ns_nsei_cmd,
164 "nse <0-65535>",
165 "Persistent NS Entity\n"
166 "NS Entity ID (NSEI)\n"
167 )
168{
169 struct gprs_ns2_nse *nse;
170 uint16_t nsei = atoi(argv[0]);
171
172 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
173 if (!nse) {
174 nse = gprs_ns2_create_nse(vty_nsi, nsei, GPRS_NS2_LL_UNDEF, GPRS_NS2_DIALECT_UNDEF);
175 if (!nse) {
176 vty_out(vty, "Failed to create NSE!%s", VTY_NEWLINE);
177 return CMD_ERR_INCOMPLETE;
178 }
179 nse->persistent = true;
180 }
181
182 if (!nse->persistent) {
183 /* TODO: should the dynamic NSE removed? */
184 vty_out(vty, "A dynamic NSE with the specified NSEI already exists%s", VTY_NEWLINE);
185 return CMD_ERR_INCOMPLETE;
186 }
187
188 vty->node = L_NS_NSE_NODE;
189 vty->index = nse;
190
191 return CMD_SUCCESS;
192}
193
194DEFUN(cfg_no_ns_nsei, cfg_no_ns_nsei_cmd,
195 "no nse <0-65535>",
196 NO_STR
197 "Delete a Persistent NS Entity\n"
198 "NS Entity ID (NSEI)\n"
199 )
200{
201 struct gprs_ns2_nse *nse;
202 uint16_t nsei = atoi(argv[0]);
203
204 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
205 if (!nse) {
206 vty_out(vty, "Can not find NS Entity %s%s", argv[0], VTY_NEWLINE);
207 return CMD_ERR_NOTHING_TODO;
208 }
209
210 if (!nse->persistent) {
211 vty_out(vty, "Ignoring non-persistent NS Entity%s", VTY_NEWLINE);
212 return CMD_WARNING;
213 }
214
215 vty_out(vty, "Deleting NS Entity %u%s", nse->nsei, VTY_NEWLINE);
216 gprs_ns2_free_nse(nse);
217 return CMD_SUCCESS;
218}
219
220/* TODO: add fr/gre */
221DEFUN(cfg_ns_bind, cfg_ns_bind_cmd,
222 "bind (fr|udp) ID",
223 "Binding\n"
224 "Frame Relay\n" "UDP/IP\n"
225 "a unique identifier for this bind to reference NS-VCs\n"
226 )
227{
228 const char *nstype = argv[0];
229 const char *name = argv[1];
230 struct vty_bind *vbind;
231 enum gprs_ns2_ll ll;
232 int rc;
233
234 rc = get_string_value(vty_ll_names, nstype);
235 if (rc < 0)
236 return CMD_WARNING;
237 ll = (enum gprs_ns2_ll) rc;
238
239 if (!osmo_identifier_valid(name)) {
240 vty_out(vty, "Invalid ID. The ID should be only alphanumeric.%s", VTY_NEWLINE);
241 return CMD_WARNING;
242 }
243
244 vbind = vty_bind_by_name(name);
245 if (vbind) {
246 if (vbind->ll != ll) {
247 vty_out(vty, "A bind with the specified ID already exists with a different type (fr|frgre|udp)!%s",
248 VTY_NEWLINE);
249 return CMD_WARNING;
250 }
251 } else {
252 vbind = vty_bind_alloc(name);
253 if (!vbind) {
254 vty_out(vty, "Can not create bind - out of memory%s", VTY_NEWLINE);
255 return CMD_WARNING;
256 }
257 vbind->ll = ll;
258 }
259
260 vty->index = vbind;
261 vty->node = L_NS_BIND_NODE;
262
263 return CMD_SUCCESS;
264}
265
266DEFUN(cfg_no_ns_bind, cfg_no_ns_bind_cmd,
267 "no bind ID",
268 NO_STR
269 "Delete a binding\n"
270 "a unique identifier for this bind to reference NS-VCs\n"
271 )
272{
273 struct vty_bind *vbind;
274 struct gprs_ns2_vc_bind *bind;
275 const char *name = argv[0];
276
277 vbind = vty_bind_by_name(name);
278 if (!vbind) {
279 vty_out(vty, "bind %s does not exist!%s", name, VTY_NEWLINE);
280 return CMD_WARNING;
281 }
282 vty_bind_free(vbind);
283 bind = gprs_ns2_bind_by_name(vty_nsi, name);
284 if (bind)
285 bind->driver->free_bind(bind);
286 return CMD_SUCCESS;
287}
288
289
290static void config_write_vbind(struct vty *vty, struct vty_bind *vbind)
291{
292 struct gprs_ns2_vc_bind *bind;
293 const struct osmo_sockaddr *addr;
294 struct osmo_sockaddr_str addr_str;
295 const char *netif, *frrole_str, *llstr;
296 enum osmo_fr_role frrole;
297
298 llstr = get_value_string_or_null(vty_ll_names, vbind->ll);
299 if (!llstr)
300 return;
301 vty_out(vty, " bind %s %s%s", llstr, vbind->name, VTY_NEWLINE);
302
303 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
304 switch (vbind->ll) {
305 case GPRS_NS2_LL_FR:
306 if (bind) {
307 netif = gprs_ns2_fr_bind_netif(bind);
308 if (!netif)
309 return;
310 frrole = gprs_ns2_fr_bind_role(bind);
311 if ((int) frrole == -1)
312 return;
313 frrole_str = get_value_string_or_null(vty_fr_role_names, frrole);
314 if (netif && frrole_str)
315 vty_out(vty, " fr %s %s%s", netif, frrole_str, VTY_NEWLINE);
316 }
317 break;
318 case GPRS_NS2_LL_UDP:
319 if (bind) {
320 addr = gprs_ns2_ip_bind_sockaddr(bind);
321 if (!osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas)) {
322 vty_out(vty, " listen %s %u%s", addr_str.ip, addr_str.port,
323 VTY_NEWLINE);
324 }
325 }
326 if (vbind->accept_ipaccess)
327 vty_out(vty, " accept-ipaccess%s", VTY_NEWLINE);
328 if (vbind->dscp)
329 vty_out(vty, " dscp %u%s", vbind->dscp, VTY_NEWLINE);
330 break;
331 default:
332 return;
333 }
334}
335
336static void config_write_nsvc(struct vty *vty, const struct gprs_ns2_vc *nsvc)
337{
338 const char *netif;
339 uint16_t dlci;
340 const struct osmo_sockaddr *addr;
341 struct osmo_sockaddr_str addr_str;
342
343 switch (nsvc->nse->ll) {
344 case GPRS_NS2_LL_UNDEF:
345 break;
346 case GPRS_NS2_LL_UDP:
347 switch (nsvc->nse->dialect) {
348 case GPRS_NS2_DIALECT_IPACCESS:
349 addr = gprs_ns2_ip_vc_remote(nsvc);
350 if (!addr)
351 break;
352 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas))
353 break;
354 vty_out(vty, " nsvc ipa %s %s %u nsvci %u%s",
355 nsvc->bind->name, addr_str.ip, addr_str.port,
356 nsvc->nsvci, VTY_NEWLINE);
357 break;
358 case GPRS_NS2_DIALECT_STATIC_ALIVE:
359 addr = gprs_ns2_ip_vc_remote(nsvc);
360 if (!addr)
361 break;
362 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas))
363 break;
364 vty_out(vty, " nsvc udp %s %s %u%s",
365 nsvc->bind->name, addr_str.ip, addr_str.port, VTY_NEWLINE);
366 break;
367 default:
368 break;
369 }
370 break;
371 case GPRS_NS2_LL_FR:
372 netif = gprs_ns2_fr_bind_netif(nsvc->bind);
373 if (!netif)
374 break;
375 dlci = gprs_ns2_fr_nsvc_dlci(nsvc);
376 if (!dlci)
377 break;
378 OSMO_ASSERT(nsvc->nsvci_is_valid);
379 vty_out(vty, " nsvc fr %s dlci %u nsvci %u%s",
380 netif, dlci, nsvc->nsvci, VTY_NEWLINE);
381 break;
382 case GPRS_NS2_LL_FR_GRE:
383 break;
384 }
385}
386
387static void _config_write_ns_nse(struct vty *vty, struct gprs_ns2_nse *nse)
388{
389 struct gprs_ns2_vc *nsvc;
390
391 vty_out(vty, " nse %u%s", nse->nsei, VTY_NEWLINE);
392 switch (nse->dialect) {
393 case GPRS_NS2_DIALECT_SNS:
394 ns2_sns_write_vty(vty, nse);
395 break;
396 default:
397 llist_for_each_entry(nsvc, &nse->nsvc, list) {
398 config_write_nsvc(vty, nsvc);
399 }
400 break;
401 }
402}
403
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100404static int config_write_ns_nse(struct vty *vty)
405{
406 struct gprs_ns2_nse *nse;
407
408 llist_for_each_entry(nse, &vty_nsi->nse, list) {
409 if (!nse->persistent)
410 continue;
411
412 _config_write_ns_nse(vty, nse);
413 }
414
415 return 0;
416}
417
418static int config_write_ns_bind(struct vty *vty)
419{
420 struct vty_bind *vbind;
421
422 llist_for_each_entry(vbind, &binds, list) {
423 config_write_vbind(vty, vbind);
424 }
425
426 return 0;
427}
428
Alexander Couzens260cd522021-01-28 20:31:31 +0100429static int config_write_ns(struct vty *vty)
430{
431 unsigned int i;
432 int ret;
433
434 vty_out(vty, "ns%s", VTY_NEWLINE);
435
436 for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++)
437 vty_out(vty, " timer %s %u%s",
438 get_value_string(gprs_ns_timer_strs, i),
439 vty_nsi->timeout[i], VTY_NEWLINE);
440
441 ret = config_write_ns_bind(vty);
442 if (ret)
443 return ret;
444
445 ret = config_write_ns_nse(vty);
446 if (ret)
447 return ret;
448
449 return 0;
450}
451
452
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100453static struct cmd_node ns_bind_node = {
454 L_NS_BIND_NODE,
455 "%s(config-ns-bind)# ",
456 1,
457};
458
459DEFUN(cfg_ns_bind_listen, cfg_ns_bind_listen_cmd,
460 "listen " VTY_IPV46_CMD " <1-65535>",
461 "Binding\n"
462 "IPv4 Address\n" "IPv6 Address\n"
463 "Port\n"
464 )
465{
466 struct vty_bind *vbind = vty->index;
467 struct gprs_ns2_vc_bind *bind;
468
469 const char *addr_str = argv[0];
470 unsigned int port = atoi(argv[1]);
471 struct osmo_sockaddr_str sockaddr_str;
472 struct osmo_sockaddr sockaddr;
473
474 if (vbind->ll != GPRS_NS2_LL_UDP) {
475 vty_out(vty, "listen can be only used with UDP bind%s",
476 VTY_NEWLINE);
477 return CMD_WARNING;
478 }
479
480 if (osmo_sockaddr_str_from_str(&sockaddr_str, addr_str, port)) {
481 vty_out(vty, "Can not parse the Address %s %s%s", argv[0], argv[1], VTY_NEWLINE);
482 return CMD_WARNING;
483 }
484 osmo_sockaddr_str_to_sockaddr(&sockaddr_str, &sockaddr.u.sas);
485 if (gprs_ns2_ip_bind_by_sockaddr(vty_nsi, &sockaddr)) {
486 vty_out(vty, "A bind with the specified address already exists!%s", VTY_NEWLINE);
487 return CMD_WARNING;
488 }
489
490 if (gprs_ns2_ip_bind(vty_nsi, vbind->name, &sockaddr, vbind->dscp, &bind) != 0) {
491 vty_out(vty, "Failed to create the bind!%s", VTY_NEWLINE);
492 return CMD_WARNING;
493 }
494
495 bind->accept_ipaccess = vbind->accept_ipaccess;
496 bind->accept_sns = vbind->accept_sns;
497
498 return CMD_SUCCESS;
499}
500
501DEFUN(cfg_no_ns_bind_listen, cfg_no_ns_bind_listen_cmd,
502 "no listen",
503 NO_STR
504 "Delete a IP/Port assignment\n"
505 )
506{
507 struct vty_bind *vbind = vty->index;
508 struct gprs_ns2_vc_bind *bind;
509
510 if (vbind->ll != GPRS_NS2_LL_UDP) {
511 vty_out(vty, "no listen can be only used with UDP bind%s", VTY_NEWLINE);
512 return CMD_WARNING;
513 }
514
515 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
516 if (!bind)
517 return CMD_ERR_NOTHING_TODO;
518
Daniel Willmann90432052021-01-26 16:09:18 +0100519 OSMO_ASSERT(bind->ll == GPRS_NS2_LL_UDP);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100520 bind->driver->free_bind(bind);
521 return CMD_SUCCESS;
522}
523
524DEFUN(cfg_ns_bind_dscp, cfg_ns_bind_dscp_cmd,
525 "dscp <0-255>",
526 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
527{
528 struct vty_bind *vbind = vty->index;
529 struct gprs_ns2_vc_bind *bind;
530 uint16_t dscp = atoi(argv[0]);
531
532 if (vbind->ll != GPRS_NS2_LL_UDP) {
533 vty_out(vty, "dscp can be only used with UDP bind%s",
534 VTY_NEWLINE);
535 return CMD_WARNING;
536 }
537
538 vbind->dscp = dscp;
539 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
540 if (bind)
541 gprs_ns2_ip_bind_set_dscp(bind, dscp);
542
543 return CMD_SUCCESS;
544}
545
546DEFUN(cfg_no_ns_bind_dscp, cfg_no_ns_bind_dscp_cmd,
547 "no dscp",
548 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
549{
550 struct vty_bind *vbind = vty->index;
551 struct gprs_ns2_vc_bind *bind;
552 uint16_t dscp = 0;
553
554 if (vbind->ll != GPRS_NS2_LL_UDP) {
555 vty_out(vty, "dscp can be only used with UDP bind%s",
556 VTY_NEWLINE);
557 return CMD_WARNING;
558 }
559
560 vbind->dscp = dscp;
561 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
562 if (bind)
563 gprs_ns2_ip_bind_set_dscp(bind, dscp);
564
565 return CMD_SUCCESS;
566}
567
568DEFUN(cfg_ns_bind_ipaccess, cfg_ns_bind_ipaccess_cmd,
569 "accept-ipaccess",
570 "Allow to create dynamic NS Entity by NS Reset PDU on UDP (ip.access style)\n"
571 )
572{
573 struct vty_bind *vbind = vty->index;
574 struct gprs_ns2_vc_bind *bind;
575
576 if (vbind->ll != GPRS_NS2_LL_UDP) {
577 vty_out(vty, "accept-ipaccess can be only used with UDP bind%s",
578 VTY_NEWLINE);
579 return CMD_WARNING;
580 }
581
582 vbind->accept_ipaccess = true;
583 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
584 if (bind)
585 bind->accept_ipaccess = true;
586
587 return CMD_SUCCESS;
588}
589
590DEFUN(cfg_no_ns_bind_ipaccess, cfg_no_ns_bind_ipaccess_cmd,
591 "no accept-ipaccess",
592 NO_STR
593 "Reject NS Reset PDU on UDP (ip.access style)\n"
594 )
595{
596 struct vty_bind *vbind = vty->index;
597 struct gprs_ns2_vc_bind *bind;
598
599 if (vbind->ll != GPRS_NS2_LL_UDP) {
600 vty_out(vty, "no accept-ipaccess can be only used with UDP bind%s",
601 VTY_NEWLINE);
602 return CMD_WARNING;
603 }
604
605 vbind->accept_ipaccess = false;
606 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
607 if (bind)
608 bind->accept_ipaccess = false;
609
610 return CMD_SUCCESS;
611}
612
613
614DEFUN(cfg_ns_bind_fr, cfg_ns_bind_fr_cmd,
615 "fr NETIF (fr|frnet)",
616 "frame relay\n"
617 IFNAME_STR
618 "fr (user) is used by BSS or SGSN attached to UNI of a FR network\n"
619 "frnet (network) is used by SGSN if BSS is directly attached\n"
620 )
621{
622 struct vty_bind *vbind = vty->index;
623 struct gprs_ns2_vc_bind *bind;
624 const char *netif = argv[0];
625 const char *role = argv[1];
626
627 int rc = 0;
628 enum osmo_fr_role frrole;
629
630 if (vbind->ll != GPRS_NS2_LL_FR) {
631 vty_out(vty, "fr can be only used with frame relay bind%s", VTY_NEWLINE);
632 return CMD_WARNING;
633 }
634
635 if (!strcmp(role, "fr"))
636 frrole = FR_ROLE_USER_EQUIPMENT;
637 else if (!strcmp(role, "frnet"))
638 frrole = FR_ROLE_NETWORK_EQUIPMENT;
639 else
640 return CMD_WARNING;
641
642 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
643 if (bind) {
644 vty_out(vty, "Interface %s already used.%s", netif, VTY_NEWLINE);
645 return CMD_WARNING;
646 }
647
648 rc = gprs_ns2_fr_bind(vty_nsi, vbind->name, netif, vty_fr_network, frrole, &bind);
649 if (rc < 0) {
650 LOGP(DLNS, LOGL_ERROR, "Failed to bind interface %s on fr. Err: %d\n", netif, rc);
651 return CMD_WARNING;
652 }
653
654 return CMD_SUCCESS;
655}
656
657DEFUN(cfg_no_ns_bind_fr, cfg_no_ns_bind_fr_cmd,
658 "no fr NETIF",
659 NO_STR
660 "Delete a frame relay link\n"
661 "Delete a frame relay link\n"
662 IFNAME_STR
663 )
664{
665 struct vty_bind *vbind = vty->index;
666 struct gprs_ns2_vc_bind *bind;
667 const char *netif = argv[0];
668
669 if (vbind->ll != GPRS_NS2_LL_FR) {
670 vty_out(vty, "fr can be only used with frame relay bind%s",
671 VTY_NEWLINE);
672 return CMD_WARNING;
673 }
674
675 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
676 if (!bind) {
677 vty_out(vty, "Interface not found.%s", VTY_NEWLINE);
678 return CMD_WARNING;
679 }
680
681 if (strcmp(bind->name, vbind->name)) {
682 vty_out(vty, "The specified interface is not bound to this bind.%s", VTY_NEWLINE);
683 return CMD_WARNING;
684 }
685
686 bind->driver->free_bind(bind);
687 return CMD_SUCCESS;
688}
689
690
691static struct cmd_node ns_nse_node = {
692 L_NS_NSE_NODE,
693 "%s(config-ns-nse)# ",
694 1,
695};
696
697DEFUN(cfg_ns_nse_nsvc_fr, cfg_ns_nse_nsvc_fr_cmd,
698 "nsvc fr NETIF dlci <16-1007> nsvci <0-65535>",
699 "NS Virtual Connection\n"
700 "frame relay\n"
701 "frame relay interface. Must be registered via fr vty\n"
702 NSVCI_STR
703 NSVCI_STR
704 DLCI_STR
705 DLCI_STR
706 )
707{
708 struct gprs_ns2_vc_bind *bind;
709 struct gprs_ns2_vc *nsvc;
710 struct gprs_ns2_nse *nse = vty->index;
711 const char *netif = argv[0];
712 uint16_t dlci = atoi(argv[1]);
713 uint16_t nsvci = atoi(argv[2]);
714 bool dialect_modified = false;
715 bool ll_modified = false;
716
717 if (nse->ll != GPRS_NS2_LL_FR && nse->ll != GPRS_NS2_LL_UNDEF) {
718 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
719 goto err;
720 }
721
722 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_RESETBLOCK && nse->dialect != GPRS_NS2_DIALECT_UNDEF) {
723 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
724 goto err;
725 }
726
727 if (nse->ll == GPRS_NS2_LL_UNDEF) {
728 nse->ll = GPRS_NS2_LL_FR;
729 ll_modified = true;
730 }
731
732 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
733 nse->dialect = GPRS_NS2_DIALECT_STATIC_RESETBLOCK;
734 dialect_modified = true;
735 }
736
737
738 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
739 if (!bind) {
740 vty_out(vty, "Can not find fr interface \"%s\". Please configure it via fr vty.%s",
741 netif, VTY_NEWLINE);
742 goto err;
743 }
744
745 if (gprs_ns2_fr_nsvc_by_dlci(bind, dlci)) {
746 vty_out(vty, "A NS-VC with the specified DLCI already exist!%s", VTY_NEWLINE);
747 goto err;
748 }
749
750 if (gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci)) {
751 vty_out(vty, "A NS-VC with the specified NS-VCI already exist!%s", VTY_NEWLINE);
752 goto err;
753 }
754
755 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
756 if (!nsvc) {
757 /* Could not create NS-VC, connect failed */
758 vty_out(vty, "Failed to create the NS-VC%s", VTY_NEWLINE);
759 goto err;
760 }
761 nsvc->persistent = true;
762 return CMD_SUCCESS;
763
764err:
765 if (ll_modified)
766 nse->ll = GPRS_NS2_LL_UNDEF;
767 if (dialect_modified)
768 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
769
770 return CMD_WARNING;
771}
772
773DEFUN(cfg_no_ns_nse_nsvc_fr_dlci, cfg_no_ns_nse_nsvc_fr_dlci_cmd,
774 "no nsvc fr NETIF dlci <16-1007>",
775 NO_STR
776 "Delete frame relay NS-VC\n"
777 "frame relay\n"
778 "frame relay interface. Must be registered via fr vty\n"
779 DLCI_STR
780 DLCI_STR
781 )
782{
783 struct gprs_ns2_vc_bind *bind;
784 struct gprs_ns2_vc *nsvc;
785 struct gprs_ns2_nse *nse = vty->index;
786 const char *netif = argv[0];
787 uint16_t dlci = atoi(argv[1]);
788
789 if (nse->ll != GPRS_NS2_LL_FR) {
790 vty_out(vty, "This NSE doesn't support frame relay.%s", VTY_NEWLINE);
791 return CMD_WARNING;
792 }
793
794 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
795 if (!bind) {
796 vty_out(vty, "Can not find fr interface \"%s\"%s",
797 netif, VTY_NEWLINE);
798 return CMD_ERR_NOTHING_TODO;
799 }
800
801 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
802 if (!nsvc) {
803 vty_out(vty, "Can not find a NS-VC on fr interface %s with dlci %u%s",
804 netif, dlci, VTY_NEWLINE);
805 return CMD_WARNING;
806 }
807
808 if (nse != nsvc->nse) {
809 vty_out(vty, "The specified NS-VC is not a part of the NSE %u!%s"
810 "To remove this NS-VC go to the vty node 'nse %u'%s",
811 nse->nsei, VTY_NEWLINE,
812 nsvc->nse->nsei, VTY_NEWLINE);
813 return CMD_WARNING;
814 }
815
816 gprs_ns2_free_nsvc(nsvc);
817 if (llist_empty(&nse->nsvc)) {
818 nse->ll = GPRS_NS2_LL_UNDEF;
819 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
820 }
821
822 return CMD_SUCCESS;
823}
824
825DEFUN(cfg_no_ns_nse_nsvci, cfg_no_ns_nse_nsvci_cmd,
826 "no nsvc nsvci <0-65535>",
827 NO_STR
828 "Delete NSVC\n"
829 NSVCI_STR
830 NSVCI_STR
831 )
832{
833 struct gprs_ns2_vc *nsvc;
834 struct gprs_ns2_nse *nse = vty->index;
835 uint16_t nsvci = atoi(argv[0]);
836
837 switch (nse->dialect) {
838 case GPRS_NS2_DIALECT_SNS:
839 case GPRS_NS2_DIALECT_STATIC_ALIVE:
840 vty_out(vty, "NSE doesn't support NSVCI.%s", VTY_NEWLINE);
841 return CMD_WARNING;
842 case GPRS_NS2_DIALECT_UNDEF:
843 vty_out(vty, "No NSVCs configured%s", VTY_NEWLINE);
844 return CMD_WARNING;
845 case GPRS_NS2_DIALECT_IPACCESS:
846 case GPRS_NS2_DIALECT_STATIC_RESETBLOCK:
847 break;
848 }
849
850 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci);
851 if (!nsvc) {
852 vty_out(vty, "Can not find NS-VC with NS-VCI %u%s", nsvci, VTY_NEWLINE);
853 return CMD_WARNING;
854 }
855
856 if (nse != nsvc->nse) {
857 vty_out(vty, "NS-VC with NS-VCI %u is not part of this NSE!%s",
858 nsvci, VTY_NEWLINE);
859 return CMD_WARNING;
860 }
861
862 gprs_ns2_free_nsvc(nsvc);
863 if (llist_empty(&nse->nsvc)) {
864 nse->ll = GPRS_NS2_LL_UNDEF;
865 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
866 }
867
868 return CMD_SUCCESS;
869}
870
871DEFUN(cfg_ns_nse_nsvc_udp, cfg_ns_nse_nsvc_udp_cmd,
872 "nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
873 "NS Virtual Connection\n"
874 "NS over UDP\n"
875 "A unique bind identifier created by ns bind\n"
876 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
877 "Remote UDP Port\n"
878 )
879{
880 struct gprs_ns2_vc_bind *bind;
881 struct gprs_ns2_vc *nsvc;
882 struct gprs_ns2_nse *nse = vty->index;
883 bool dialect_modified = false;
884 bool ll_modified = false;
885
886 const char *bind_name = argv[0];
887 struct osmo_sockaddr_str remote_str;
888 struct osmo_sockaddr remote;
889 uint16_t port = atoi(argv[2]);
890
891 if (nse->ll == GPRS_NS2_LL_UNDEF) {
892 nse->ll = GPRS_NS2_LL_UDP;
893 ll_modified = true;
894 }
895
896 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
897 nse->dialect = GPRS_NS2_DIALECT_STATIC_ALIVE;
898 dialect_modified = true;
899 }
900
901 if (nse->ll != GPRS_NS2_LL_UDP) {
902 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
903 goto err;
904 }
905
906 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
907 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
908 goto err;
909 }
910
911 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
912 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
913 goto err;
914 }
915
916 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
917 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
918 goto err;
919 }
920
921 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
922 if (!bind) {
923 vty_out(vty, "Can not find bind with name %s%s",
924 bind_name, VTY_NEWLINE);
925 goto err;
926 }
927
928 if (bind->ll != GPRS_NS2_LL_UDP) {
929 vty_out(vty, "Bind %s is not an UDP bind.%s",
930 bind_name, VTY_NEWLINE);
931 goto err;
932 }
933
934 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, 0);
935 if (!nsvc) {
936 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
937 goto err;
938 }
939 nsvc->persistent = true;
940
941 return CMD_SUCCESS;
942
943err:
944 if (ll_modified)
945 nse->ll = GPRS_NS2_LL_UNDEF;
946 if (dialect_modified)
947 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
948 return CMD_WARNING;
949}
950
951DEFUN(cfg_no_ns_nse_nsvc_udp, cfg_no_ns_nse_nsvc_udp_cmd,
952 "no nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
953 NO_STR
954 "Delete a NS Virtual Connection\n"
955 "NS over UDP\n"
956 "A unique bind identifier created by ns bind\n"
957 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
958 "Remote UDP Port\n"
959 )
960{
961 struct gprs_ns2_vc_bind *bind;
962 struct gprs_ns2_vc *nsvc;
963 struct gprs_ns2_nse *nse = vty->index;
964 const char *bind_name = argv[0];
965 struct osmo_sockaddr_str remote_str;
966 struct osmo_sockaddr remote;
967 uint16_t port = atoi(argv[2]);
968
969 if (nse->ll != GPRS_NS2_LL_UDP) {
970 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
971 return CMD_WARNING;
972 }
973
974 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
975 vty_out(vty, "This NSE doesn't support UDP with dialect static alive.%s", VTY_NEWLINE);
976 return CMD_WARNING;
977 }
978
979 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
980 if (!bind) {
981 vty_out(vty, "Can not find bind with name %s%s",
982 bind_name, VTY_NEWLINE);
983 return CMD_WARNING;
984 }
985
986 if (bind->ll != GPRS_NS2_LL_UDP) {
987 vty_out(vty, "Bind %s is not an UDP bind.%s",
988 bind_name, VTY_NEWLINE);
989 return CMD_WARNING;
990 }
991
992 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
993 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
994 return CMD_WARNING;
995 }
996
997 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
998 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
999 return CMD_WARNING;
1000 }
1001
1002 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1003 if (!nsvc) {
1004 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1005 remote_str.ip, remote_str.port, VTY_NEWLINE);
1006 return CMD_WARNING;
1007 }
1008
1009 if (!nsvc->persistent) {
1010 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1011 remote_str.ip, remote_str.port, VTY_NEWLINE);
1012 return CMD_WARNING;
1013 }
1014
1015 if (nsvc->nse != nse) {
1016 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1017 return CMD_WARNING;
1018 }
1019
1020 gprs_ns2_free_nsvc(nsvc);
1021 if (llist_empty(&nse->nsvc)) {
1022 nse->ll = GPRS_NS2_LL_UNDEF;
1023 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1024 }
1025
1026 return CMD_SUCCESS;
1027}
1028
1029DEFUN(cfg_ns_nse_nsvc_ipa, cfg_ns_nse_nsvc_ipa_cmd,
1030 "nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>" ,
1031 "NS Virtual Connection\n"
1032 "NS over UDP ip.access style (uses RESET/BLOCK)\n"
1033 "A unique bind identifier created by ns bind\n"
1034 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1035 "Remote UDP Port\n"
1036 NSVCI_STR
1037 NSVCI_STR
1038 )
1039{
1040 struct gprs_ns2_vc_bind *bind;
1041 struct gprs_ns2_vc *nsvc;
1042 struct gprs_ns2_nse *nse = vty->index;
1043 bool dialect_modified = false;
1044 bool ll_modified = false;
1045
1046 const char *bind_name = argv[0];
1047 struct osmo_sockaddr_str remote_str;
1048 struct osmo_sockaddr remote;
1049 uint16_t port = atoi(argv[2]);
1050 uint16_t nsvci = atoi(argv[3]);
1051
1052 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1053 nse->ll = GPRS_NS2_LL_UDP;
1054 ll_modified = true;
1055 }
1056
1057 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
1058 nse->dialect = GPRS_NS2_DIALECT_IPACCESS;
1059 dialect_modified = true;
1060 }
1061
1062 if (nse->ll != GPRS_NS2_LL_UDP) {
1063 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1064 goto err;
1065 }
1066
1067 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1068 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1069 goto err;
1070 }
1071
1072 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1073 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1074 goto err;
1075 }
1076
1077 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1078 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1079 goto err;
1080 }
1081
1082 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1083 if (!bind) {
1084 vty_out(vty, "Can not find bind with name %s%s",
1085 bind_name, VTY_NEWLINE);
1086 goto err;
1087 }
1088
1089 if (bind->ll != GPRS_NS2_LL_UDP) {
1090 vty_out(vty, "Bind %s is not an UDP bind.%s",
1091 bind_name, VTY_NEWLINE);
1092 goto err;
1093 }
1094
1095 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, nsvci);
1096 if (!nsvc) {
1097 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
1098 goto err;
1099 }
1100 nsvc->persistent = true;
1101
1102 return CMD_SUCCESS;
1103
1104err:
1105 if (ll_modified)
1106 nse->ll = GPRS_NS2_LL_UNDEF;
1107 if (dialect_modified)
1108 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1109 return CMD_WARNING;
1110}
1111
1112DEFUN(cfg_no_ns_nse_nsvc_ipa, cfg_no_ns_nse_nsvc_ipa_cmd,
1113 "no nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>",
1114 NO_STR
1115 "Delete a NS Virtual Connection\n"
1116 "NS over UDP\n"
1117 "A unique bind identifier created by ns bind\n"
1118 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1119 "Remote UDP Port\n"
1120 NSVCI_STR
1121 NSVCI_STR
1122 )
1123{
1124 struct gprs_ns2_vc_bind *bind;
1125 struct gprs_ns2_vc *nsvc;
1126 struct gprs_ns2_nse *nse = vty->index;
1127 const char *bind_name = argv[0];
1128 struct osmo_sockaddr_str remote_str;
1129 struct osmo_sockaddr remote;
1130 uint16_t port = atoi(argv[2]);
1131 uint16_t nsvci = atoi(argv[3]);
1132
1133 if (nse->ll != GPRS_NS2_LL_UDP) {
1134 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1135 return CMD_WARNING;
1136 }
1137
1138 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1139 vty_out(vty, "This NSE doesn't support UDP with dialect ipaccess.%s", VTY_NEWLINE);
1140 return CMD_WARNING;
1141 }
1142
1143 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1144 if (!bind) {
1145 vty_out(vty, "Can not find bind with name %s%s",
1146 bind_name, VTY_NEWLINE);
1147 return CMD_WARNING;
1148 }
1149
1150 if (bind->ll != GPRS_NS2_LL_UDP) {
1151 vty_out(vty, "Bind %s is not an UDP bind.%s",
1152 bind_name, VTY_NEWLINE);
1153 return CMD_WARNING;
1154 }
1155
1156 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1157 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1158 return CMD_WARNING;
1159 }
1160
1161 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1162 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1163 return CMD_WARNING;
1164 }
1165
1166 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1167 if (!nsvc) {
1168 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1169 remote_str.ip, remote_str.port, VTY_NEWLINE);
1170 return CMD_WARNING;
1171 }
1172
1173 if (!nsvc->persistent) {
1174 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1175 remote_str.ip, remote_str.port, VTY_NEWLINE);
1176 return CMD_WARNING;
1177 }
1178
1179 if (nsvc->nse != nse) {
1180 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1181 return CMD_WARNING;
1182 }
1183
1184 if (!nsvc->nsvci_is_valid) {
1185 vty_out(vty, "NS-VC doesn't have a nsvci!%s", VTY_NEWLINE);
1186 return CMD_WARNING;
1187 }
1188
1189 if (nsvc->nsvci != nsvci) {
1190 vty_out(vty, "NS-VC has a different nsvci (%u)!%s",
1191 nsvc->nsvci, VTY_NEWLINE);
1192 return CMD_WARNING;
1193 }
1194
1195 gprs_ns2_free_nsvc(nsvc);
1196 if (llist_empty(&nse->nsvc)) {
1197 nse->ll = GPRS_NS2_LL_UNDEF;
1198 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1199 }
1200
1201 return CMD_SUCCESS;
1202}
1203
1204DEFUN(cfg_ns_nse_ip_sns, cfg_ns_nse_ip_sns_cmd,
1205 "ip-sns " VTY_IPV46_CMD " <1-65535>",
1206 "SNS Initial Endpoint\n"
1207 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1208 "SGSN UDP Port\n"
1209 )
1210{
1211 struct gprs_ns2_nse *nse = vty->index;
1212 bool dialect_modified = false;
1213 bool ll_modified = false;
1214 int rc;
1215
1216 /* argv[0] */
1217 struct osmo_sockaddr_str remote_str;
1218 struct osmo_sockaddr remote;
1219 uint16_t port = atoi(argv[1]);
1220
1221 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1222 nse->ll = GPRS_NS2_LL_UDP;
1223 ll_modified = true;
1224 }
1225
1226 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
1227 char sns[16];
1228 snprintf(sns, sizeof(sns), "NSE%05u-SNS", nse->nsei);
1229 nse->bss_sns_fi = ns2_sns_bss_fsm_alloc(nse, sns);
1230 if (!nse->bss_sns_fi)
1231 goto err;
1232 nse->dialect = GPRS_NS2_DIALECT_SNS;
1233 dialect_modified = true;
1234 }
1235
1236 if (nse->ll != GPRS_NS2_LL_UDP) {
1237 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1238 goto err;
1239 }
1240
1241 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1242 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1243 goto err;
1244 }
1245
1246 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1247 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1248 goto err;
1249 }
1250
1251 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1252 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1253 goto err;
1254 }
1255
1256 rc = gprs_ns2_sns_add_endpoint(nse, &remote);
1257 switch (rc) {
1258 case 0:
1259 return CMD_SUCCESS;
1260 case -EADDRINUSE:
1261 vty_out(vty, "Specified SNS endpoint already part of the NSE.%s", VTY_NEWLINE);
1262 return CMD_WARNING;
1263 default:
1264 vty_out(vty, "Can not add specified SNS endpoint.%s", VTY_NEWLINE);
1265 return CMD_WARNING;
1266 }
1267
1268err:
1269 if (ll_modified)
1270 nse->ll = GPRS_NS2_LL_UNDEF;
1271 if (dialect_modified)
1272 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1273 return CMD_WARNING;
1274}
1275
1276DEFUN(cfg_no_ns_nse_ip_sns, cfg_no_ns_nse_ip_sns_cmd,
1277 "no ip-sns " VTY_IPV46_CMD " <1-65535>",
1278 NO_STR
1279 "Delete a SNS Initial Endpoint\n"
1280 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1281 "SGSN UDP Port\n"
1282 )
1283{
1284 struct gprs_ns2_nse *nse = vty->index;
1285 struct osmo_sockaddr_str remote_str; /* argv[0] */
1286 struct osmo_sockaddr remote;
1287 uint16_t port = atoi(argv[1]);
1288 int count;
1289
1290 if (nse->ll != GPRS_NS2_LL_UDP) {
1291 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1292 return CMD_WARNING;
1293 }
1294
1295 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1296 vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%s", VTY_NEWLINE);
1297 return CMD_WARNING;
1298 }
1299
1300 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1301 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1302 return CMD_WARNING;
1303 }
1304
1305 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1306 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1307 return CMD_WARNING;
1308 }
1309
1310 if (gprs_ns2_sns_del_endpoint(nse, &remote)) {
1311 vty_out(vty, "Can not remove specified SNS endpoint.%s", VTY_NEWLINE);
1312 return CMD_WARNING;
1313 }
1314
1315 count = gprs_ns2_sns_count(nse);
1316 if (count > 0) {
1317 /* there are other sns endpoints */
1318 return CMD_SUCCESS;
1319 } else if (count < 0) {
1320 OSMO_ASSERT(0);
1321 } else {
1322 /* clean up nse to allow other nsvc commands */
1323 osmo_fsm_inst_term(nse->bss_sns_fi, OSMO_FSM_TERM_REQUEST, NULL);
1324 nse->bss_sns_fi = NULL;
1325 nse->ll = GPRS_NS2_LL_UNDEF;
1326 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1327 }
1328
1329 return CMD_SUCCESS;
1330}
1331
1332
1333/* non-config commands */
Alexander Couzens6a161492020-07-12 13:45:50 +02001334static void dump_nsvc(struct vty *vty, struct gprs_ns2_vc *nsvc, bool stats)
1335{
Harald Weltedc2d0802020-12-01 18:17:28 +01001336 char nsvci_str[32];
1337
1338 if (nsvc->nsvci_is_valid)
1339 snprintf(nsvci_str, sizeof(nsvci_str), "%05u", nsvc->nsvci);
1340 else
1341 snprintf(nsvci_str, sizeof(nsvci_str), "none");
1342
1343 vty_out(vty, " NSVCI %s: %s %s data_weight=%u sig_weight=%u %s%s", nsvci_str,
1344 osmo_fsm_inst_state_name(nsvc->fi),
1345 nsvc->persistent ? "PERSIST" : "DYNAMIC",
1346 nsvc->data_weight, nsvc->sig_weight,
1347 gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001348
1349 if (stats) {
Harald Welte7aa60992020-12-01 17:53:17 +01001350 vty_out_rate_ctr_group(vty, " ", nsvc->ctrg);
1351 vty_out_stat_item_group(vty, " ", nsvc->statg);
Alexander Couzens6a161492020-07-12 13:45:50 +02001352 }
1353}
1354
1355static void dump_nse(struct vty *vty, const struct gprs_ns2_nse *nse, bool stats, bool persistent_only)
1356{
1357 struct gprs_ns2_vc *nsvc;
1358
Harald Welte0ff12ad2020-12-01 17:51:07 +01001359 vty_out(vty, "NSEI %05u: %s, %s%s", nse->nsei, gprs_ns2_lltype_str(nse->ll),
1360 nse->alive ? "ALIVE" : "DEAD", VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001361
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001362 ns2_sns_dump_vty(vty, " ", nse, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001363 llist_for_each_entry(nsvc, &nse->nsvc, list) {
1364 if (persistent_only) {
1365 if (nsvc->persistent)
1366 dump_nsvc(vty, nsvc, stats);
1367 } else {
1368 dump_nsvc(vty, nsvc, stats);
1369 }
1370 }
1371}
1372
Alexander Couzens22f34712020-10-02 02:34:39 +02001373static void dump_bind(struct vty *vty, const struct gprs_ns2_vc_bind *bind, bool stats)
1374{
1375 if (bind->dump_vty)
1376 bind->dump_vty(bind, vty, stats);
1377}
1378
Harald Welte2fce19a2020-12-01 17:52:55 +01001379static void dump_ns_bind(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats)
Alexander Couzens6a161492020-07-12 13:45:50 +02001380{
Alexander Couzens22f34712020-10-02 02:34:39 +02001381 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6a161492020-07-12 13:45:50 +02001382
Alexander Couzens22f34712020-10-02 02:34:39 +02001383 llist_for_each_entry(bind, &nsi->binding, list) {
1384 dump_bind(vty, bind, stats);
1385 }
Harald Welte2fce19a2020-12-01 17:52:55 +01001386}
1387
1388
1389static void dump_ns_entities(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats, bool persistent_only)
1390{
1391 struct gprs_ns2_nse *nse;
Alexander Couzens22f34712020-10-02 02:34:39 +02001392
Alexander Couzens6a161492020-07-12 13:45:50 +02001393 llist_for_each_entry(nse, &nsi->nse, list) {
1394 dump_nse(vty, nse, stats, persistent_only);
Alexander Couzens6a161492020-07-12 13:45:50 +02001395 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001396}
1397
Harald Welte25ee7552020-12-02 22:14:00 +01001398/* Backwards compatibility, among other things for the TestVTYGbproxy which expects
1399 * 'show ns' to output something about binds */
1400DEFUN_HIDDEN(show_ns, show_ns_cmd, "show ns",
1401 SHOW_STR SHOW_NS_STR)
1402{
1403 dump_ns_entities(vty, vty_nsi, false, false);
1404 dump_ns_bind(vty, vty_nsi, false);
1405 return CMD_SUCCESS;
1406}
1407
1408
Harald Welte2fce19a2020-12-01 17:52:55 +01001409DEFUN(show_ns_binds, show_ns_binds_cmd, "show ns binds [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001410 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01001411 "Display information about the NS protocol binds\n"
1412 "Include statistic\n")
Alexander Couzens6a161492020-07-12 13:45:50 +02001413{
Harald Welte2fce19a2020-12-01 17:52:55 +01001414 bool stats = false;
1415 if (argc > 0)
1416 stats = true;
1417
1418 dump_ns_bind(vty, vty_nsi, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001419 return CMD_SUCCESS;
1420}
1421
Harald Welte2fce19a2020-12-01 17:52:55 +01001422DEFUN(show_ns_entities, show_ns_entities_cmd, "show ns entities [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001423 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01001424 "Display information about the NS protocol entities (NSEs)\n"
Alexander Couzens6a161492020-07-12 13:45:50 +02001425 "Include statistics\n")
1426{
Harald Welte2fce19a2020-12-01 17:52:55 +01001427 bool stats = false;
1428 if (argc > 0)
1429 stats = true;
1430
1431 dump_ns_entities(vty, vty_nsi, stats, false);
Alexander Couzens6a161492020-07-12 13:45:50 +02001432 return CMD_SUCCESS;
1433}
1434
1435DEFUN(show_ns_pers, show_ns_pers_cmd, "show ns persistent",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001436 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02001437 "Show only persistent NS\n")
1438{
Harald Welte2fce19a2020-12-01 17:52:55 +01001439 dump_ns_entities(vty, vty_nsi, true, true);
Alexander Couzens6a161492020-07-12 13:45:50 +02001440 return CMD_SUCCESS;
1441}
1442
1443DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001444 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02001445 "Select one NSE by its NSE Identifier\n"
1446 "Select one NSE by its NS-VC Identifier\n"
1447 "The Identifier of selected type\n"
1448 "Include Statistics\n")
1449{
1450 struct gprs_ns2_inst *nsi = vty_nsi;
1451 struct gprs_ns2_nse *nse;
1452 struct gprs_ns2_vc *nsvc;
1453 uint16_t id = atoi(argv[1]);
1454 bool show_stats = false;
1455
1456 if (argc >= 3)
1457 show_stats = true;
1458
1459 if (!strcmp(argv[0], "nsei")) {
1460 nse = gprs_ns2_nse_by_nsei(nsi, id);
1461 if (!nse) {
1462 return CMD_WARNING;
1463 }
1464
1465 dump_nse(vty, nse, show_stats, false);
1466 } else {
1467 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
1468
1469 if (!nsvc) {
1470 vty_out(vty, "No such NS Entity%s", VTY_NEWLINE);
1471 return CMD_WARNING;
1472 }
1473
1474 dump_nsvc(vty, nsvc, show_stats);
1475 }
1476
1477 return CMD_SUCCESS;
1478}
1479
Daniel Willmanndbab7142020-11-18 14:19:56 +01001480static int nsvc_force_unconf_cb(struct gprs_ns2_vc *nsvc, void *ctx)
1481{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001482 ns2_vc_force_unconfigured(nsvc);
Daniel Willmanndbab7142020-11-18 14:19:56 +01001483 return 0;
1484}
1485
1486DEFUN_HIDDEN(nsvc_force_unconf, nsvc_force_unconf_cmd,
1487 "nsvc nsei <0-65535> force-unconfigured",
1488 "NS Virtual Connection\n"
1489 "The NSEI\n"
1490 "Reset the NSVCs back to initial state\n"
1491 )
1492{
1493 struct gprs_ns2_inst *nsi = vty_nsi;
1494 struct gprs_ns2_nse *nse;
1495
1496 uint16_t id = atoi(argv[0]);
1497
1498 nse = gprs_ns2_nse_by_nsei(nsi, id);
1499 if (!nse) {
1500 vty_out(vty, "Could not find NSE for NSEI %u%s", id, VTY_NEWLINE);
1501 return CMD_WARNING;
1502 }
1503
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001504 if (!nse->persistent) {
1505 gprs_ns2_free_nse(nse);
1506 } else if (nse->dialect == GPRS_NS2_DIALECT_SNS) {
Alexander Couzens280ed782020-12-21 18:25:41 +01001507 gprs_ns2_free_nsvcs(nse);
1508 } else {
1509 /* Perform the operation for all nsvc */
1510 gprs_ns2_nse_foreach_nsvc(nse, nsvc_force_unconf_cb, NULL);
1511 }
Daniel Willmanndbab7142020-11-18 14:19:56 +01001512
1513 return CMD_SUCCESS;
1514}
1515
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001516DEFUN(nsvc_block, nsvc_block_cmd,
1517 "nsvc <0-65535> (block|unblock)",
1518 "NS Virtual Connection\n"
1519 NSVCI_STR
1520 "Block a NSVC. As cause code O&M intervention will be used.\n"
1521 "Unblock a NSVC. As cause code O&M intervention will be used.\n")
Alexander Couzens841817e2020-11-19 00:41:29 +01001522{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001523 struct gprs_ns2_inst *nsi = vty_nsi;
1524 struct gprs_ns2_vc *nsvc;
Alexander Couzens841817e2020-11-19 00:41:29 +01001525
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001526 uint16_t id = atoi(argv[0]);
Alexander Couzens841817e2020-11-19 00:41:29 +01001527
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001528 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
1529 if (!nsvc) {
1530 vty_out(vty, "Could not find NSVCI %05u%s", id, VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +01001531 return CMD_WARNING;
1532 }
1533
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001534 if (!strcmp(argv[1], "block")) {
1535 ns2_vc_block(nsvc);
1536 } else {
1537 ns2_vc_unblock(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +02001538 }
1539
1540 return CMD_SUCCESS;
1541}
1542
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001543static void log_set_nse_filter(struct log_target *target,
1544 struct gprs_ns2_nse *nse)
Alexander Couzens6a161492020-07-12 13:45:50 +02001545{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001546 if (nse) {
1547 target->filter_map |= (1 << LOG_FLT_GB_NSE);
1548 target->filter_data[LOG_FLT_GB_NSE] = nse;
1549 } else if (target->filter_data[LOG_FLT_GB_NSE]) {
1550 target->filter_map = ~(1 << LOG_FLT_GB_NSE);
1551 target->filter_data[LOG_FLT_GB_NSE] = NULL;
1552 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001553}
1554
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001555static void log_set_nsvc_filter(struct log_target *target,
1556 struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +02001557{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001558 if (nsvc) {
1559 target->filter_map |= (1 << LOG_FLT_GB_NSVC);
1560 target->filter_data[LOG_FLT_GB_NSVC] = nsvc;
1561 } else if (target->filter_data[LOG_FLT_GB_NSVC]) {
1562 target->filter_map = ~(1 << LOG_FLT_GB_NSVC);
1563 target->filter_data[LOG_FLT_GB_NSVC] = NULL;
1564 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001565}
1566
Daniel Willmann751977b2020-12-02 18:59:44 +01001567DEFUN(logging_fltr_nse,
1568 logging_fltr_nse_cmd,
1569 "logging filter nse nsei <0-65535>",
1570 LOGGING_STR FILTER_STR
1571 "Filter based on NS Entity\n"
1572 "Identify NSE by NSEI\n"
1573 "Numeric identifier\n")
1574{
1575 struct log_target *tgt;
1576 struct gprs_ns2_nse *nse;
Daniel Willmann89106522020-12-04 01:36:59 +01001577 uint16_t id = atoi(argv[0]);
Daniel Willmann751977b2020-12-02 18:59:44 +01001578
1579 log_tgt_mutex_lock();
1580 tgt = osmo_log_vty2tgt(vty);
1581 if (!tgt) {
1582 log_tgt_mutex_unlock();
1583 return CMD_WARNING;
1584 }
1585
1586 nse = gprs_ns2_nse_by_nsei(vty_nsi, id);
1587 if (!nse) {
1588 vty_out(vty, "No NSE by that identifier%s", VTY_NEWLINE);
1589 log_tgt_mutex_unlock();
1590 return CMD_WARNING;
1591 }
1592
1593 log_set_nse_filter(tgt, nse);
1594 log_tgt_mutex_unlock();
1595 return CMD_SUCCESS;
1596}
1597
Alexander Couzens6a161492020-07-12 13:45:50 +02001598/* TODO: add filter for single connection by description */
1599DEFUN(logging_fltr_nsvc,
1600 logging_fltr_nsvc_cmd,
1601 "logging filter nsvc nsvci <0-65535>",
1602 LOGGING_STR FILTER_STR
1603 "Filter based on NS Virtual Connection\n"
1604 "Identify NS-VC by NSVCI\n"
1605 "Numeric identifier\n")
1606{
1607 struct log_target *tgt;
1608 struct gprs_ns2_vc *nsvc;
Daniel Willmann89106522020-12-04 01:36:59 +01001609 uint16_t id = atoi(argv[0]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001610
1611 log_tgt_mutex_lock();
1612 tgt = osmo_log_vty2tgt(vty);
1613 if (!tgt) {
1614 log_tgt_mutex_unlock();
1615 return CMD_WARNING;
1616 }
1617
1618 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, id);
1619 if (!nsvc) {
1620 vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE);
1621 log_tgt_mutex_unlock();
1622 return CMD_WARNING;
1623 }
1624
1625 log_set_nsvc_filter(tgt, nsvc);
1626 log_tgt_mutex_unlock();
1627 return CMD_SUCCESS;
1628}
1629
Alexander Couzense43b46e2021-01-27 21:52:08 +01001630/*! initialized a reduced vty interface which excludes the configuration nodes besides timeouts.
1631 * This can be used by the PCU which can be only configured by the BTS/BSC and not by the vty.
1632 * \param[in] nsi NS instance on which we operate
1633 * \return 0 on success.
1634 */
1635int gprs_ns2_vty_init_reduced(struct gprs_ns2_inst *nsi)
Alexander Couzens6a161492020-07-12 13:45:50 +02001636{
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01001637 vty_nsi = nsi;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001638 INIT_LLIST_HEAD(&binds);
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01001639
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001640 vty_fr_network = osmo_fr_network_alloc(nsi);
1641 if (!vty_fr_network)
1642 return -ENOMEM;
Alexander Couzens6a161492020-07-12 13:45:50 +02001643
Harald Welte25ee7552020-12-02 22:14:00 +01001644 install_lib_element_ve(&show_ns_cmd);
Harald Welte2fce19a2020-12-01 17:52:55 +01001645 install_lib_element_ve(&show_ns_binds_cmd);
1646 install_lib_element_ve(&show_ns_entities_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07001647 install_lib_element_ve(&show_ns_pers_cmd);
1648 install_lib_element_ve(&show_nse_cmd);
Daniel Willmann751977b2020-12-02 18:59:44 +01001649 install_lib_element_ve(&logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07001650 install_lib_element_ve(&logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02001651
Daniel Willmanndbab7142020-11-18 14:19:56 +01001652 install_lib_element(ENABLE_NODE, &nsvc_force_unconf_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001653 install_lib_element(ENABLE_NODE, &nsvc_block_cmd);
Daniel Willmanndbab7142020-11-18 14:19:56 +01001654
Daniel Willmann751977b2020-12-02 18:59:44 +01001655 install_lib_element(CFG_LOG_NODE, &logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07001656 install_lib_element(CFG_LOG_NODE, &logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02001657
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07001658 install_lib_element(CONFIG_NODE, &cfg_ns_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001659
Alexander Couzens6a161492020-07-12 13:45:50 +02001660 install_node(&ns_node, config_write_ns);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001661 /* TODO: convert into osmo timer */
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07001662 install_lib_element(L_NS_NODE, &cfg_ns_timer_cmd);
Alexander Couzense43b46e2021-01-27 21:52:08 +01001663
1664 return 0;
1665}
1666
1667int gprs_ns2_vty_init(struct gprs_ns2_inst *nsi)
1668{
1669 int rc = gprs_ns2_vty_init_reduced(nsi);
1670 if (rc)
1671 return rc;
1672
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001673 install_lib_element(L_NS_NODE, &cfg_ns_nsei_cmd);
1674 install_lib_element(L_NS_NODE, &cfg_no_ns_nsei_cmd);
1675 install_lib_element(L_NS_NODE, &cfg_ns_bind_cmd);
1676 install_lib_element(L_NS_NODE, &cfg_no_ns_bind_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02001677
Alexander Couzens260cd522021-01-28 20:31:31 +01001678 install_node(&ns_bind_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001679 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_listen_cmd);
1680 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_listen_cmd);
1681 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_dscp_cmd);
1682 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_dscp_cmd);
1683 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_ipaccess_cmd);
1684 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_ipaccess_cmd);
1685 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_fr_cmd);
1686 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_fr_cmd);
1687 /* TODO: accept-ip-sns when SGSN SNS has been implemented */
Alexander Couzens6a161492020-07-12 13:45:50 +02001688
Alexander Couzens260cd522021-01-28 20:31:31 +01001689 install_node(&ns_nse_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001690 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_fr_cmd);
1691 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvci_cmd);
1692 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_fr_dlci_cmd);
1693 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_udp_cmd);
1694 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_udp_cmd);
1695 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_ipa_cmd);
1696 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_ipa_cmd);
1697 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_cmd);
1698 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02001699
1700 return 0;
1701}