blob: 42ab2b259b1c2007ff8d67dfd8205c4877b6682d [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;
Alexander Couzens6b9d2322021-02-12 03:17:59 +010061static struct llist_head nses;
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010062
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010063struct vty_bind {
64 struct llist_head list;
65 const char *name;
66 enum gprs_ns2_ll ll;
67 int dscp;
68 bool accept_ipaccess;
69 bool accept_sns;
Alexander Couzensc4704762021-02-08 23:13:12 +010070 uint8_t ip_sns_sig_weight;
71 uint8_t ip_sns_data_weight;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010072};
73
Alexander Couzens6b9d2322021-02-12 03:17:59 +010074struct vty_nse {
75 struct llist_head list;
76 uint16_t nsei;
77 /* list of binds which are valid for this nse. Only IP-SNS uses this
78 * to allow `no listen ..` in the bind context. So "half" created binds are valid for
79 * IP-SNS. This allows changing the bind ip without modifying all NSEs afterwards */
80 struct llist_head binds;
81};
82
83/* used by IP-SNS to connect multiple vty_nse_bind to a vty_nse */
84struct vty_nse_bind {
85 struct llist_head list;
86 struct vty_bind *vbind;
87};
88
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010089/* TODO: this should into osmo timer */
Alexander Couzens6a161492020-07-12 13:45:50 +020090static const struct value_string gprs_ns_timer_strs[] = {
91 { 0, "tns-block" },
92 { 1, "tns-block-retries" },
93 { 2, "tns-reset" },
94 { 3, "tns-reset-retries" },
95 { 4, "tns-test" },
96 { 5, "tns-alive" },
97 { 6, "tns-alive-retries" },
98 { 7, "tsns-prov" },
Harald Welte33c3c062020-12-16 11:59:19 +010099 { 8, "tsns-size-retries" },
100 { 9, "tsns-config-retries" },
Alexander Couzens6a161492020-07-12 13:45:50 +0200101 { 0, NULL }
102};
103
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100104const struct value_string vty_fr_role_names[] = {
105 { FR_ROLE_USER_EQUIPMENT, "fr" },
106 { FR_ROLE_NETWORK_EQUIPMENT, "frnet" },
107 { 0, NULL }
108};
109
110const struct value_string vty_ll_names[] = {
111 { GPRS_NS2_LL_FR, "fr" },
112 { GPRS_NS2_LL_FR_GRE, "frgre" },
113 { GPRS_NS2_LL_UDP, "udp" },
114 { 0, NULL }
115};
116
117static struct vty_bind *vty_bind_by_name(const char *name)
Daniel Willmann751977b2020-12-02 18:59:44 +0100118{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100119 struct vty_bind *vbind;
120 llist_for_each_entry(vbind, &binds, list) {
Alexander Couzensb7921732021-02-12 03:08:42 +0100121 if (!strcmp(vbind->name, name))
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100122 return vbind;
Daniel Willmann751977b2020-12-02 18:59:44 +0100123 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100124 return NULL;
Daniel Willmann751977b2020-12-02 18:59:44 +0100125}
126
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100127static struct vty_bind *vty_bind_alloc(const char *name)
Alexander Couzens6a161492020-07-12 13:45:50 +0200128{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100129 struct vty_bind *vbind = talloc_zero(vty_nsi, struct vty_bind);
130 if (!vbind)
131 return NULL;
132
133 vbind->name = talloc_strdup(vty_nsi, name);
134 if (!vbind->name) {
135 talloc_free(vbind);
136 return NULL;
Alexander Couzens6a161492020-07-12 13:45:50 +0200137 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100138
Alexander Couzensc4704762021-02-08 23:13:12 +0100139 vbind->ip_sns_sig_weight = 1;
140 vbind->ip_sns_data_weight = 1;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100141 llist_add(&vbind->list, &binds);
142 return vbind;
143}
144
145static void vty_bind_free(struct vty_bind *vbind)
146{
147 if (!vbind)
148 return;
149
150 llist_del(&vbind->list);
Alexander Couzens3e2e4a02021-02-09 16:15:06 +0100151 talloc_free(vbind);
Alexander Couzens6a161492020-07-12 13:45:50 +0200152}
153
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100154static struct vty_nse *vty_nse_by_nsei(uint16_t nsei)
155{
156 struct vty_nse *vnse;
157 llist_for_each_entry(vnse, &nses, list) {
158 if (vnse->nsei == nsei)
159 return vnse;
160 }
161 return NULL;
162}
163
164static struct vty_nse *vty_nse_alloc(uint16_t nsei)
165{
166 struct vty_nse *vnse = talloc_zero(vty_nsi, struct vty_nse);
167 if (!vnse)
168 return NULL;
169
170 vnse->nsei = nsei;
171 INIT_LLIST_HEAD(&vnse->binds);
172 llist_add(&vnse->list, &nses);
173 return vnse;
174}
175
176static void vty_nse_free(struct vty_nse *vnse)
177{
178 if (!vnse)
179 return;
180
181 llist_del(&vnse->list);
182 /* all vbind of the nse will be freed by talloc */
183 talloc_free(vnse);
184}
185
186static int vty_nse_add_vbind(struct vty_nse *vnse, struct vty_bind *vbind)
187{
188 struct vty_nse_bind *vnse_bind;
189
190 if (vbind->ll != GPRS_NS2_LL_UDP)
191 return -EINVAL;
192
193 llist_for_each_entry(vnse_bind, &vnse->binds, list) {
194 if (vnse_bind->vbind == vbind)
195 return -EALREADY;
196 }
197
198 vnse_bind = talloc(vnse, struct vty_nse_bind);
199 if (!vnse_bind)
200 return -ENOMEM;
201 vnse_bind->vbind = vbind;
202
203 llist_add_tail(&vnse_bind->list, &vnse->binds);
204 return 0;
205}
206
207static int vty_nse_remove_vbind(struct vty_nse *vnse, struct vty_bind *vbind)
208{
209 struct vty_nse_bind *vnse_bind, *tmp;
210 if (vbind->ll != GPRS_NS2_LL_UDP)
211 return -EINVAL;
212
213 llist_for_each_entry_safe(vnse_bind, tmp, &vnse->binds, list) {
214 if (vnse_bind->vbind == vbind) {
215 llist_del(&vnse_bind->list);
216 talloc_free(vnse_bind);
217 }
218 }
219
220 return -ENOENT;
221}
222
223/* check if the NSE still has SNS configuration */
224static bool vty_nse_check_sns(struct gprs_ns2_nse *nse) {
225 struct vty_nse *vnse = vty_nse_by_nsei(nse->nsei);
226
227 int count = gprs_ns2_sns_count(nse);
228 if (count > 0) {
229 /* there are other sns endpoints */
230 return true;
231 }
232
233 if (!vnse)
234 return false;
235
236 if (llist_empty(&vnse->binds))
237 return false;
238
239 return true;
240}
241
Alexander Couzens6a161492020-07-12 13:45:50 +0200242static struct cmd_node ns_node = {
243 L_NS_NODE,
244 "%s(config-ns)# ",
245 1,
246};
247
Alexander Couzens6a161492020-07-12 13:45:50 +0200248DEFUN(cfg_ns, cfg_ns_cmd,
249 "ns",
250 "Configure the GPRS Network Service")
251{
252 vty->node = L_NS_NODE;
253 return CMD_SUCCESS;
254}
255
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100256DEFUN(cfg_ns_timer, cfg_ns_timer_cmd,
257 "timer " NS_TIMERS " <0-65535>",
258 "Network Service Timer\n"
259 NS_TIMERS_HELP "Timer Value\n")
260{
261 int idx = get_string_value(gprs_ns_timer_strs, argv[0]);
262 int val = atoi(argv[1]);
263
264 if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout))
265 return CMD_WARNING;
266
267 vty_nsi->timeout[idx] = val;
268
269 return CMD_SUCCESS;
270}
271
272DEFUN(cfg_ns_nsei, cfg_ns_nsei_cmd,
Harald Welte579699b2021-03-05 10:22:23 +0100273 "nse <0-65535> [ip-sns-role-sgsn]",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100274 "Persistent NS Entity\n"
275 "NS Entity ID (NSEI)\n"
Harald Welte579699b2021-03-05 10:22:23 +0100276 "Create NSE in SGSN role (default: BSS)\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100277 )
278{
279 struct gprs_ns2_nse *nse;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100280 struct vty_nse *vnse;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100281 uint16_t nsei = atoi(argv[0]);
Harald Welte579699b2021-03-05 10:22:23 +0100282 bool sgsn_role = false;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100283 bool free_vnse = false;
Harald Welte579699b2021-03-05 10:22:23 +0100284 if (argc > 1 && !strcmp(argv[1], "ip-sns-role-sgsn"))
285 sgsn_role = true;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100286
287 vnse = vty_nse_by_nsei(nsei);
288 if (!vnse) {
289 vnse = vty_nse_alloc(nsei);
290 if (!vnse) {
291 vty_out(vty, "Failed to create vty NSE!%s", VTY_NEWLINE);
292 return CMD_ERR_INCOMPLETE;
293 }
294 free_vnse = true;
295 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100296
297 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
298 if (!nse) {
Harald Welte579699b2021-03-05 10:22:23 +0100299 nse = gprs_ns2_create_nse2(vty_nsi, nsei, GPRS_NS2_LL_UNDEF, GPRS_NS2_DIALECT_UNDEF,
300 sgsn_role);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100301 if (!nse) {
302 vty_out(vty, "Failed to create NSE!%s", VTY_NEWLINE);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100303 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100304 }
305 nse->persistent = true;
306 }
307
308 if (!nse->persistent) {
309 /* TODO: should the dynamic NSE removed? */
310 vty_out(vty, "A dynamic NSE with the specified NSEI already exists%s", VTY_NEWLINE);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100311 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100312 }
313
314 vty->node = L_NS_NSE_NODE;
315 vty->index = nse;
316
317 return CMD_SUCCESS;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100318
319err:
320 if (free_vnse)
321 talloc_free(vnse);
322
323 return CMD_ERR_INCOMPLETE;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100324}
325
326DEFUN(cfg_no_ns_nsei, cfg_no_ns_nsei_cmd,
327 "no nse <0-65535>",
328 NO_STR
329 "Delete a Persistent NS Entity\n"
330 "NS Entity ID (NSEI)\n"
331 )
332{
333 struct gprs_ns2_nse *nse;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100334 struct vty_nse *vnse;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100335 uint16_t nsei = atoi(argv[0]);
336
337 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
338 if (!nse) {
339 vty_out(vty, "Can not find NS Entity %s%s", argv[0], VTY_NEWLINE);
340 return CMD_ERR_NOTHING_TODO;
341 }
342
343 if (!nse->persistent) {
344 vty_out(vty, "Ignoring non-persistent NS Entity%s", VTY_NEWLINE);
345 return CMD_WARNING;
346 }
347
348 vty_out(vty, "Deleting NS Entity %u%s", nse->nsei, VTY_NEWLINE);
349 gprs_ns2_free_nse(nse);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100350
351 vnse = vty_nse_by_nsei(nsei);
352 vty_nse_free(vnse);
353
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100354 return CMD_SUCCESS;
355}
356
357/* TODO: add fr/gre */
358DEFUN(cfg_ns_bind, cfg_ns_bind_cmd,
359 "bind (fr|udp) ID",
Harald Welte2230a912021-03-04 20:09:50 +0100360 "Configure local Bind\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100361 "Frame Relay\n" "UDP/IP\n"
Harald Welte2230a912021-03-04 20:09:50 +0100362 "Unique identifier for this bind (to reference from NS-VCs, NSEs, ...)\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100363 )
364{
365 const char *nstype = argv[0];
366 const char *name = argv[1];
367 struct vty_bind *vbind;
368 enum gprs_ns2_ll ll;
369 int rc;
370
371 rc = get_string_value(vty_ll_names, nstype);
372 if (rc < 0)
373 return CMD_WARNING;
374 ll = (enum gprs_ns2_ll) rc;
375
376 if (!osmo_identifier_valid(name)) {
377 vty_out(vty, "Invalid ID. The ID should be only alphanumeric.%s", VTY_NEWLINE);
378 return CMD_WARNING;
379 }
380
381 vbind = vty_bind_by_name(name);
382 if (vbind) {
383 if (vbind->ll != ll) {
384 vty_out(vty, "A bind with the specified ID already exists with a different type (fr|frgre|udp)!%s",
385 VTY_NEWLINE);
386 return CMD_WARNING;
387 }
388 } else {
389 vbind = vty_bind_alloc(name);
390 if (!vbind) {
391 vty_out(vty, "Can not create bind - out of memory%s", VTY_NEWLINE);
392 return CMD_WARNING;
393 }
394 vbind->ll = ll;
395 }
396
397 vty->index = vbind;
398 vty->node = L_NS_BIND_NODE;
399
400 return CMD_SUCCESS;
401}
402
403DEFUN(cfg_no_ns_bind, cfg_no_ns_bind_cmd,
404 "no bind ID",
405 NO_STR
Harald Welte2230a912021-03-04 20:09:50 +0100406 "Delete a bind\n"
407 "Unique identifier for this bind\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100408 )
409{
410 struct vty_bind *vbind;
411 struct gprs_ns2_vc_bind *bind;
412 const char *name = argv[0];
413
414 vbind = vty_bind_by_name(name);
415 if (!vbind) {
416 vty_out(vty, "bind %s does not exist!%s", name, VTY_NEWLINE);
417 return CMD_WARNING;
418 }
419 vty_bind_free(vbind);
420 bind = gprs_ns2_bind_by_name(vty_nsi, name);
421 if (bind)
422 bind->driver->free_bind(bind);
423 return CMD_SUCCESS;
424}
425
426
427static void config_write_vbind(struct vty *vty, struct vty_bind *vbind)
428{
429 struct gprs_ns2_vc_bind *bind;
430 const struct osmo_sockaddr *addr;
431 struct osmo_sockaddr_str addr_str;
432 const char *netif, *frrole_str, *llstr;
433 enum osmo_fr_role frrole;
434
435 llstr = get_value_string_or_null(vty_ll_names, vbind->ll);
436 if (!llstr)
437 return;
438 vty_out(vty, " bind %s %s%s", llstr, vbind->name, VTY_NEWLINE);
439
440 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
441 switch (vbind->ll) {
442 case GPRS_NS2_LL_FR:
443 if (bind) {
444 netif = gprs_ns2_fr_bind_netif(bind);
445 if (!netif)
446 return;
447 frrole = gprs_ns2_fr_bind_role(bind);
448 if ((int) frrole == -1)
449 return;
450 frrole_str = get_value_string_or_null(vty_fr_role_names, frrole);
451 if (netif && frrole_str)
452 vty_out(vty, " fr %s %s%s", netif, frrole_str, VTY_NEWLINE);
453 }
454 break;
455 case GPRS_NS2_LL_UDP:
456 if (bind) {
457 addr = gprs_ns2_ip_bind_sockaddr(bind);
458 if (!osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas)) {
459 vty_out(vty, " listen %s %u%s", addr_str.ip, addr_str.port,
460 VTY_NEWLINE);
461 }
462 }
463 if (vbind->accept_ipaccess)
464 vty_out(vty, " accept-ipaccess%s", VTY_NEWLINE);
465 if (vbind->dscp)
466 vty_out(vty, " dscp %u%s", vbind->dscp, VTY_NEWLINE);
Daniel Willmann64db6362021-02-12 12:21:45 +0100467 vty_out(vty, " ip-sns signalling-weight %u data-weight %u%s",
Alexander Couzensc4704762021-02-08 23:13:12 +0100468 vbind->ip_sns_sig_weight, vbind->ip_sns_data_weight, VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100469 break;
470 default:
471 return;
472 }
473}
474
475static void config_write_nsvc(struct vty *vty, const struct gprs_ns2_vc *nsvc)
476{
477 const char *netif;
478 uint16_t dlci;
479 const struct osmo_sockaddr *addr;
480 struct osmo_sockaddr_str addr_str;
481
482 switch (nsvc->nse->ll) {
483 case GPRS_NS2_LL_UNDEF:
484 break;
485 case GPRS_NS2_LL_UDP:
486 switch (nsvc->nse->dialect) {
487 case GPRS_NS2_DIALECT_IPACCESS:
488 addr = gprs_ns2_ip_vc_remote(nsvc);
489 if (!addr)
490 break;
491 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas))
492 break;
493 vty_out(vty, " nsvc ipa %s %s %u nsvci %u%s",
494 nsvc->bind->name, addr_str.ip, addr_str.port,
495 nsvc->nsvci, VTY_NEWLINE);
496 break;
497 case GPRS_NS2_DIALECT_STATIC_ALIVE:
498 addr = gprs_ns2_ip_vc_remote(nsvc);
499 if (!addr)
500 break;
501 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas))
502 break;
503 vty_out(vty, " nsvc udp %s %s %u%s",
504 nsvc->bind->name, addr_str.ip, addr_str.port, VTY_NEWLINE);
505 break;
506 default:
507 break;
508 }
509 break;
510 case GPRS_NS2_LL_FR:
511 netif = gprs_ns2_fr_bind_netif(nsvc->bind);
512 if (!netif)
513 break;
514 dlci = gprs_ns2_fr_nsvc_dlci(nsvc);
515 if (!dlci)
516 break;
517 OSMO_ASSERT(nsvc->nsvci_is_valid);
518 vty_out(vty, " nsvc fr %s dlci %u nsvci %u%s",
519 netif, dlci, nsvc->nsvci, VTY_NEWLINE);
520 break;
521 case GPRS_NS2_LL_FR_GRE:
522 break;
523 }
524}
525
526static void _config_write_ns_nse(struct vty *vty, struct gprs_ns2_nse *nse)
527{
528 struct gprs_ns2_vc *nsvc;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100529 struct vty_nse *vnse = vty_nse_by_nsei(nse->nsei);
530 struct vty_nse_bind *vbind;
531
532 OSMO_ASSERT(vnse);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100533
Harald Welte579699b2021-03-05 10:22:23 +0100534 vty_out(vty, " nse %u%s%s", nse->nsei,
535 nse->ip_sns_role_sgsn ? " ip-sns-role-sgsn" : "", VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100536 switch (nse->dialect) {
537 case GPRS_NS2_DIALECT_SNS:
538 ns2_sns_write_vty(vty, nse);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100539 llist_for_each_entry(vbind, &vnse->binds, list) {
540 vty_out(vty, " ip-sns-bind %s%s", vbind->vbind->name, VTY_NEWLINE);
541 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100542 break;
543 default:
544 llist_for_each_entry(nsvc, &nse->nsvc, list) {
545 config_write_nsvc(vty, nsvc);
546 }
547 break;
548 }
549}
550
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100551static int config_write_ns_nse(struct vty *vty)
552{
553 struct gprs_ns2_nse *nse;
554
555 llist_for_each_entry(nse, &vty_nsi->nse, list) {
556 if (!nse->persistent)
557 continue;
558
559 _config_write_ns_nse(vty, nse);
560 }
561
562 return 0;
563}
564
565static int config_write_ns_bind(struct vty *vty)
566{
567 struct vty_bind *vbind;
568
569 llist_for_each_entry(vbind, &binds, list) {
570 config_write_vbind(vty, vbind);
571 }
572
573 return 0;
574}
575
Alexander Couzens260cd522021-01-28 20:31:31 +0100576static int config_write_ns(struct vty *vty)
577{
578 unsigned int i;
579 int ret;
580
581 vty_out(vty, "ns%s", VTY_NEWLINE);
582
583 for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++)
584 vty_out(vty, " timer %s %u%s",
585 get_value_string(gprs_ns_timer_strs, i),
586 vty_nsi->timeout[i], VTY_NEWLINE);
587
588 ret = config_write_ns_bind(vty);
589 if (ret)
590 return ret;
591
592 ret = config_write_ns_nse(vty);
593 if (ret)
594 return ret;
595
596 return 0;
597}
598
599
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100600static struct cmd_node ns_bind_node = {
601 L_NS_BIND_NODE,
602 "%s(config-ns-bind)# ",
603 1,
604};
605
606DEFUN(cfg_ns_bind_listen, cfg_ns_bind_listen_cmd,
607 "listen " VTY_IPV46_CMD " <1-65535>",
Harald Welte2230a912021-03-04 20:09:50 +0100608 "Configure local IP + Port of this bind\n"
609 "Local IPv4 Address\n" "Local IPv6 Address\n"
610 "Local UDP Port\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100611 )
612{
613 struct vty_bind *vbind = vty->index;
614 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100615 int rc;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100616 const char *addr_str = argv[0];
617 unsigned int port = atoi(argv[1]);
618 struct osmo_sockaddr_str sockaddr_str;
619 struct osmo_sockaddr sockaddr;
620
621 if (vbind->ll != GPRS_NS2_LL_UDP) {
622 vty_out(vty, "listen can be only used with UDP bind%s",
623 VTY_NEWLINE);
624 return CMD_WARNING;
625 }
626
627 if (osmo_sockaddr_str_from_str(&sockaddr_str, addr_str, port)) {
628 vty_out(vty, "Can not parse the Address %s %s%s", argv[0], argv[1], VTY_NEWLINE);
629 return CMD_WARNING;
630 }
631 osmo_sockaddr_str_to_sockaddr(&sockaddr_str, &sockaddr.u.sas);
632 if (gprs_ns2_ip_bind_by_sockaddr(vty_nsi, &sockaddr)) {
633 vty_out(vty, "A bind with the specified address already exists!%s", VTY_NEWLINE);
634 return CMD_WARNING;
635 }
636
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100637 rc = gprs_ns2_ip_bind(vty_nsi, vbind->name, &sockaddr, vbind->dscp, &bind);
638 if (rc != 0) {
639 vty_out(vty, "Failed to create the bind (rc %d)!%s", rc, VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100640 return CMD_WARNING;
641 }
642
643 bind->accept_ipaccess = vbind->accept_ipaccess;
644 bind->accept_sns = vbind->accept_sns;
645
646 return CMD_SUCCESS;
647}
648
649DEFUN(cfg_no_ns_bind_listen, cfg_no_ns_bind_listen_cmd,
650 "no listen",
651 NO_STR
652 "Delete a IP/Port assignment\n"
653 )
654{
655 struct vty_bind *vbind = vty->index;
656 struct gprs_ns2_vc_bind *bind;
657
658 if (vbind->ll != GPRS_NS2_LL_UDP) {
659 vty_out(vty, "no listen can be only used with UDP bind%s", VTY_NEWLINE);
660 return CMD_WARNING;
661 }
662
663 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
664 if (!bind)
665 return CMD_ERR_NOTHING_TODO;
666
Daniel Willmann90432052021-01-26 16:09:18 +0100667 OSMO_ASSERT(bind->ll == GPRS_NS2_LL_UDP);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100668 bind->driver->free_bind(bind);
669 return CMD_SUCCESS;
670}
671
672DEFUN(cfg_ns_bind_dscp, cfg_ns_bind_dscp_cmd,
673 "dscp <0-255>",
674 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
675{
676 struct vty_bind *vbind = vty->index;
677 struct gprs_ns2_vc_bind *bind;
678 uint16_t dscp = atoi(argv[0]);
679
680 if (vbind->ll != GPRS_NS2_LL_UDP) {
681 vty_out(vty, "dscp can be only used with UDP bind%s",
682 VTY_NEWLINE);
683 return CMD_WARNING;
684 }
685
686 vbind->dscp = dscp;
687 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
688 if (bind)
689 gprs_ns2_ip_bind_set_dscp(bind, dscp);
690
691 return CMD_SUCCESS;
692}
693
694DEFUN(cfg_no_ns_bind_dscp, cfg_no_ns_bind_dscp_cmd,
695 "no dscp",
696 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
697{
698 struct vty_bind *vbind = vty->index;
699 struct gprs_ns2_vc_bind *bind;
700 uint16_t dscp = 0;
701
702 if (vbind->ll != GPRS_NS2_LL_UDP) {
703 vty_out(vty, "dscp can be only used with UDP bind%s",
704 VTY_NEWLINE);
705 return CMD_WARNING;
706 }
707
708 vbind->dscp = dscp;
709 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
710 if (bind)
711 gprs_ns2_ip_bind_set_dscp(bind, dscp);
712
713 return CMD_SUCCESS;
714}
715
716DEFUN(cfg_ns_bind_ipaccess, cfg_ns_bind_ipaccess_cmd,
717 "accept-ipaccess",
718 "Allow to create dynamic NS Entity by NS Reset PDU on UDP (ip.access style)\n"
719 )
720{
721 struct vty_bind *vbind = vty->index;
722 struct gprs_ns2_vc_bind *bind;
723
724 if (vbind->ll != GPRS_NS2_LL_UDP) {
725 vty_out(vty, "accept-ipaccess can be only used with UDP bind%s",
726 VTY_NEWLINE);
727 return CMD_WARNING;
728 }
729
730 vbind->accept_ipaccess = true;
731 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
732 if (bind)
733 bind->accept_ipaccess = true;
734
735 return CMD_SUCCESS;
736}
737
738DEFUN(cfg_no_ns_bind_ipaccess, cfg_no_ns_bind_ipaccess_cmd,
739 "no accept-ipaccess",
740 NO_STR
741 "Reject NS Reset PDU on UDP (ip.access style)\n"
742 )
743{
744 struct vty_bind *vbind = vty->index;
745 struct gprs_ns2_vc_bind *bind;
746
747 if (vbind->ll != GPRS_NS2_LL_UDP) {
748 vty_out(vty, "no accept-ipaccess can be only used with UDP bind%s",
749 VTY_NEWLINE);
750 return CMD_WARNING;
751 }
752
753 vbind->accept_ipaccess = false;
754 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
755 if (bind)
756 bind->accept_ipaccess = false;
757
758 return CMD_SUCCESS;
759}
760
Alexander Couzensc4704762021-02-08 23:13:12 +0100761DEFUN(cfg_ns_bind_ip_sns_weight, cfg_ns_bind_ip_sns_weight_cmd,
762 "ip-sns signalling-weight <0-254> data-weight <0-254>",
763 "IP SNS\n"
764 "signalling weight used by IP-SNS dynamic configuration\n"
765 "signalling weight used by IP-SNS dynamic configuration\n"
766 "data weight used by IP-SNS dynamic configuration\n"
767 "data weight used by IP-SNS dynamic configuration\n")
768{
769 struct vty_bind *vbind = vty->index;
770 struct gprs_ns2_vc_bind *bind;
771
772 int signalling = atoi(argv[0]);
773 int data = atoi(argv[1]);
774
775 if (vbind->ll != GPRS_NS2_LL_UDP) {
776 vty_out(vty, "ip-sns signalling-weight <0-254> data-weight <0-254> can be only used with UDP bind%s",
777 VTY_NEWLINE);
778 return CMD_WARNING;
779 }
780
781 vbind->ip_sns_data_weight = data;
782 vbind->ip_sns_sig_weight = signalling;
783 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
784 if (bind)
785 gprs_ns2_ip_bind_set_sns_weight(bind, signalling, data);
786
787 return CMD_SUCCESS;
788}
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100789
790DEFUN(cfg_ns_bind_fr, cfg_ns_bind_fr_cmd,
791 "fr NETIF (fr|frnet)",
792 "frame relay\n"
793 IFNAME_STR
794 "fr (user) is used by BSS or SGSN attached to UNI of a FR network\n"
795 "frnet (network) is used by SGSN if BSS is directly attached\n"
796 )
797{
798 struct vty_bind *vbind = vty->index;
799 struct gprs_ns2_vc_bind *bind;
800 const char *netif = argv[0];
801 const char *role = argv[1];
802
803 int rc = 0;
804 enum osmo_fr_role frrole;
805
806 if (vbind->ll != GPRS_NS2_LL_FR) {
807 vty_out(vty, "fr can be only used with frame relay bind%s", VTY_NEWLINE);
808 return CMD_WARNING;
809 }
810
811 if (!strcmp(role, "fr"))
812 frrole = FR_ROLE_USER_EQUIPMENT;
813 else if (!strcmp(role, "frnet"))
814 frrole = FR_ROLE_NETWORK_EQUIPMENT;
815 else
816 return CMD_WARNING;
817
818 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
819 if (bind) {
820 vty_out(vty, "Interface %s already used.%s", netif, VTY_NEWLINE);
821 return CMD_WARNING;
822 }
823
824 rc = gprs_ns2_fr_bind(vty_nsi, vbind->name, netif, vty_fr_network, frrole, &bind);
825 if (rc < 0) {
826 LOGP(DLNS, LOGL_ERROR, "Failed to bind interface %s on fr. Err: %d\n", netif, rc);
827 return CMD_WARNING;
828 }
829
830 return CMD_SUCCESS;
831}
832
833DEFUN(cfg_no_ns_bind_fr, cfg_no_ns_bind_fr_cmd,
834 "no fr NETIF",
835 NO_STR
836 "Delete a frame relay link\n"
837 "Delete a frame relay link\n"
838 IFNAME_STR
839 )
840{
841 struct vty_bind *vbind = vty->index;
842 struct gprs_ns2_vc_bind *bind;
843 const char *netif = argv[0];
844
845 if (vbind->ll != GPRS_NS2_LL_FR) {
846 vty_out(vty, "fr can be only used with frame relay bind%s",
847 VTY_NEWLINE);
848 return CMD_WARNING;
849 }
850
851 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
852 if (!bind) {
853 vty_out(vty, "Interface not found.%s", VTY_NEWLINE);
854 return CMD_WARNING;
855 }
856
857 if (strcmp(bind->name, vbind->name)) {
858 vty_out(vty, "The specified interface is not bound to this bind.%s", VTY_NEWLINE);
859 return CMD_WARNING;
860 }
861
862 bind->driver->free_bind(bind);
863 return CMD_SUCCESS;
864}
865
866
867static struct cmd_node ns_nse_node = {
868 L_NS_NSE_NODE,
869 "%s(config-ns-nse)# ",
870 1,
871};
872
873DEFUN(cfg_ns_nse_nsvc_fr, cfg_ns_nse_nsvc_fr_cmd,
874 "nsvc fr NETIF dlci <16-1007> nsvci <0-65535>",
875 "NS Virtual Connection\n"
876 "frame relay\n"
877 "frame relay interface. Must be registered via fr vty\n"
878 NSVCI_STR
879 NSVCI_STR
880 DLCI_STR
881 DLCI_STR
882 )
883{
884 struct gprs_ns2_vc_bind *bind;
885 struct gprs_ns2_vc *nsvc;
886 struct gprs_ns2_nse *nse = vty->index;
887 const char *netif = argv[0];
888 uint16_t dlci = atoi(argv[1]);
889 uint16_t nsvci = atoi(argv[2]);
890 bool dialect_modified = false;
891 bool ll_modified = false;
892
893 if (nse->ll != GPRS_NS2_LL_FR && nse->ll != GPRS_NS2_LL_UNDEF) {
894 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
895 goto err;
896 }
897
898 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_RESETBLOCK && nse->dialect != GPRS_NS2_DIALECT_UNDEF) {
899 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
900 goto err;
901 }
902
903 if (nse->ll == GPRS_NS2_LL_UNDEF) {
904 nse->ll = GPRS_NS2_LL_FR;
905 ll_modified = true;
906 }
907
908 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +0100909 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_STATIC_RESETBLOCK);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100910 dialect_modified = true;
911 }
912
913
914 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
915 if (!bind) {
916 vty_out(vty, "Can not find fr interface \"%s\". Please configure it via fr vty.%s",
917 netif, VTY_NEWLINE);
918 goto err;
919 }
920
921 if (gprs_ns2_fr_nsvc_by_dlci(bind, dlci)) {
922 vty_out(vty, "A NS-VC with the specified DLCI already exist!%s", VTY_NEWLINE);
923 goto err;
924 }
925
926 if (gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci)) {
927 vty_out(vty, "A NS-VC with the specified NS-VCI already exist!%s", VTY_NEWLINE);
928 goto err;
929 }
930
931 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
932 if (!nsvc) {
933 /* Could not create NS-VC, connect failed */
934 vty_out(vty, "Failed to create the NS-VC%s", VTY_NEWLINE);
935 goto err;
936 }
937 nsvc->persistent = true;
938 return CMD_SUCCESS;
939
940err:
941 if (ll_modified)
942 nse->ll = GPRS_NS2_LL_UNDEF;
943 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +0100944 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100945
946 return CMD_WARNING;
947}
948
949DEFUN(cfg_no_ns_nse_nsvc_fr_dlci, cfg_no_ns_nse_nsvc_fr_dlci_cmd,
950 "no nsvc fr NETIF dlci <16-1007>",
951 NO_STR
952 "Delete frame relay NS-VC\n"
953 "frame relay\n"
954 "frame relay interface. Must be registered via fr vty\n"
955 DLCI_STR
956 DLCI_STR
957 )
958{
959 struct gprs_ns2_vc_bind *bind;
960 struct gprs_ns2_vc *nsvc;
961 struct gprs_ns2_nse *nse = vty->index;
962 const char *netif = argv[0];
963 uint16_t dlci = atoi(argv[1]);
964
965 if (nse->ll != GPRS_NS2_LL_FR) {
966 vty_out(vty, "This NSE doesn't support frame relay.%s", VTY_NEWLINE);
967 return CMD_WARNING;
968 }
969
970 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
971 if (!bind) {
972 vty_out(vty, "Can not find fr interface \"%s\"%s",
973 netif, VTY_NEWLINE);
974 return CMD_ERR_NOTHING_TODO;
975 }
976
977 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
978 if (!nsvc) {
979 vty_out(vty, "Can not find a NS-VC on fr interface %s with dlci %u%s",
980 netif, dlci, VTY_NEWLINE);
981 return CMD_WARNING;
982 }
983
984 if (nse != nsvc->nse) {
985 vty_out(vty, "The specified NS-VC is not a part of the NSE %u!%s"
986 "To remove this NS-VC go to the vty node 'nse %u'%s",
987 nse->nsei, VTY_NEWLINE,
988 nsvc->nse->nsei, VTY_NEWLINE);
989 return CMD_WARNING;
990 }
991
992 gprs_ns2_free_nsvc(nsvc);
993 if (llist_empty(&nse->nsvc)) {
994 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +0100995 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100996 }
997
998 return CMD_SUCCESS;
999}
1000
1001DEFUN(cfg_no_ns_nse_nsvci, cfg_no_ns_nse_nsvci_cmd,
1002 "no nsvc nsvci <0-65535>",
1003 NO_STR
1004 "Delete NSVC\n"
1005 NSVCI_STR
1006 NSVCI_STR
1007 )
1008{
1009 struct gprs_ns2_vc *nsvc;
1010 struct gprs_ns2_nse *nse = vty->index;
1011 uint16_t nsvci = atoi(argv[0]);
1012
1013 switch (nse->dialect) {
1014 case GPRS_NS2_DIALECT_SNS:
1015 case GPRS_NS2_DIALECT_STATIC_ALIVE:
1016 vty_out(vty, "NSE doesn't support NSVCI.%s", VTY_NEWLINE);
1017 return CMD_WARNING;
1018 case GPRS_NS2_DIALECT_UNDEF:
1019 vty_out(vty, "No NSVCs configured%s", VTY_NEWLINE);
1020 return CMD_WARNING;
1021 case GPRS_NS2_DIALECT_IPACCESS:
1022 case GPRS_NS2_DIALECT_STATIC_RESETBLOCK:
1023 break;
1024 }
1025
1026 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci);
1027 if (!nsvc) {
1028 vty_out(vty, "Can not find NS-VC with NS-VCI %u%s", nsvci, VTY_NEWLINE);
1029 return CMD_WARNING;
1030 }
1031
1032 if (nse != nsvc->nse) {
1033 vty_out(vty, "NS-VC with NS-VCI %u is not part of this NSE!%s",
1034 nsvci, VTY_NEWLINE);
1035 return CMD_WARNING;
1036 }
1037
1038 gprs_ns2_free_nsvc(nsvc);
1039 if (llist_empty(&nse->nsvc)) {
1040 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001041 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001042 }
1043
1044 return CMD_SUCCESS;
1045}
1046
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001047static int ns_nse_nsvc_udp_cmds(struct vty *vty, const char *bind_name, const char *remote_char, uint16_t port,
1048 uint16_t sig_weight, uint16_t data_weight)
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001049{
1050 struct gprs_ns2_vc_bind *bind;
1051 struct gprs_ns2_vc *nsvc;
1052 struct gprs_ns2_nse *nse = vty->index;
1053 bool dialect_modified = false;
1054 bool ll_modified = false;
1055
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001056 struct osmo_sockaddr_str remote_str;
1057 struct osmo_sockaddr remote;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001058
1059 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1060 nse->ll = GPRS_NS2_LL_UDP;
1061 ll_modified = true;
1062 }
1063
1064 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001065 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_STATIC_ALIVE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001066 dialect_modified = true;
1067 }
1068
1069 if (nse->ll != GPRS_NS2_LL_UDP) {
1070 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1071 goto err;
1072 }
1073
1074 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
1075 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1076 goto err;
1077 }
1078
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001079 if (osmo_sockaddr_str_from_str(&remote_str, remote_char, port)) {
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001080 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1081 goto err;
1082 }
1083
1084 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1085 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1086 goto err;
1087 }
1088
1089 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1090 if (!bind) {
1091 vty_out(vty, "Can not find bind with name %s%s",
1092 bind_name, VTY_NEWLINE);
1093 goto err;
1094 }
1095
1096 if (bind->ll != GPRS_NS2_LL_UDP) {
1097 vty_out(vty, "Bind %s is not an UDP bind.%s",
1098 bind_name, VTY_NEWLINE);
1099 goto err;
1100 }
1101
Alexander Couzens7bb39e32021-02-16 23:06:53 +01001102 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1103 if (nsvc) {
1104 if (nsvc->nse == nse)
1105 vty_out(vty, "Specified NSVC is already present in this NSE.%s", VTY_NEWLINE);
1106 else
1107 vty_out(vty, "Specified NSVC is already present in another NSE%05u.%s", nsvc->nse->nsei, VTY_NEWLINE);
1108 goto err;
1109 }
1110
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001111 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, 0);
1112 if (!nsvc) {
1113 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
1114 goto err;
1115 }
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001116 nsvc->sig_weight = sig_weight;
1117 nsvc->data_weight = data_weight;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001118 nsvc->persistent = true;
1119
1120 return CMD_SUCCESS;
1121
1122err:
1123 if (ll_modified)
1124 nse->ll = GPRS_NS2_LL_UNDEF;
1125 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001126 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001127 return CMD_WARNING;
1128}
1129
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001130DEFUN(cfg_ns_nse_nsvc_udp, cfg_ns_nse_nsvc_udp_cmd,
1131 "nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
1132 "NS Virtual Connection\n"
1133 "NS over UDP\n"
1134 "A unique bind identifier created by ns bind\n"
1135 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1136 "Remote UDP Port\n")
1137{
1138 const char *bind_name = argv[0];
1139 const char *remote = argv[1];
1140 uint16_t port = atoi(argv[2]);
1141 uint16_t sig_weight = 1;
1142 uint16_t data_weight = 1;
1143
1144 return ns_nse_nsvc_udp_cmds(vty, bind_name, remote, port, sig_weight, data_weight);
1145}
1146
1147DEFUN(cfg_ns_nse_nsvc_udp_weights, cfg_ns_nse_nsvc_udp_weights_cmd,
1148 "nsvc udp BIND " VTY_IPV46_CMD " <1-65535> signalling-weight <0-254> data-weight <0-254>",
1149 "NS Virtual Connection\n"
1150 "NS over UDP\n"
1151 "A unique bind identifier created by ns bind\n"
1152 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1153 "Remote UDP Port\n"
1154 "Signalling weight of the NSVC (default = 1)\n"
1155 "Signalling weight of the NSVC (default = 1)\n"
1156 "Data weight of the NSVC (default = 1)\n"
1157 "Data weight of the NSVC (default = 1)\n"
1158 )
1159{
1160 const char *bind_name = argv[0];
1161 const char *remote = argv[1];
1162 uint16_t port = atoi(argv[2]);
1163 uint16_t sig_weight = atoi(argv[3]);
1164 uint16_t data_weight = atoi(argv[4]);
1165
1166 return ns_nse_nsvc_udp_cmds(vty, bind_name, remote, port, sig_weight, data_weight);
1167}
1168
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001169DEFUN(cfg_no_ns_nse_nsvc_udp, cfg_no_ns_nse_nsvc_udp_cmd,
1170 "no nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
1171 NO_STR
1172 "Delete a NS Virtual Connection\n"
1173 "NS over UDP\n"
1174 "A unique bind identifier created by ns bind\n"
1175 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1176 "Remote UDP Port\n"
1177 )
1178{
1179 struct gprs_ns2_vc_bind *bind;
1180 struct gprs_ns2_vc *nsvc;
1181 struct gprs_ns2_nse *nse = vty->index;
1182 const char *bind_name = argv[0];
1183 struct osmo_sockaddr_str remote_str;
1184 struct osmo_sockaddr remote;
1185 uint16_t port = atoi(argv[2]);
1186
1187 if (nse->ll != GPRS_NS2_LL_UDP) {
1188 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1189 return CMD_WARNING;
1190 }
1191
1192 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
1193 vty_out(vty, "This NSE doesn't support UDP with dialect static alive.%s", VTY_NEWLINE);
1194 return CMD_WARNING;
1195 }
1196
1197 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1198 if (!bind) {
1199 vty_out(vty, "Can not find bind with name %s%s",
1200 bind_name, VTY_NEWLINE);
1201 return CMD_WARNING;
1202 }
1203
1204 if (bind->ll != GPRS_NS2_LL_UDP) {
1205 vty_out(vty, "Bind %s is not an UDP bind.%s",
1206 bind_name, VTY_NEWLINE);
1207 return CMD_WARNING;
1208 }
1209
1210 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1211 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1212 return CMD_WARNING;
1213 }
1214
1215 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1216 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1217 return CMD_WARNING;
1218 }
1219
1220 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1221 if (!nsvc) {
1222 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1223 remote_str.ip, remote_str.port, VTY_NEWLINE);
1224 return CMD_WARNING;
1225 }
1226
1227 if (!nsvc->persistent) {
1228 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1229 remote_str.ip, remote_str.port, VTY_NEWLINE);
1230 return CMD_WARNING;
1231 }
1232
1233 if (nsvc->nse != nse) {
1234 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1235 return CMD_WARNING;
1236 }
1237
1238 gprs_ns2_free_nsvc(nsvc);
1239 if (llist_empty(&nse->nsvc)) {
1240 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001241 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001242 }
1243
1244 return CMD_SUCCESS;
1245}
1246
1247DEFUN(cfg_ns_nse_nsvc_ipa, cfg_ns_nse_nsvc_ipa_cmd,
1248 "nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>" ,
1249 "NS Virtual Connection\n"
1250 "NS over UDP ip.access style (uses RESET/BLOCK)\n"
1251 "A unique bind identifier created by ns bind\n"
1252 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1253 "Remote UDP Port\n"
1254 NSVCI_STR
1255 NSVCI_STR
1256 )
1257{
1258 struct gprs_ns2_vc_bind *bind;
1259 struct gprs_ns2_vc *nsvc;
1260 struct gprs_ns2_nse *nse = vty->index;
1261 bool dialect_modified = false;
1262 bool ll_modified = false;
1263
1264 const char *bind_name = argv[0];
1265 struct osmo_sockaddr_str remote_str;
1266 struct osmo_sockaddr remote;
1267 uint16_t port = atoi(argv[2]);
1268 uint16_t nsvci = atoi(argv[3]);
1269
1270 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1271 nse->ll = GPRS_NS2_LL_UDP;
1272 ll_modified = true;
1273 }
1274
1275 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001276 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_IPACCESS);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001277 dialect_modified = true;
1278 }
1279
1280 if (nse->ll != GPRS_NS2_LL_UDP) {
1281 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1282 goto err;
1283 }
1284
1285 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1286 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1287 goto err;
1288 }
1289
1290 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1291 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1292 goto err;
1293 }
1294
1295 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1296 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1297 goto err;
1298 }
1299
1300 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1301 if (!bind) {
1302 vty_out(vty, "Can not find bind with name %s%s",
1303 bind_name, VTY_NEWLINE);
1304 goto err;
1305 }
1306
1307 if (bind->ll != GPRS_NS2_LL_UDP) {
1308 vty_out(vty, "Bind %s is not an UDP bind.%s",
1309 bind_name, VTY_NEWLINE);
1310 goto err;
1311 }
1312
1313 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, nsvci);
1314 if (!nsvc) {
1315 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
1316 goto err;
1317 }
1318 nsvc->persistent = true;
1319
1320 return CMD_SUCCESS;
1321
1322err:
1323 if (ll_modified)
1324 nse->ll = GPRS_NS2_LL_UNDEF;
1325 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001326 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001327 return CMD_WARNING;
1328}
1329
1330DEFUN(cfg_no_ns_nse_nsvc_ipa, cfg_no_ns_nse_nsvc_ipa_cmd,
1331 "no nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>",
1332 NO_STR
1333 "Delete a NS Virtual Connection\n"
1334 "NS over UDP\n"
1335 "A unique bind identifier created by ns bind\n"
1336 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1337 "Remote UDP Port\n"
1338 NSVCI_STR
1339 NSVCI_STR
1340 )
1341{
1342 struct gprs_ns2_vc_bind *bind;
1343 struct gprs_ns2_vc *nsvc;
1344 struct gprs_ns2_nse *nse = vty->index;
1345 const char *bind_name = argv[0];
1346 struct osmo_sockaddr_str remote_str;
1347 struct osmo_sockaddr remote;
1348 uint16_t port = atoi(argv[2]);
1349 uint16_t nsvci = atoi(argv[3]);
1350
1351 if (nse->ll != GPRS_NS2_LL_UDP) {
1352 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1353 return CMD_WARNING;
1354 }
1355
1356 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1357 vty_out(vty, "This NSE doesn't support UDP with dialect ipaccess.%s", VTY_NEWLINE);
1358 return CMD_WARNING;
1359 }
1360
1361 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1362 if (!bind) {
1363 vty_out(vty, "Can not find bind with name %s%s",
1364 bind_name, VTY_NEWLINE);
1365 return CMD_WARNING;
1366 }
1367
1368 if (bind->ll != GPRS_NS2_LL_UDP) {
1369 vty_out(vty, "Bind %s is not an UDP bind.%s",
1370 bind_name, VTY_NEWLINE);
1371 return CMD_WARNING;
1372 }
1373
1374 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1375 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1376 return CMD_WARNING;
1377 }
1378
1379 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1380 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1381 return CMD_WARNING;
1382 }
1383
1384 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1385 if (!nsvc) {
1386 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1387 remote_str.ip, remote_str.port, VTY_NEWLINE);
1388 return CMD_WARNING;
1389 }
1390
1391 if (!nsvc->persistent) {
1392 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1393 remote_str.ip, remote_str.port, VTY_NEWLINE);
1394 return CMD_WARNING;
1395 }
1396
1397 if (nsvc->nse != nse) {
1398 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1399 return CMD_WARNING;
1400 }
1401
1402 if (!nsvc->nsvci_is_valid) {
1403 vty_out(vty, "NS-VC doesn't have a nsvci!%s", VTY_NEWLINE);
1404 return CMD_WARNING;
1405 }
1406
1407 if (nsvc->nsvci != nsvci) {
1408 vty_out(vty, "NS-VC has a different nsvci (%u)!%s",
1409 nsvc->nsvci, VTY_NEWLINE);
1410 return CMD_WARNING;
1411 }
1412
1413 gprs_ns2_free_nsvc(nsvc);
1414 if (llist_empty(&nse->nsvc)) {
1415 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001416 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001417 }
1418
1419 return CMD_SUCCESS;
1420}
1421
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001422DEFUN(cfg_ns_nse_ip_sns_remote, cfg_ns_nse_ip_sns_remote_cmd,
1423 "ip-sns-remote " VTY_IPV46_CMD " <1-65535>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001424 "SNS Initial Endpoint\n"
1425 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1426 "SGSN UDP Port\n"
1427 )
1428{
1429 struct gprs_ns2_nse *nse = vty->index;
1430 bool dialect_modified = false;
1431 bool ll_modified = false;
1432 int rc;
1433
1434 /* argv[0] */
1435 struct osmo_sockaddr_str remote_str;
1436 struct osmo_sockaddr remote;
1437 uint16_t port = atoi(argv[1]);
1438
1439 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1440 nse->ll = GPRS_NS2_LL_UDP;
1441 ll_modified = true;
1442 }
1443
1444 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001445 if (ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_SNS) < 0)
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001446 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001447 dialect_modified = true;
1448 }
1449
1450 if (nse->ll != GPRS_NS2_LL_UDP) {
1451 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1452 goto err;
1453 }
1454
1455 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1456 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1457 goto err;
1458 }
1459
1460 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1461 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1462 goto err;
1463 }
1464
1465 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1466 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1467 goto err;
1468 }
1469
1470 rc = gprs_ns2_sns_add_endpoint(nse, &remote);
1471 switch (rc) {
1472 case 0:
1473 return CMD_SUCCESS;
1474 case -EADDRINUSE:
1475 vty_out(vty, "Specified SNS endpoint already part of the NSE.%s", VTY_NEWLINE);
1476 return CMD_WARNING;
1477 default:
1478 vty_out(vty, "Can not add specified SNS endpoint.%s", VTY_NEWLINE);
1479 return CMD_WARNING;
1480 }
1481
1482err:
1483 if (ll_modified)
1484 nse->ll = GPRS_NS2_LL_UNDEF;
1485 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001486 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001487 return CMD_WARNING;
1488}
1489
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001490DEFUN(cfg_no_ns_nse_ip_sns_remote, cfg_no_ns_nse_ip_sns_remote_cmd,
1491 "no ip-sns-remote " VTY_IPV46_CMD " <1-65535>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001492 NO_STR
1493 "Delete a SNS Initial Endpoint\n"
1494 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1495 "SGSN UDP Port\n"
1496 )
1497{
1498 struct gprs_ns2_nse *nse = vty->index;
1499 struct osmo_sockaddr_str remote_str; /* argv[0] */
1500 struct osmo_sockaddr remote;
1501 uint16_t port = atoi(argv[1]);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001502
1503 if (nse->ll != GPRS_NS2_LL_UDP) {
1504 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1505 return CMD_WARNING;
1506 }
1507
1508 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1509 vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%s", VTY_NEWLINE);
1510 return CMD_WARNING;
1511 }
1512
1513 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1514 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1515 return CMD_WARNING;
1516 }
1517
1518 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1519 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1520 return CMD_WARNING;
1521 }
1522
1523 if (gprs_ns2_sns_del_endpoint(nse, &remote)) {
1524 vty_out(vty, "Can not remove specified SNS endpoint.%s", VTY_NEWLINE);
1525 return CMD_WARNING;
1526 }
1527
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001528 if (vty_nse_check_sns(nse)) {
1529 /* there is still sns configuration valid */
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001530 return CMD_SUCCESS;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001531 } else {
1532 /* clean up nse to allow other nsvc commands */
Harald Welte06d9bf92021-03-05 10:20:11 +01001533 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001534 nse->ll = GPRS_NS2_LL_UNDEF;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001535 }
1536
1537 return CMD_SUCCESS;
1538}
1539
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001540DEFUN(cfg_ns_nse_ip_sns_bind, cfg_ns_nse_ip_sns_bind_cmd,
1541 "ip-sns-bind BINDID",
1542 "IP SNS binds\n"
Harald Welte2230a912021-03-04 20:09:50 +01001543 "Name of NS udp bind whose IP endpoint will be used as IP-SNS local endpoint. Can be given multiple times.\n")
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001544{
1545 struct gprs_ns2_nse *nse = vty->index;
1546 struct gprs_ns2_vc_bind *bind;
1547 struct vty_bind *vbind;
1548 struct vty_nse *vnse;
1549 const char *name = argv[0];
1550 bool ll_modified = false;
1551 bool dialect_modified = false;
1552 int rc;
1553
1554 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1555 nse->ll = GPRS_NS2_LL_UDP;
1556 ll_modified = true;
1557 }
1558
1559 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001560 if (ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_SNS) < 0)
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001561 goto err;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001562 dialect_modified = true;
1563 }
1564
1565 if (nse->ll != GPRS_NS2_LL_UDP) {
1566 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1567 goto err;
1568 }
1569
1570 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1571 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1572 goto err;
1573 }
1574
1575 vbind = vty_bind_by_name(name);
1576 if (!vbind) {
1577 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1578 goto err;
1579 }
1580
1581 if (vbind->ll != GPRS_NS2_LL_UDP) {
1582 vty_out(vty, "ip-sns-bind can only be used with UDP bind%s",
1583 VTY_NEWLINE);
1584 goto err;
1585 }
1586
1587 /* the vnse has been created together when creating the nse node. The parent node should check this already! */
1588 vnse = vty_nse_by_nsei(nse->nsei);
1589 OSMO_ASSERT(vnse);
1590
1591 rc = vty_nse_add_vbind(vnse, vbind);
1592 switch (rc) {
1593 case 0:
1594 break;
1595 case -EALREADY:
1596 vty_out(vty, "Failed to add ip-sns-bind %s already present%s", name, VTY_NEWLINE);
1597 goto err;
1598 case -ENOMEM:
1599 vty_out(vty, "Failed to add ip-sns-bind %s out of memory%s", name, VTY_NEWLINE);
1600 goto err;
1601 default:
1602 vty_out(vty, "Failed to add ip-sns-bind %s! %d%s", name, rc, VTY_NEWLINE);
1603 goto err;
1604 }
1605
1606 /* the bind might not yet created because "listen" is missing. */
1607 bind = gprs_ns2_bind_by_name(vty_nsi, name);
1608 if (!bind)
1609 return CMD_SUCCESS;
1610
1611 rc = gprs_ns2_sns_add_bind(nse, bind);
1612 switch (rc) {
1613 case 0:
1614 break;
1615 case -EALREADY:
1616 vty_out(vty, "Failed to add ip-sns-bind %s already present%s", name, VTY_NEWLINE);
1617 goto err;
1618 case -ENOMEM:
1619 vty_out(vty, "Failed to add ip-sns-bind %s out of memory%s", name, VTY_NEWLINE);
1620 goto err;
1621 default:
1622 vty_out(vty, "Failed to add ip-sns-bind %s! %d%s", name, rc, VTY_NEWLINE);
1623 goto err;
1624 }
1625
1626 return CMD_SUCCESS;
1627err:
1628 if (ll_modified)
1629 nse->ll = GPRS_NS2_LL_UNDEF;
1630 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001631 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001632
1633 return CMD_WARNING;
1634}
1635
1636DEFUN(cfg_no_ns_nse_ip_sns_bind, cfg_no_ns_nse_ip_sns_bind_cmd,
1637 "no ip-sns-bind BINDID",
1638 NO_STR
1639 "IP SNS binds\n"
Harald Welte2230a912021-03-04 20:09:50 +01001640 "Name of NS udp bind whose IP endpoint will not be used as IP-SNS local endpoint\n")
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001641{
1642 struct gprs_ns2_nse *nse = vty->index;
1643 struct gprs_ns2_vc_bind *bind;
1644 struct vty_bind *vbind;
1645 struct vty_nse *vnse;
1646 const char *name = argv[0];
1647 int rc;
1648
1649 if (nse->ll != GPRS_NS2_LL_UDP) {
1650 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1651 return CMD_WARNING;
1652 }
1653
1654 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1655 vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%s", VTY_NEWLINE);
1656 return CMD_WARNING;
1657 }
1658
1659 vbind = vty_bind_by_name(name);
1660 if (!vbind) {
1661 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1662 return CMD_WARNING;
1663 }
1664
1665 if (vbind->ll != GPRS_NS2_LL_UDP) {
1666 vty_out(vty, "no ip-sns-bind can only be used with UDP bind%s",
1667 VTY_NEWLINE);
1668 return CMD_WARNING;
1669 }
1670
1671 /* the vnse has been created together when creating the nse node. The parent node should check this already! */
1672 vnse = vty_nse_by_nsei(nse->nsei);
1673 OSMO_ASSERT(vnse);
1674
1675 rc = vty_nse_remove_vbind(vnse, vbind);
1676 switch(rc) {
1677 case 0:
1678 break;
1679 case -ENOENT:
1680 vty_out(vty, "Bind %s is not part of this NSE%s", name, VTY_NEWLINE);
1681 return CMD_WARNING;
1682 case -EINVAL:
1683 vty_out(vty, "no ip-sns-bind can only be used with UDP bind%s",
1684 VTY_NEWLINE);
1685 return CMD_WARNING;
1686 default:
1687 return CMD_WARNING;
1688 }
1689
1690 /* the bind might not exists yet */
1691 bind = gprs_ns2_bind_by_name(vty_nsi, name);
1692 if (bind)
1693 gprs_ns2_sns_del_bind(nse, bind);
1694
1695 if (!vty_nse_check_sns(nse)) {
1696 /* clean up nse to allow other nsvc commands */
Harald Welte06d9bf92021-03-05 10:20:11 +01001697 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001698 nse->ll = GPRS_NS2_LL_UNDEF;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001699 }
1700
1701 return CMD_SUCCESS;
1702}
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001703
1704/* non-config commands */
Alexander Couzens6a161492020-07-12 13:45:50 +02001705static void dump_nsvc(struct vty *vty, struct gprs_ns2_vc *nsvc, bool stats)
1706{
Harald Weltedc2d0802020-12-01 18:17:28 +01001707 char nsvci_str[32];
1708
1709 if (nsvc->nsvci_is_valid)
1710 snprintf(nsvci_str, sizeof(nsvci_str), "%05u", nsvc->nsvci);
1711 else
1712 snprintf(nsvci_str, sizeof(nsvci_str), "none");
1713
1714 vty_out(vty, " NSVCI %s: %s %s data_weight=%u sig_weight=%u %s%s", nsvci_str,
1715 osmo_fsm_inst_state_name(nsvc->fi),
1716 nsvc->persistent ? "PERSIST" : "DYNAMIC",
1717 nsvc->data_weight, nsvc->sig_weight,
1718 gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001719
1720 if (stats) {
Harald Welte7aa60992020-12-01 17:53:17 +01001721 vty_out_rate_ctr_group(vty, " ", nsvc->ctrg);
1722 vty_out_stat_item_group(vty, " ", nsvc->statg);
Alexander Couzens6a161492020-07-12 13:45:50 +02001723 }
1724}
1725
1726static void dump_nse(struct vty *vty, const struct gprs_ns2_nse *nse, bool stats, bool persistent_only)
1727{
1728 struct gprs_ns2_vc *nsvc;
1729
Harald Welte0ff12ad2020-12-01 17:51:07 +01001730 vty_out(vty, "NSEI %05u: %s, %s%s", nse->nsei, gprs_ns2_lltype_str(nse->ll),
1731 nse->alive ? "ALIVE" : "DEAD", VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001732
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001733 ns2_sns_dump_vty(vty, " ", nse, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001734 llist_for_each_entry(nsvc, &nse->nsvc, list) {
1735 if (persistent_only) {
1736 if (nsvc->persistent)
1737 dump_nsvc(vty, nsvc, stats);
1738 } else {
1739 dump_nsvc(vty, nsvc, stats);
1740 }
1741 }
1742}
1743
Alexander Couzens22f34712020-10-02 02:34:39 +02001744static void dump_bind(struct vty *vty, const struct gprs_ns2_vc_bind *bind, bool stats)
1745{
1746 if (bind->dump_vty)
1747 bind->dump_vty(bind, vty, stats);
Harald Welte76346072021-01-31 11:54:02 +01001748
1749 if (stats) {
1750 vty_out_stat_item_group(vty, " ", bind->statg);
1751 }
Alexander Couzens22f34712020-10-02 02:34:39 +02001752}
1753
Harald Welte2fce19a2020-12-01 17:52:55 +01001754static void dump_ns_bind(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats)
Alexander Couzens6a161492020-07-12 13:45:50 +02001755{
Alexander Couzens22f34712020-10-02 02:34:39 +02001756 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6a161492020-07-12 13:45:50 +02001757
Alexander Couzens22f34712020-10-02 02:34:39 +02001758 llist_for_each_entry(bind, &nsi->binding, list) {
1759 dump_bind(vty, bind, stats);
1760 }
Harald Welte2fce19a2020-12-01 17:52:55 +01001761}
1762
1763
1764static void dump_ns_entities(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats, bool persistent_only)
1765{
1766 struct gprs_ns2_nse *nse;
Alexander Couzens22f34712020-10-02 02:34:39 +02001767
Alexander Couzens6a161492020-07-12 13:45:50 +02001768 llist_for_each_entry(nse, &nsi->nse, list) {
1769 dump_nse(vty, nse, stats, persistent_only);
Alexander Couzens6a161492020-07-12 13:45:50 +02001770 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001771}
1772
Harald Welte25ee7552020-12-02 22:14:00 +01001773/* Backwards compatibility, among other things for the TestVTYGbproxy which expects
1774 * 'show ns' to output something about binds */
1775DEFUN_HIDDEN(show_ns, show_ns_cmd, "show ns",
1776 SHOW_STR SHOW_NS_STR)
1777{
1778 dump_ns_entities(vty, vty_nsi, false, false);
1779 dump_ns_bind(vty, vty_nsi, false);
1780 return CMD_SUCCESS;
1781}
1782
1783
Harald Welte2fce19a2020-12-01 17:52:55 +01001784DEFUN(show_ns_binds, show_ns_binds_cmd, "show ns binds [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001785 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01001786 "Display information about the NS protocol binds\n"
1787 "Include statistic\n")
Alexander Couzens6a161492020-07-12 13:45:50 +02001788{
Harald Welte2fce19a2020-12-01 17:52:55 +01001789 bool stats = false;
1790 if (argc > 0)
1791 stats = true;
1792
1793 dump_ns_bind(vty, vty_nsi, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001794 return CMD_SUCCESS;
1795}
1796
Harald Welte2fce19a2020-12-01 17:52:55 +01001797DEFUN(show_ns_entities, show_ns_entities_cmd, "show ns entities [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001798 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01001799 "Display information about the NS protocol entities (NSEs)\n"
Alexander Couzens6a161492020-07-12 13:45:50 +02001800 "Include statistics\n")
1801{
Harald Welte2fce19a2020-12-01 17:52:55 +01001802 bool stats = false;
1803 if (argc > 0)
1804 stats = true;
1805
1806 dump_ns_entities(vty, vty_nsi, stats, false);
Alexander Couzens6a161492020-07-12 13:45:50 +02001807 return CMD_SUCCESS;
1808}
1809
1810DEFUN(show_ns_pers, show_ns_pers_cmd, "show ns persistent",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001811 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02001812 "Show only persistent NS\n")
1813{
Harald Welte2fce19a2020-12-01 17:52:55 +01001814 dump_ns_entities(vty, vty_nsi, true, true);
Alexander Couzens6a161492020-07-12 13:45:50 +02001815 return CMD_SUCCESS;
1816}
1817
1818DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001819 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02001820 "Select one NSE by its NSE Identifier\n"
1821 "Select one NSE by its NS-VC Identifier\n"
1822 "The Identifier of selected type\n"
1823 "Include Statistics\n")
1824{
1825 struct gprs_ns2_inst *nsi = vty_nsi;
1826 struct gprs_ns2_nse *nse;
1827 struct gprs_ns2_vc *nsvc;
1828 uint16_t id = atoi(argv[1]);
1829 bool show_stats = false;
1830
1831 if (argc >= 3)
1832 show_stats = true;
1833
1834 if (!strcmp(argv[0], "nsei")) {
1835 nse = gprs_ns2_nse_by_nsei(nsi, id);
1836 if (!nse) {
1837 return CMD_WARNING;
1838 }
1839
1840 dump_nse(vty, nse, show_stats, false);
1841 } else {
1842 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
1843
1844 if (!nsvc) {
1845 vty_out(vty, "No such NS Entity%s", VTY_NEWLINE);
1846 return CMD_WARNING;
1847 }
1848
1849 dump_nsvc(vty, nsvc, show_stats);
1850 }
1851
1852 return CMD_SUCCESS;
1853}
1854
Daniel Willmanndbab7142020-11-18 14:19:56 +01001855static int nsvc_force_unconf_cb(struct gprs_ns2_vc *nsvc, void *ctx)
1856{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001857 ns2_vc_force_unconfigured(nsvc);
Harald Welte7fe8d712021-01-31 18:40:54 +01001858 ns2_vc_fsm_start(nsvc);
Daniel Willmanndbab7142020-11-18 14:19:56 +01001859 return 0;
1860}
1861
1862DEFUN_HIDDEN(nsvc_force_unconf, nsvc_force_unconf_cmd,
1863 "nsvc nsei <0-65535> force-unconfigured",
1864 "NS Virtual Connection\n"
1865 "The NSEI\n"
1866 "Reset the NSVCs back to initial state\n"
1867 )
1868{
1869 struct gprs_ns2_inst *nsi = vty_nsi;
1870 struct gprs_ns2_nse *nse;
1871
1872 uint16_t id = atoi(argv[0]);
1873
1874 nse = gprs_ns2_nse_by_nsei(nsi, id);
1875 if (!nse) {
1876 vty_out(vty, "Could not find NSE for NSEI %u%s", id, VTY_NEWLINE);
1877 return CMD_WARNING;
1878 }
1879
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001880 if (!nse->persistent) {
1881 gprs_ns2_free_nse(nse);
1882 } else if (nse->dialect == GPRS_NS2_DIALECT_SNS) {
Alexander Couzens280ed782020-12-21 18:25:41 +01001883 gprs_ns2_free_nsvcs(nse);
1884 } else {
1885 /* Perform the operation for all nsvc */
1886 gprs_ns2_nse_foreach_nsvc(nse, nsvc_force_unconf_cb, NULL);
1887 }
Daniel Willmanndbab7142020-11-18 14:19:56 +01001888
1889 return CMD_SUCCESS;
1890}
1891
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001892DEFUN(nsvc_block, nsvc_block_cmd,
1893 "nsvc <0-65535> (block|unblock)",
1894 "NS Virtual Connection\n"
1895 NSVCI_STR
1896 "Block a NSVC. As cause code O&M intervention will be used.\n"
1897 "Unblock a NSVC. As cause code O&M intervention will be used.\n")
Alexander Couzens841817e2020-11-19 00:41:29 +01001898{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001899 struct gprs_ns2_inst *nsi = vty_nsi;
1900 struct gprs_ns2_vc *nsvc;
Alexander Couzens841817e2020-11-19 00:41:29 +01001901
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001902 uint16_t id = atoi(argv[0]);
Alexander Couzens841817e2020-11-19 00:41:29 +01001903
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001904 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
1905 if (!nsvc) {
1906 vty_out(vty, "Could not find NSVCI %05u%s", id, VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +01001907 return CMD_WARNING;
1908 }
1909
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001910 if (!strcmp(argv[1], "block")) {
1911 ns2_vc_block(nsvc);
1912 } else {
1913 ns2_vc_unblock(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +02001914 }
1915
1916 return CMD_SUCCESS;
1917}
1918
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001919static void log_set_nse_filter(struct log_target *target,
1920 struct gprs_ns2_nse *nse)
Alexander Couzens6a161492020-07-12 13:45:50 +02001921{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001922 if (nse) {
1923 target->filter_map |= (1 << LOG_FLT_GB_NSE);
1924 target->filter_data[LOG_FLT_GB_NSE] = nse;
1925 } else if (target->filter_data[LOG_FLT_GB_NSE]) {
1926 target->filter_map = ~(1 << LOG_FLT_GB_NSE);
1927 target->filter_data[LOG_FLT_GB_NSE] = NULL;
1928 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001929}
1930
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001931static void log_set_nsvc_filter(struct log_target *target,
1932 struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +02001933{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001934 if (nsvc) {
1935 target->filter_map |= (1 << LOG_FLT_GB_NSVC);
1936 target->filter_data[LOG_FLT_GB_NSVC] = nsvc;
1937 } else if (target->filter_data[LOG_FLT_GB_NSVC]) {
1938 target->filter_map = ~(1 << LOG_FLT_GB_NSVC);
1939 target->filter_data[LOG_FLT_GB_NSVC] = NULL;
1940 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001941}
1942
Daniel Willmann751977b2020-12-02 18:59:44 +01001943DEFUN(logging_fltr_nse,
1944 logging_fltr_nse_cmd,
1945 "logging filter nse nsei <0-65535>",
1946 LOGGING_STR FILTER_STR
1947 "Filter based on NS Entity\n"
1948 "Identify NSE by NSEI\n"
1949 "Numeric identifier\n")
1950{
1951 struct log_target *tgt;
1952 struct gprs_ns2_nse *nse;
Daniel Willmann89106522020-12-04 01:36:59 +01001953 uint16_t id = atoi(argv[0]);
Daniel Willmann751977b2020-12-02 18:59:44 +01001954
1955 log_tgt_mutex_lock();
1956 tgt = osmo_log_vty2tgt(vty);
1957 if (!tgt) {
1958 log_tgt_mutex_unlock();
1959 return CMD_WARNING;
1960 }
1961
1962 nse = gprs_ns2_nse_by_nsei(vty_nsi, id);
1963 if (!nse) {
1964 vty_out(vty, "No NSE by that identifier%s", VTY_NEWLINE);
1965 log_tgt_mutex_unlock();
1966 return CMD_WARNING;
1967 }
1968
1969 log_set_nse_filter(tgt, nse);
1970 log_tgt_mutex_unlock();
1971 return CMD_SUCCESS;
1972}
1973
Alexander Couzens6a161492020-07-12 13:45:50 +02001974/* TODO: add filter for single connection by description */
1975DEFUN(logging_fltr_nsvc,
1976 logging_fltr_nsvc_cmd,
1977 "logging filter nsvc nsvci <0-65535>",
1978 LOGGING_STR FILTER_STR
1979 "Filter based on NS Virtual Connection\n"
1980 "Identify NS-VC by NSVCI\n"
1981 "Numeric identifier\n")
1982{
1983 struct log_target *tgt;
1984 struct gprs_ns2_vc *nsvc;
Daniel Willmann89106522020-12-04 01:36:59 +01001985 uint16_t id = atoi(argv[0]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001986
1987 log_tgt_mutex_lock();
1988 tgt = osmo_log_vty2tgt(vty);
1989 if (!tgt) {
1990 log_tgt_mutex_unlock();
1991 return CMD_WARNING;
1992 }
1993
1994 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, id);
1995 if (!nsvc) {
1996 vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE);
1997 log_tgt_mutex_unlock();
1998 return CMD_WARNING;
1999 }
2000
2001 log_set_nsvc_filter(tgt, nsvc);
2002 log_tgt_mutex_unlock();
2003 return CMD_SUCCESS;
2004}
2005
Alexander Couzense43b46e2021-01-27 21:52:08 +01002006/*! initialized a reduced vty interface which excludes the configuration nodes besides timeouts.
2007 * This can be used by the PCU which can be only configured by the BTS/BSC and not by the vty.
2008 * \param[in] nsi NS instance on which we operate
2009 * \return 0 on success.
2010 */
2011int gprs_ns2_vty_init_reduced(struct gprs_ns2_inst *nsi)
Alexander Couzens6a161492020-07-12 13:45:50 +02002012{
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01002013 vty_nsi = nsi;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002014 INIT_LLIST_HEAD(&binds);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002015 INIT_LLIST_HEAD(&nses);
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01002016
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002017 vty_fr_network = osmo_fr_network_alloc(nsi);
2018 if (!vty_fr_network)
2019 return -ENOMEM;
Alexander Couzens6a161492020-07-12 13:45:50 +02002020
Harald Welte25ee7552020-12-02 22:14:00 +01002021 install_lib_element_ve(&show_ns_cmd);
Harald Welte2fce19a2020-12-01 17:52:55 +01002022 install_lib_element_ve(&show_ns_binds_cmd);
2023 install_lib_element_ve(&show_ns_entities_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002024 install_lib_element_ve(&show_ns_pers_cmd);
2025 install_lib_element_ve(&show_nse_cmd);
Daniel Willmann751977b2020-12-02 18:59:44 +01002026 install_lib_element_ve(&logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002027 install_lib_element_ve(&logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002028
Daniel Willmanndbab7142020-11-18 14:19:56 +01002029 install_lib_element(ENABLE_NODE, &nsvc_force_unconf_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002030 install_lib_element(ENABLE_NODE, &nsvc_block_cmd);
Daniel Willmanndbab7142020-11-18 14:19:56 +01002031
Daniel Willmann751977b2020-12-02 18:59:44 +01002032 install_lib_element(CFG_LOG_NODE, &logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002033 install_lib_element(CFG_LOG_NODE, &logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002034
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002035 install_lib_element(CONFIG_NODE, &cfg_ns_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002036
Alexander Couzens6a161492020-07-12 13:45:50 +02002037 install_node(&ns_node, config_write_ns);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002038 /* TODO: convert into osmo timer */
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002039 install_lib_element(L_NS_NODE, &cfg_ns_timer_cmd);
Alexander Couzense43b46e2021-01-27 21:52:08 +01002040
2041 return 0;
2042}
2043
2044int gprs_ns2_vty_init(struct gprs_ns2_inst *nsi)
2045{
2046 int rc = gprs_ns2_vty_init_reduced(nsi);
2047 if (rc)
2048 return rc;
2049
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002050 install_lib_element(L_NS_NODE, &cfg_ns_nsei_cmd);
2051 install_lib_element(L_NS_NODE, &cfg_no_ns_nsei_cmd);
2052 install_lib_element(L_NS_NODE, &cfg_ns_bind_cmd);
2053 install_lib_element(L_NS_NODE, &cfg_no_ns_bind_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002054
Alexander Couzens260cd522021-01-28 20:31:31 +01002055 install_node(&ns_bind_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002056 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_listen_cmd);
2057 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_listen_cmd);
2058 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_dscp_cmd);
2059 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_dscp_cmd);
Alexander Couzensc4704762021-02-08 23:13:12 +01002060 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_ip_sns_weight_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002061 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_ipaccess_cmd);
2062 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_ipaccess_cmd);
2063 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_fr_cmd);
2064 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_fr_cmd);
2065 /* TODO: accept-ip-sns when SGSN SNS has been implemented */
Alexander Couzens6a161492020-07-12 13:45:50 +02002066
Alexander Couzens260cd522021-01-28 20:31:31 +01002067 install_node(&ns_nse_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002068 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_fr_cmd);
2069 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvci_cmd);
2070 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_fr_dlci_cmd);
2071 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_udp_cmd);
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01002072 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_udp_weights_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002073 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_udp_cmd);
2074 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_ipa_cmd);
2075 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_ipa_cmd);
Alexander Couzens5fa431c2021-02-08 23:21:54 +01002076 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_remote_cmd);
2077 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_remote_cmd);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002078 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_bind_cmd);
2079 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_bind_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002080
2081 return 0;
2082}