blob: 3132e3473a57eae4beb3bb45dbaeeec2ac2e6920 [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>
Harald Welted164ef82021-03-04 22:29:17 +01006 * (C) 2021 by Harald Welte <laforge@osmocom.org>
Alexander Couzens6a161492020-07-12 13:45:50 +02007 *
8 * All Rights Reserved
9 *
10 * SPDX-License-Identifier: GPL-2.0+
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 *
25 */
26
27#include <stdlib.h>
28#include <unistd.h>
29#include <errno.h>
30#include <stdint.h>
31
32#include <arpa/inet.h>
Alexander Couzens841817e2020-11-19 00:41:29 +010033#include <net/if.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020034
Alexander Couzens6a161492020-07-12 13:45:50 +020035#include <osmocom/core/byteswap.h>
Daniel Willmanndbab7142020-11-18 14:19:56 +010036#include <osmocom/core/fsm.h>
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010037#include <osmocom/core/linuxlist.h>
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010038#include <osmocom/core/msgb.h>
Daniel Willmann3236fdf2023-08-29 16:24:56 +020039#include <osmocom/core/osmo_io.h>
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010040#include <osmocom/core/rate_ctr.h>
41#include <osmocom/core/select.h>
42#include <osmocom/core/talloc.h>
43#include <osmocom/core/sockaddr_str.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020044#include <osmocom/core/socket.h>
Alexander Couzens841817e2020-11-19 00:41:29 +010045#include <osmocom/gprs/frame_relay.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020046#include <osmocom/gprs/gprs_ns2.h>
47#include <osmocom/gsm/tlv.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020048#include <osmocom/vty/command.h>
49#include <osmocom/vty/logging.h>
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010050#include <osmocom/vty/misc.h>
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010051#include <osmocom/vty/telnet_interface.h>
52#include <osmocom/vty/vty.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020053
54#include "gprs_ns2_internal.h"
55
Daniel Willmanncb3e9b52020-12-02 15:50:22 +010056#define SHOW_NS_STR "Display information about the NS protocol\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010057#define NSVCI_STR "NS Virtual Connection ID (NS-VCI)\n"
58#define DLCI_STR "Data Link connection identifier\n"
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010059
60static struct gprs_ns2_inst *vty_nsi = NULL;
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010061static struct osmo_fr_network *vty_fr_network = NULL;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010062static struct llist_head binds;
Alexander Couzens6b9d2322021-02-12 03:17:59 +010063static struct llist_head nses;
Harald Welted164ef82021-03-04 22:29:17 +010064static struct llist_head ip_sns_default_binds;
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010065
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010066struct vty_bind {
67 struct llist_head list;
68 const char *name;
69 enum gprs_ns2_ll ll;
70 int dscp;
Harald Welted99e4ee2021-04-28 19:57:12 +020071 uint8_t priority;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010072 bool accept_ipaccess;
73 bool accept_sns;
Alexander Couzensc4704762021-02-08 23:13:12 +010074 uint8_t ip_sns_sig_weight;
75 uint8_t ip_sns_data_weight;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010076};
77
Alexander Couzens6b9d2322021-02-12 03:17:59 +010078struct vty_nse {
79 struct llist_head list;
80 uint16_t nsei;
81 /* list of binds which are valid for this nse. Only IP-SNS uses this
82 * to allow `no listen ..` in the bind context. So "half" created binds are valid for
83 * IP-SNS. This allows changing the bind ip without modifying all NSEs afterwards */
84 struct llist_head binds;
85};
86
87/* used by IP-SNS to connect multiple vty_nse_bind to a vty_nse */
88struct vty_nse_bind {
89 struct llist_head list;
90 struct vty_bind *vbind;
91};
92
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010093/* TODO: this should into osmo timer */
Alexander Couzens6a161492020-07-12 13:45:50 +020094static const struct value_string gprs_ns_timer_strs[] = {
95 { 0, "tns-block" },
96 { 1, "tns-block-retries" },
97 { 2, "tns-reset" },
98 { 3, "tns-reset-retries" },
99 { 4, "tns-test" },
100 { 5, "tns-alive" },
101 { 6, "tns-alive-retries" },
102 { 7, "tsns-prov" },
Harald Welte33c3c062020-12-16 11:59:19 +0100103 { 8, "tsns-size-retries" },
104 { 9, "tsns-config-retries" },
Alexander Couzens1f3193d2021-06-05 22:08:11 +0200105 {10, "tsns-procedures-retries" },
Alexander Couzens6a161492020-07-12 13:45:50 +0200106 { 0, NULL }
107};
108
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100109const struct value_string vty_fr_role_names[] = {
110 { FR_ROLE_USER_EQUIPMENT, "fr" },
111 { FR_ROLE_NETWORK_EQUIPMENT, "frnet" },
112 { 0, NULL }
113};
114
115const struct value_string vty_ll_names[] = {
116 { GPRS_NS2_LL_FR, "fr" },
117 { GPRS_NS2_LL_FR_GRE, "frgre" },
118 { GPRS_NS2_LL_UDP, "udp" },
119 { 0, NULL }
120};
121
122static struct vty_bind *vty_bind_by_name(const char *name)
Daniel Willmann751977b2020-12-02 18:59:44 +0100123{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100124 struct vty_bind *vbind;
125 llist_for_each_entry(vbind, &binds, list) {
Alexander Couzensb7921732021-02-12 03:08:42 +0100126 if (!strcmp(vbind->name, name))
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100127 return vbind;
Daniel Willmann751977b2020-12-02 18:59:44 +0100128 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100129 return NULL;
Daniel Willmann751977b2020-12-02 18:59:44 +0100130}
131
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100132static struct vty_bind *vty_bind_alloc(const char *name)
Alexander Couzens6a161492020-07-12 13:45:50 +0200133{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100134 struct vty_bind *vbind = talloc_zero(vty_nsi, struct vty_bind);
135 if (!vbind)
136 return NULL;
137
138 vbind->name = talloc_strdup(vty_nsi, name);
139 if (!vbind->name) {
140 talloc_free(vbind);
141 return NULL;
Alexander Couzens6a161492020-07-12 13:45:50 +0200142 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100143
Alexander Couzensc4704762021-02-08 23:13:12 +0100144 vbind->ip_sns_sig_weight = 1;
145 vbind->ip_sns_data_weight = 1;
Alexander Couzensd5cd8c62021-06-15 20:59:03 +0200146 llist_add_tail(&vbind->list, &binds);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100147 return vbind;
148}
149
150static void vty_bind_free(struct vty_bind *vbind)
151{
152 if (!vbind)
153 return;
154
155 llist_del(&vbind->list);
Alexander Couzens3e2e4a02021-02-09 16:15:06 +0100156 talloc_free(vbind);
Alexander Couzens6a161492020-07-12 13:45:50 +0200157}
158
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100159static struct vty_nse *vty_nse_by_nsei(uint16_t nsei)
160{
161 struct vty_nse *vnse;
162 llist_for_each_entry(vnse, &nses, list) {
163 if (vnse->nsei == nsei)
164 return vnse;
165 }
166 return NULL;
167}
168
169static struct vty_nse *vty_nse_alloc(uint16_t nsei)
170{
171 struct vty_nse *vnse = talloc_zero(vty_nsi, struct vty_nse);
172 if (!vnse)
173 return NULL;
174
175 vnse->nsei = nsei;
176 INIT_LLIST_HEAD(&vnse->binds);
Alexander Couzensd5cd8c62021-06-15 20:59:03 +0200177 llist_add_tail(&vnse->list, &nses);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100178 return vnse;
179}
180
181static void vty_nse_free(struct vty_nse *vnse)
182{
183 if (!vnse)
184 return;
185
186 llist_del(&vnse->list);
187 /* all vbind of the nse will be freed by talloc */
188 talloc_free(vnse);
189}
190
191static int vty_nse_add_vbind(struct vty_nse *vnse, struct vty_bind *vbind)
192{
193 struct vty_nse_bind *vnse_bind;
194
195 if (vbind->ll != GPRS_NS2_LL_UDP)
196 return -EINVAL;
197
198 llist_for_each_entry(vnse_bind, &vnse->binds, list) {
199 if (vnse_bind->vbind == vbind)
200 return -EALREADY;
201 }
202
203 vnse_bind = talloc(vnse, struct vty_nse_bind);
204 if (!vnse_bind)
205 return -ENOMEM;
206 vnse_bind->vbind = vbind;
207
208 llist_add_tail(&vnse_bind->list, &vnse->binds);
209 return 0;
210}
211
212static int vty_nse_remove_vbind(struct vty_nse *vnse, struct vty_bind *vbind)
213{
214 struct vty_nse_bind *vnse_bind, *tmp;
215 if (vbind->ll != GPRS_NS2_LL_UDP)
216 return -EINVAL;
217
218 llist_for_each_entry_safe(vnse_bind, tmp, &vnse->binds, list) {
219 if (vnse_bind->vbind == vbind) {
220 llist_del(&vnse_bind->list);
221 talloc_free(vnse_bind);
Alexander Couzens15596892021-04-19 03:31:05 +0200222 return 0;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100223 }
224 }
225
226 return -ENOENT;
227}
228
229/* check if the NSE still has SNS configuration */
230static bool vty_nse_check_sns(struct gprs_ns2_nse *nse) {
231 struct vty_nse *vnse = vty_nse_by_nsei(nse->nsei);
232
233 int count = gprs_ns2_sns_count(nse);
234 if (count > 0) {
235 /* there are other sns endpoints */
236 return true;
237 }
238
239 if (!vnse)
240 return false;
241
242 if (llist_empty(&vnse->binds))
243 return false;
244
245 return true;
246}
247
Alexander Couzens6a161492020-07-12 13:45:50 +0200248static struct cmd_node ns_node = {
249 L_NS_NODE,
250 "%s(config-ns)# ",
251 1,
252};
253
Alexander Couzens6a161492020-07-12 13:45:50 +0200254DEFUN(cfg_ns, cfg_ns_cmd,
255 "ns",
256 "Configure the GPRS Network Service")
257{
258 vty->node = L_NS_NODE;
259 return CMD_SUCCESS;
260}
261
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100262DEFUN(cfg_ns_timer, cfg_ns_timer_cmd,
263 "timer " NS_TIMERS " <0-65535>",
264 "Network Service Timer\n"
265 NS_TIMERS_HELP "Timer Value\n")
266{
267 int idx = get_string_value(gprs_ns_timer_strs, argv[0]);
268 int val = atoi(argv[1]);
269
270 if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout))
271 return CMD_WARNING;
272
273 vty_nsi->timeout[idx] = val;
274
275 return CMD_SUCCESS;
276}
277
278DEFUN(cfg_ns_nsei, cfg_ns_nsei_cmd,
Harald Welte579699b2021-03-05 10:22:23 +0100279 "nse <0-65535> [ip-sns-role-sgsn]",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100280 "Persistent NS Entity\n"
281 "NS Entity ID (NSEI)\n"
Harald Welte579699b2021-03-05 10:22:23 +0100282 "Create NSE in SGSN role (default: BSS)\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100283 )
284{
285 struct gprs_ns2_nse *nse;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100286 struct vty_nse *vnse;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100287 uint16_t nsei = atoi(argv[0]);
Harald Welte579699b2021-03-05 10:22:23 +0100288 bool sgsn_role = false;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100289 bool free_vnse = false;
Harald Welte579699b2021-03-05 10:22:23 +0100290 if (argc > 1 && !strcmp(argv[1], "ip-sns-role-sgsn"))
291 sgsn_role = true;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100292
293 vnse = vty_nse_by_nsei(nsei);
294 if (!vnse) {
295 vnse = vty_nse_alloc(nsei);
296 if (!vnse) {
297 vty_out(vty, "Failed to create vty NSE!%s", VTY_NEWLINE);
298 return CMD_ERR_INCOMPLETE;
299 }
300 free_vnse = true;
301 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100302
303 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
304 if (!nse) {
Harald Welte579699b2021-03-05 10:22:23 +0100305 nse = gprs_ns2_create_nse2(vty_nsi, nsei, GPRS_NS2_LL_UNDEF, GPRS_NS2_DIALECT_UNDEF,
306 sgsn_role);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100307 if (!nse) {
308 vty_out(vty, "Failed to create NSE!%s", VTY_NEWLINE);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100309 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100310 }
311 nse->persistent = true;
312 }
313
314 if (!nse->persistent) {
315 /* TODO: should the dynamic NSE removed? */
316 vty_out(vty, "A dynamic NSE with the specified NSEI already exists%s", VTY_NEWLINE);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100317 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100318 }
319
320 vty->node = L_NS_NSE_NODE;
321 vty->index = nse;
322
323 return CMD_SUCCESS;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100324
325err:
326 if (free_vnse)
327 talloc_free(vnse);
328
329 return CMD_ERR_INCOMPLETE;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100330}
331
332DEFUN(cfg_no_ns_nsei, cfg_no_ns_nsei_cmd,
333 "no nse <0-65535>",
334 NO_STR
335 "Delete a Persistent NS Entity\n"
336 "NS Entity ID (NSEI)\n"
337 )
338{
339 struct gprs_ns2_nse *nse;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100340 struct vty_nse *vnse;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100341 uint16_t nsei = atoi(argv[0]);
342
343 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
344 if (!nse) {
345 vty_out(vty, "Can not find NS Entity %s%s", argv[0], VTY_NEWLINE);
346 return CMD_ERR_NOTHING_TODO;
347 }
348
349 if (!nse->persistent) {
350 vty_out(vty, "Ignoring non-persistent NS Entity%s", VTY_NEWLINE);
351 return CMD_WARNING;
352 }
353
354 vty_out(vty, "Deleting NS Entity %u%s", nse->nsei, VTY_NEWLINE);
355 gprs_ns2_free_nse(nse);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100356
357 vnse = vty_nse_by_nsei(nsei);
358 vty_nse_free(vnse);
359
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100360 return CMD_SUCCESS;
361}
362
363/* TODO: add fr/gre */
364DEFUN(cfg_ns_bind, cfg_ns_bind_cmd,
365 "bind (fr|udp) ID",
Harald Welte2230a912021-03-04 20:09:50 +0100366 "Configure local Bind\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100367 "Frame Relay\n" "UDP/IP\n"
Harald Welte2230a912021-03-04 20:09:50 +0100368 "Unique identifier for this bind (to reference from NS-VCs, NSEs, ...)\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100369 )
370{
371 const char *nstype = argv[0];
372 const char *name = argv[1];
373 struct vty_bind *vbind;
374 enum gprs_ns2_ll ll;
375 int rc;
376
377 rc = get_string_value(vty_ll_names, nstype);
378 if (rc < 0)
379 return CMD_WARNING;
380 ll = (enum gprs_ns2_ll) rc;
381
382 if (!osmo_identifier_valid(name)) {
383 vty_out(vty, "Invalid ID. The ID should be only alphanumeric.%s", VTY_NEWLINE);
384 return CMD_WARNING;
385 }
386
387 vbind = vty_bind_by_name(name);
388 if (vbind) {
389 if (vbind->ll != ll) {
390 vty_out(vty, "A bind with the specified ID already exists with a different type (fr|frgre|udp)!%s",
391 VTY_NEWLINE);
392 return CMD_WARNING;
393 }
394 } else {
395 vbind = vty_bind_alloc(name);
396 if (!vbind) {
397 vty_out(vty, "Can not create bind - out of memory%s", VTY_NEWLINE);
398 return CMD_WARNING;
399 }
400 vbind->ll = ll;
401 }
402
403 vty->index = vbind;
404 vty->node = L_NS_BIND_NODE;
405
406 return CMD_SUCCESS;
407}
408
409DEFUN(cfg_no_ns_bind, cfg_no_ns_bind_cmd,
410 "no bind ID",
411 NO_STR
Harald Welte2230a912021-03-04 20:09:50 +0100412 "Delete a bind\n"
413 "Unique identifier for this bind\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100414 )
415{
416 struct vty_bind *vbind;
417 struct gprs_ns2_vc_bind *bind;
418 const char *name = argv[0];
419
420 vbind = vty_bind_by_name(name);
421 if (!vbind) {
422 vty_out(vty, "bind %s does not exist!%s", name, VTY_NEWLINE);
423 return CMD_WARNING;
424 }
425 vty_bind_free(vbind);
426 bind = gprs_ns2_bind_by_name(vty_nsi, name);
427 if (bind)
Alexander Couzens56287d22021-07-06 10:56:55 +0200428 gprs_ns2_free_bind(bind);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100429 return CMD_SUCCESS;
430}
431
432
433static void config_write_vbind(struct vty *vty, struct vty_bind *vbind)
434{
435 struct gprs_ns2_vc_bind *bind;
436 const struct osmo_sockaddr *addr;
437 struct osmo_sockaddr_str addr_str;
438 const char *netif, *frrole_str, *llstr;
439 enum osmo_fr_role frrole;
440
441 llstr = get_value_string_or_null(vty_ll_names, vbind->ll);
442 if (!llstr)
443 return;
444 vty_out(vty, " bind %s %s%s", llstr, vbind->name, VTY_NEWLINE);
445
446 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
447 switch (vbind->ll) {
448 case GPRS_NS2_LL_FR:
449 if (bind) {
450 netif = gprs_ns2_fr_bind_netif(bind);
451 if (!netif)
452 return;
453 frrole = gprs_ns2_fr_bind_role(bind);
454 if ((int) frrole == -1)
455 return;
456 frrole_str = get_value_string_or_null(vty_fr_role_names, frrole);
457 if (netif && frrole_str)
458 vty_out(vty, " fr %s %s%s", netif, frrole_str, VTY_NEWLINE);
459 }
460 break;
461 case GPRS_NS2_LL_UDP:
462 if (bind) {
463 addr = gprs_ns2_ip_bind_sockaddr(bind);
464 if (!osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas)) {
465 vty_out(vty, " listen %s %u%s", addr_str.ip, addr_str.port,
466 VTY_NEWLINE);
467 }
468 }
469 if (vbind->accept_ipaccess)
470 vty_out(vty, " accept-ipaccess%s", VTY_NEWLINE);
Harald Welte42e36462021-03-03 18:12:09 +0100471 if (vbind->accept_sns)
472 vty_out(vty, " accept-dynamic-ip-sns%s", VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100473 if (vbind->dscp)
474 vty_out(vty, " dscp %u%s", vbind->dscp, VTY_NEWLINE);
Harald Welted99e4ee2021-04-28 19:57:12 +0200475 if (vbind->priority)
Harald Welte5782fec2021-04-29 21:28:53 +0200476 vty_out(vty, " socket-priority %u%s", vbind->priority, VTY_NEWLINE);
Daniel Willmann64db6362021-02-12 12:21:45 +0100477 vty_out(vty, " ip-sns signalling-weight %u data-weight %u%s",
Alexander Couzensc4704762021-02-08 23:13:12 +0100478 vbind->ip_sns_sig_weight, vbind->ip_sns_data_weight, VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100479 break;
480 default:
481 return;
482 }
483}
484
485static void config_write_nsvc(struct vty *vty, const struct gprs_ns2_vc *nsvc)
486{
487 const char *netif;
488 uint16_t dlci;
489 const struct osmo_sockaddr *addr;
490 struct osmo_sockaddr_str addr_str;
491
492 switch (nsvc->nse->ll) {
493 case GPRS_NS2_LL_UNDEF:
494 break;
495 case GPRS_NS2_LL_UDP:
496 switch (nsvc->nse->dialect) {
497 case GPRS_NS2_DIALECT_IPACCESS:
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 ipa %s %s %u nsvci %u%s",
504 nsvc->bind->name, addr_str.ip, addr_str.port,
505 nsvc->nsvci, VTY_NEWLINE);
506 break;
507 case GPRS_NS2_DIALECT_STATIC_ALIVE:
508 addr = gprs_ns2_ip_vc_remote(nsvc);
509 if (!addr)
510 break;
511 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas))
512 break;
513 vty_out(vty, " nsvc udp %s %s %u%s",
514 nsvc->bind->name, addr_str.ip, addr_str.port, VTY_NEWLINE);
515 break;
516 default:
517 break;
518 }
519 break;
520 case GPRS_NS2_LL_FR:
521 netif = gprs_ns2_fr_bind_netif(nsvc->bind);
522 if (!netif)
523 break;
524 dlci = gprs_ns2_fr_nsvc_dlci(nsvc);
525 if (!dlci)
526 break;
527 OSMO_ASSERT(nsvc->nsvci_is_valid);
528 vty_out(vty, " nsvc fr %s dlci %u nsvci %u%s",
529 netif, dlci, nsvc->nsvci, VTY_NEWLINE);
530 break;
531 case GPRS_NS2_LL_FR_GRE:
532 break;
533 }
534}
535
536static void _config_write_ns_nse(struct vty *vty, struct gprs_ns2_nse *nse)
537{
538 struct gprs_ns2_vc *nsvc;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100539 struct vty_nse *vnse = vty_nse_by_nsei(nse->nsei);
540 struct vty_nse_bind *vbind;
541
542 OSMO_ASSERT(vnse);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100543
Harald Welte579699b2021-03-05 10:22:23 +0100544 vty_out(vty, " nse %u%s%s", nse->nsei,
545 nse->ip_sns_role_sgsn ? " ip-sns-role-sgsn" : "", VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100546 switch (nse->dialect) {
547 case GPRS_NS2_DIALECT_SNS:
548 ns2_sns_write_vty(vty, nse);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100549 llist_for_each_entry(vbind, &vnse->binds, list) {
550 vty_out(vty, " ip-sns-bind %s%s", vbind->vbind->name, VTY_NEWLINE);
551 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100552 break;
553 default:
554 llist_for_each_entry(nsvc, &nse->nsvc, list) {
555 config_write_nsvc(vty, nsvc);
556 }
557 break;
558 }
559}
560
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100561static int config_write_ns_nse(struct vty *vty)
562{
563 struct gprs_ns2_nse *nse;
564
565 llist_for_each_entry(nse, &vty_nsi->nse, list) {
566 if (!nse->persistent)
567 continue;
568
569 _config_write_ns_nse(vty, nse);
570 }
571
572 return 0;
573}
574
575static int config_write_ns_bind(struct vty *vty)
576{
577 struct vty_bind *vbind;
578
579 llist_for_each_entry(vbind, &binds, list) {
580 config_write_vbind(vty, vbind);
581 }
582
583 return 0;
584}
585
Alexander Couzens260cd522021-01-28 20:31:31 +0100586static int config_write_ns(struct vty *vty)
587{
Harald Welted164ef82021-03-04 22:29:17 +0100588 struct vty_nse_bind *vbind;
Alexander Couzens260cd522021-01-28 20:31:31 +0100589 unsigned int i;
590 int ret;
591
592 vty_out(vty, "ns%s", VTY_NEWLINE);
593
594 for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++)
595 vty_out(vty, " timer %s %u%s",
596 get_value_string(gprs_ns_timer_strs, i),
597 vty_nsi->timeout[i], VTY_NEWLINE);
598
Daniel Willmann3236fdf2023-08-29 16:24:56 +0200599 if (vty_nsi->txqueue_max_length != NS_DEFAULT_TXQUEUE_MAX_LENGTH)
600 vty_out(vty, " txqueue-max-length %u%s", vty_nsi->txqueue_max_length, VTY_NEWLINE);
601
Alexander Couzens260cd522021-01-28 20:31:31 +0100602 ret = config_write_ns_bind(vty);
603 if (ret)
604 return ret;
605
Harald Welted164ef82021-03-04 22:29:17 +0100606 llist_for_each_entry(vbind, &ip_sns_default_binds, list) {
607 vty_out(vty, " ip-sns-default bind %s%s", vbind->vbind->name, VTY_NEWLINE);
608 }
609
Alexander Couzens260cd522021-01-28 20:31:31 +0100610 ret = config_write_ns_nse(vty);
611 if (ret)
612 return ret;
613
614 return 0;
615}
616
617
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100618static struct cmd_node ns_bind_node = {
619 L_NS_BIND_NODE,
620 "%s(config-ns-bind)# ",
621 1,
622};
623
624DEFUN(cfg_ns_bind_listen, cfg_ns_bind_listen_cmd,
625 "listen " VTY_IPV46_CMD " <1-65535>",
Harald Welte2230a912021-03-04 20:09:50 +0100626 "Configure local IP + Port of this bind\n"
627 "Local IPv4 Address\n" "Local IPv6 Address\n"
628 "Local UDP Port\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100629 )
630{
631 struct vty_bind *vbind = vty->index;
632 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100633 int rc;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100634 const char *addr_str = argv[0];
635 unsigned int port = atoi(argv[1]);
636 struct osmo_sockaddr_str sockaddr_str;
637 struct osmo_sockaddr sockaddr;
638
639 if (vbind->ll != GPRS_NS2_LL_UDP) {
640 vty_out(vty, "listen can be only used with UDP bind%s",
641 VTY_NEWLINE);
642 return CMD_WARNING;
643 }
644
645 if (osmo_sockaddr_str_from_str(&sockaddr_str, addr_str, port)) {
646 vty_out(vty, "Can not parse the Address %s %s%s", argv[0], argv[1], VTY_NEWLINE);
647 return CMD_WARNING;
648 }
649 osmo_sockaddr_str_to_sockaddr(&sockaddr_str, &sockaddr.u.sas);
650 if (gprs_ns2_ip_bind_by_sockaddr(vty_nsi, &sockaddr)) {
651 vty_out(vty, "A bind with the specified address already exists!%s", VTY_NEWLINE);
652 return CMD_WARNING;
653 }
654
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100655 rc = gprs_ns2_ip_bind(vty_nsi, vbind->name, &sockaddr, vbind->dscp, &bind);
656 if (rc != 0) {
657 vty_out(vty, "Failed to create the bind (rc %d)!%s", rc, VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100658 return CMD_WARNING;
659 }
660
661 bind->accept_ipaccess = vbind->accept_ipaccess;
662 bind->accept_sns = vbind->accept_sns;
663
664 return CMD_SUCCESS;
665}
666
667DEFUN(cfg_no_ns_bind_listen, cfg_no_ns_bind_listen_cmd,
668 "no listen",
669 NO_STR
670 "Delete a IP/Port assignment\n"
671 )
672{
673 struct vty_bind *vbind = vty->index;
674 struct gprs_ns2_vc_bind *bind;
675
676 if (vbind->ll != GPRS_NS2_LL_UDP) {
677 vty_out(vty, "no listen can be only used with UDP bind%s", VTY_NEWLINE);
678 return CMD_WARNING;
679 }
680
681 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
682 if (!bind)
683 return CMD_ERR_NOTHING_TODO;
684
Daniel Willmann90432052021-01-26 16:09:18 +0100685 OSMO_ASSERT(bind->ll == GPRS_NS2_LL_UDP);
Alexander Couzens56287d22021-07-06 10:56:55 +0200686 gprs_ns2_free_bind(bind);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100687 return CMD_SUCCESS;
688}
689
690DEFUN(cfg_ns_bind_dscp, cfg_ns_bind_dscp_cmd,
Harald Weltec96d7162021-04-27 21:56:25 +0200691 "dscp <0-63>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100692 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
693{
694 struct vty_bind *vbind = vty->index;
695 struct gprs_ns2_vc_bind *bind;
696 uint16_t dscp = atoi(argv[0]);
697
698 if (vbind->ll != GPRS_NS2_LL_UDP) {
699 vty_out(vty, "dscp can be only used with UDP bind%s",
700 VTY_NEWLINE);
701 return CMD_WARNING;
702 }
703
704 vbind->dscp = dscp;
705 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
706 if (bind)
707 gprs_ns2_ip_bind_set_dscp(bind, dscp);
708
709 return CMD_SUCCESS;
710}
711
712DEFUN(cfg_no_ns_bind_dscp, cfg_no_ns_bind_dscp_cmd,
713 "no dscp",
714 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
715{
716 struct vty_bind *vbind = vty->index;
717 struct gprs_ns2_vc_bind *bind;
718 uint16_t dscp = 0;
719
720 if (vbind->ll != GPRS_NS2_LL_UDP) {
721 vty_out(vty, "dscp can be only used with UDP bind%s",
722 VTY_NEWLINE);
723 return CMD_WARNING;
724 }
725
726 vbind->dscp = dscp;
727 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
728 if (bind)
729 gprs_ns2_ip_bind_set_dscp(bind, dscp);
730
731 return CMD_SUCCESS;
732}
733
Harald Welted99e4ee2021-04-28 19:57:12 +0200734DEFUN(cfg_ns_bind_priority, cfg_ns_bind_priority_cmd,
Harald Welte5782fec2021-04-29 21:28:53 +0200735 "socket-priority <0-255>",
Harald Welted99e4ee2021-04-28 19:57:12 +0200736 "Set socket priority on the UDP socket\n" "Priority Value (>6 requires CAP_NET_ADMIN)\n")
737{
738 struct vty_bind *vbind = vty->index;
739 struct gprs_ns2_vc_bind *bind;
740 uint8_t prio = atoi(argv[0]);
741
742 if (vbind->ll != GPRS_NS2_LL_UDP) {
743 vty_out(vty, "dscp can be only used with UDP bind%s",
744 VTY_NEWLINE);
745 return CMD_WARNING;
746 }
747
748 vbind->priority = prio;
749 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
750 if (bind)
751 gprs_ns2_ip_bind_set_priority(bind, prio);
752
753 return CMD_SUCCESS;
754}
755
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100756DEFUN(cfg_ns_bind_ipaccess, cfg_ns_bind_ipaccess_cmd,
757 "accept-ipaccess",
758 "Allow to create dynamic NS Entity by NS Reset PDU on UDP (ip.access style)\n"
759 )
760{
761 struct vty_bind *vbind = vty->index;
762 struct gprs_ns2_vc_bind *bind;
763
764 if (vbind->ll != GPRS_NS2_LL_UDP) {
765 vty_out(vty, "accept-ipaccess can be only used with UDP bind%s",
766 VTY_NEWLINE);
767 return CMD_WARNING;
768 }
769
770 vbind->accept_ipaccess = true;
771 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
772 if (bind)
773 bind->accept_ipaccess = true;
774
775 return CMD_SUCCESS;
776}
777
778DEFUN(cfg_no_ns_bind_ipaccess, cfg_no_ns_bind_ipaccess_cmd,
779 "no accept-ipaccess",
780 NO_STR
781 "Reject NS Reset PDU on UDP (ip.access style)\n"
782 )
783{
784 struct vty_bind *vbind = vty->index;
785 struct gprs_ns2_vc_bind *bind;
786
787 if (vbind->ll != GPRS_NS2_LL_UDP) {
788 vty_out(vty, "no accept-ipaccess can be only used with UDP bind%s",
789 VTY_NEWLINE);
790 return CMD_WARNING;
791 }
792
793 vbind->accept_ipaccess = false;
794 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
795 if (bind)
796 bind->accept_ipaccess = false;
797
798 return CMD_SUCCESS;
799}
800
Harald Welte42e36462021-03-03 18:12:09 +0100801DEFUN(cfg_ns_bind_accept_sns, cfg_ns_bind_accept_sns_cmd,
802 "accept-dynamic-ip-sns",
803 "Allow to create dynamic NS Entities by IP-SNS PDUs\n"
804 )
805{
806 struct vty_bind *vbind = vty->index;
807 struct gprs_ns2_vc_bind *bind;
808
809 if (vbind->ll != GPRS_NS2_LL_UDP) {
810 vty_out(vty, "accept-dynamic-ip-sns can be only used with UDP bind%s",
811 VTY_NEWLINE);
812 return CMD_WARNING;
813 }
814
815 vbind->accept_sns = true;
816 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
817 if (bind)
818 bind->accept_sns = true;
819
820 return CMD_SUCCESS;
821}
822
823DEFUN(cfg_no_ns_bind_accept_sns, cfg_no_ns_bind_accept_sns_cmd,
824 "no accept-dynamic-ip-sns",
825 NO_STR
826 "Disable dynamic creation of NS Entities by IP-SNS PDUs\n"
827 )
828{
829 struct vty_bind *vbind = vty->index;
830 struct gprs_ns2_vc_bind *bind;
831
832 if (vbind->ll != GPRS_NS2_LL_UDP) {
833 vty_out(vty, "no accept-dynamic-ip-sns can be only used with UDP bind%s",
834 VTY_NEWLINE);
835 return CMD_WARNING;
836 }
837
838 vbind->accept_sns = false;
839 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
840 if (bind)
841 bind->accept_sns = false;
842
843 return CMD_SUCCESS;
844}
845
Alexander Couzensc4704762021-02-08 23:13:12 +0100846DEFUN(cfg_ns_bind_ip_sns_weight, cfg_ns_bind_ip_sns_weight_cmd,
847 "ip-sns signalling-weight <0-254> data-weight <0-254>",
848 "IP SNS\n"
849 "signalling weight used by IP-SNS dynamic configuration\n"
850 "signalling weight used by IP-SNS dynamic configuration\n"
851 "data weight used by IP-SNS dynamic configuration\n"
852 "data weight used by IP-SNS dynamic configuration\n")
853{
854 struct vty_bind *vbind = vty->index;
855 struct gprs_ns2_vc_bind *bind;
856
857 int signalling = atoi(argv[0]);
858 int data = atoi(argv[1]);
859
860 if (vbind->ll != GPRS_NS2_LL_UDP) {
861 vty_out(vty, "ip-sns signalling-weight <0-254> data-weight <0-254> can be only used with UDP bind%s",
862 VTY_NEWLINE);
863 return CMD_WARNING;
864 }
865
866 vbind->ip_sns_data_weight = data;
867 vbind->ip_sns_sig_weight = signalling;
868 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
869 if (bind)
870 gprs_ns2_ip_bind_set_sns_weight(bind, signalling, data);
871
872 return CMD_SUCCESS;
873}
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100874
875DEFUN(cfg_ns_bind_fr, cfg_ns_bind_fr_cmd,
876 "fr NETIF (fr|frnet)",
877 "frame relay\n"
878 IFNAME_STR
879 "fr (user) is used by BSS or SGSN attached to UNI of a FR network\n"
880 "frnet (network) is used by SGSN if BSS is directly attached\n"
881 )
882{
883 struct vty_bind *vbind = vty->index;
884 struct gprs_ns2_vc_bind *bind;
885 const char *netif = argv[0];
886 const char *role = argv[1];
887
888 int rc = 0;
889 enum osmo_fr_role frrole;
890
891 if (vbind->ll != GPRS_NS2_LL_FR) {
892 vty_out(vty, "fr can be only used with frame relay bind%s", VTY_NEWLINE);
893 return CMD_WARNING;
894 }
895
896 if (!strcmp(role, "fr"))
897 frrole = FR_ROLE_USER_EQUIPMENT;
898 else if (!strcmp(role, "frnet"))
899 frrole = FR_ROLE_NETWORK_EQUIPMENT;
900 else
901 return CMD_WARNING;
902
903 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
904 if (bind) {
905 vty_out(vty, "Interface %s already used.%s", netif, VTY_NEWLINE);
906 return CMD_WARNING;
907 }
908
909 rc = gprs_ns2_fr_bind(vty_nsi, vbind->name, netif, vty_fr_network, frrole, &bind);
910 if (rc < 0) {
911 LOGP(DLNS, LOGL_ERROR, "Failed to bind interface %s on fr. Err: %d\n", netif, rc);
912 return CMD_WARNING;
913 }
914
915 return CMD_SUCCESS;
916}
917
918DEFUN(cfg_no_ns_bind_fr, cfg_no_ns_bind_fr_cmd,
919 "no fr NETIF",
920 NO_STR
921 "Delete a frame relay link\n"
922 "Delete a frame relay link\n"
923 IFNAME_STR
924 )
925{
926 struct vty_bind *vbind = vty->index;
927 struct gprs_ns2_vc_bind *bind;
928 const char *netif = argv[0];
929
930 if (vbind->ll != GPRS_NS2_LL_FR) {
931 vty_out(vty, "fr can be only used with frame relay bind%s",
932 VTY_NEWLINE);
933 return CMD_WARNING;
934 }
935
936 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
937 if (!bind) {
938 vty_out(vty, "Interface not found.%s", VTY_NEWLINE);
939 return CMD_WARNING;
940 }
941
942 if (strcmp(bind->name, vbind->name)) {
943 vty_out(vty, "The specified interface is not bound to this bind.%s", VTY_NEWLINE);
944 return CMD_WARNING;
945 }
946
Alexander Couzens56287d22021-07-06 10:56:55 +0200947 gprs_ns2_free_bind(bind);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100948 return CMD_SUCCESS;
949}
950
951
952static struct cmd_node ns_nse_node = {
953 L_NS_NSE_NODE,
954 "%s(config-ns-nse)# ",
955 1,
956};
957
958DEFUN(cfg_ns_nse_nsvc_fr, cfg_ns_nse_nsvc_fr_cmd,
959 "nsvc fr NETIF dlci <16-1007> nsvci <0-65535>",
960 "NS Virtual Connection\n"
961 "frame relay\n"
962 "frame relay interface. Must be registered via fr vty\n"
963 NSVCI_STR
964 NSVCI_STR
965 DLCI_STR
966 DLCI_STR
967 )
968{
969 struct gprs_ns2_vc_bind *bind;
970 struct gprs_ns2_vc *nsvc;
971 struct gprs_ns2_nse *nse = vty->index;
972 const char *netif = argv[0];
973 uint16_t dlci = atoi(argv[1]);
974 uint16_t nsvci = atoi(argv[2]);
975 bool dialect_modified = false;
976 bool ll_modified = false;
977
978 if (nse->ll != GPRS_NS2_LL_FR && nse->ll != GPRS_NS2_LL_UNDEF) {
979 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
980 goto err;
981 }
982
983 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_RESETBLOCK && nse->dialect != GPRS_NS2_DIALECT_UNDEF) {
984 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
985 goto err;
986 }
987
988 if (nse->ll == GPRS_NS2_LL_UNDEF) {
989 nse->ll = GPRS_NS2_LL_FR;
990 ll_modified = true;
991 }
992
993 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +0100994 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_STATIC_RESETBLOCK);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100995 dialect_modified = true;
996 }
997
998
999 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
1000 if (!bind) {
1001 vty_out(vty, "Can not find fr interface \"%s\". Please configure it via fr vty.%s",
1002 netif, VTY_NEWLINE);
1003 goto err;
1004 }
1005
1006 if (gprs_ns2_fr_nsvc_by_dlci(bind, dlci)) {
1007 vty_out(vty, "A NS-VC with the specified DLCI already exist!%s", VTY_NEWLINE);
1008 goto err;
1009 }
1010
1011 if (gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci)) {
1012 vty_out(vty, "A NS-VC with the specified NS-VCI already exist!%s", VTY_NEWLINE);
1013 goto err;
1014 }
1015
1016 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
1017 if (!nsvc) {
1018 /* Could not create NS-VC, connect failed */
1019 vty_out(vty, "Failed to create the NS-VC%s", VTY_NEWLINE);
1020 goto err;
1021 }
1022 nsvc->persistent = true;
1023 return CMD_SUCCESS;
1024
1025err:
1026 if (ll_modified)
1027 nse->ll = GPRS_NS2_LL_UNDEF;
1028 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001029 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001030
1031 return CMD_WARNING;
1032}
1033
1034DEFUN(cfg_no_ns_nse_nsvc_fr_dlci, cfg_no_ns_nse_nsvc_fr_dlci_cmd,
1035 "no nsvc fr NETIF dlci <16-1007>",
1036 NO_STR
1037 "Delete frame relay NS-VC\n"
1038 "frame relay\n"
1039 "frame relay interface. Must be registered via fr vty\n"
1040 DLCI_STR
1041 DLCI_STR
1042 )
1043{
1044 struct gprs_ns2_vc_bind *bind;
1045 struct gprs_ns2_vc *nsvc;
1046 struct gprs_ns2_nse *nse = vty->index;
1047 const char *netif = argv[0];
1048 uint16_t dlci = atoi(argv[1]);
1049
1050 if (nse->ll != GPRS_NS2_LL_FR) {
1051 vty_out(vty, "This NSE doesn't support frame relay.%s", VTY_NEWLINE);
1052 return CMD_WARNING;
1053 }
1054
1055 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
1056 if (!bind) {
1057 vty_out(vty, "Can not find fr interface \"%s\"%s",
1058 netif, VTY_NEWLINE);
1059 return CMD_ERR_NOTHING_TODO;
1060 }
1061
1062 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
1063 if (!nsvc) {
1064 vty_out(vty, "Can not find a NS-VC on fr interface %s with dlci %u%s",
1065 netif, dlci, VTY_NEWLINE);
1066 return CMD_WARNING;
1067 }
1068
1069 if (nse != nsvc->nse) {
1070 vty_out(vty, "The specified NS-VC is not a part of the NSE %u!%s"
1071 "To remove this NS-VC go to the vty node 'nse %u'%s",
1072 nse->nsei, VTY_NEWLINE,
1073 nsvc->nse->nsei, VTY_NEWLINE);
1074 return CMD_WARNING;
1075 }
1076
1077 gprs_ns2_free_nsvc(nsvc);
1078 if (llist_empty(&nse->nsvc)) {
1079 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001080 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001081 }
1082
1083 return CMD_SUCCESS;
1084}
1085
1086DEFUN(cfg_no_ns_nse_nsvci, cfg_no_ns_nse_nsvci_cmd,
1087 "no nsvc nsvci <0-65535>",
1088 NO_STR
1089 "Delete NSVC\n"
1090 NSVCI_STR
1091 NSVCI_STR
1092 )
1093{
1094 struct gprs_ns2_vc *nsvc;
1095 struct gprs_ns2_nse *nse = vty->index;
1096 uint16_t nsvci = atoi(argv[0]);
1097
1098 switch (nse->dialect) {
1099 case GPRS_NS2_DIALECT_SNS:
1100 case GPRS_NS2_DIALECT_STATIC_ALIVE:
1101 vty_out(vty, "NSE doesn't support NSVCI.%s", VTY_NEWLINE);
1102 return CMD_WARNING;
1103 case GPRS_NS2_DIALECT_UNDEF:
1104 vty_out(vty, "No NSVCs configured%s", VTY_NEWLINE);
1105 return CMD_WARNING;
1106 case GPRS_NS2_DIALECT_IPACCESS:
1107 case GPRS_NS2_DIALECT_STATIC_RESETBLOCK:
1108 break;
1109 }
1110
1111 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci);
1112 if (!nsvc) {
1113 vty_out(vty, "Can not find NS-VC with NS-VCI %u%s", nsvci, VTY_NEWLINE);
1114 return CMD_WARNING;
1115 }
1116
1117 if (nse != nsvc->nse) {
1118 vty_out(vty, "NS-VC with NS-VCI %u is not part of this NSE!%s",
1119 nsvci, VTY_NEWLINE);
1120 return CMD_WARNING;
1121 }
1122
1123 gprs_ns2_free_nsvc(nsvc);
1124 if (llist_empty(&nse->nsvc)) {
1125 nse->ll = GPRS_NS2_LL_UNDEF;
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 }
1128
1129 return CMD_SUCCESS;
1130}
1131
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001132static int ns_nse_nsvc_udp_cmds(struct vty *vty, const char *bind_name, const char *remote_char, uint16_t port,
1133 uint16_t sig_weight, uint16_t data_weight)
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001134{
1135 struct gprs_ns2_vc_bind *bind;
1136 struct gprs_ns2_vc *nsvc;
1137 struct gprs_ns2_nse *nse = vty->index;
1138 bool dialect_modified = false;
1139 bool ll_modified = false;
1140
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001141 struct osmo_sockaddr_str remote_str;
1142 struct osmo_sockaddr remote;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001143
1144 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1145 nse->ll = GPRS_NS2_LL_UDP;
1146 ll_modified = true;
1147 }
1148
1149 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001150 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_STATIC_ALIVE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001151 dialect_modified = true;
1152 }
1153
1154 if (nse->ll != GPRS_NS2_LL_UDP) {
1155 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1156 goto err;
1157 }
1158
1159 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
1160 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1161 goto err;
1162 }
1163
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001164 if (osmo_sockaddr_str_from_str(&remote_str, remote_char, port)) {
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001165 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1166 goto err;
1167 }
1168
1169 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1170 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1171 goto err;
1172 }
1173
1174 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1175 if (!bind) {
1176 vty_out(vty, "Can not find bind with name %s%s",
1177 bind_name, VTY_NEWLINE);
1178 goto err;
1179 }
1180
1181 if (bind->ll != GPRS_NS2_LL_UDP) {
1182 vty_out(vty, "Bind %s is not an UDP bind.%s",
1183 bind_name, VTY_NEWLINE);
1184 goto err;
1185 }
1186
Alexander Couzens7bb39e32021-02-16 23:06:53 +01001187 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1188 if (nsvc) {
1189 if (nsvc->nse == nse)
1190 vty_out(vty, "Specified NSVC is already present in this NSE.%s", VTY_NEWLINE);
1191 else
1192 vty_out(vty, "Specified NSVC is already present in another NSE%05u.%s", nsvc->nse->nsei, VTY_NEWLINE);
1193 goto err;
1194 }
1195
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001196 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, 0);
1197 if (!nsvc) {
1198 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
1199 goto err;
1200 }
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001201 nsvc->sig_weight = sig_weight;
1202 nsvc->data_weight = data_weight;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001203 nsvc->persistent = true;
1204
1205 return CMD_SUCCESS;
1206
1207err:
1208 if (ll_modified)
1209 nse->ll = GPRS_NS2_LL_UNDEF;
1210 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001211 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001212 return CMD_WARNING;
1213}
1214
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001215DEFUN(cfg_ns_nse_nsvc_udp, cfg_ns_nse_nsvc_udp_cmd,
1216 "nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
1217 "NS Virtual Connection\n"
1218 "NS over UDP\n"
1219 "A unique bind identifier created by ns bind\n"
1220 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1221 "Remote UDP Port\n")
1222{
1223 const char *bind_name = argv[0];
1224 const char *remote = argv[1];
1225 uint16_t port = atoi(argv[2]);
1226 uint16_t sig_weight = 1;
1227 uint16_t data_weight = 1;
1228
1229 return ns_nse_nsvc_udp_cmds(vty, bind_name, remote, port, sig_weight, data_weight);
1230}
1231
1232DEFUN(cfg_ns_nse_nsvc_udp_weights, cfg_ns_nse_nsvc_udp_weights_cmd,
1233 "nsvc udp BIND " VTY_IPV46_CMD " <1-65535> signalling-weight <0-254> data-weight <0-254>",
1234 "NS Virtual Connection\n"
1235 "NS over UDP\n"
1236 "A unique bind identifier created by ns bind\n"
1237 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1238 "Remote UDP Port\n"
1239 "Signalling weight of the NSVC (default = 1)\n"
1240 "Signalling weight of the NSVC (default = 1)\n"
1241 "Data weight of the NSVC (default = 1)\n"
1242 "Data weight of the NSVC (default = 1)\n"
1243 )
1244{
1245 const char *bind_name = argv[0];
1246 const char *remote = argv[1];
1247 uint16_t port = atoi(argv[2]);
1248 uint16_t sig_weight = atoi(argv[3]);
1249 uint16_t data_weight = atoi(argv[4]);
1250
1251 return ns_nse_nsvc_udp_cmds(vty, bind_name, remote, port, sig_weight, data_weight);
1252}
1253
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001254DEFUN(cfg_no_ns_nse_nsvc_udp, cfg_no_ns_nse_nsvc_udp_cmd,
1255 "no nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
1256 NO_STR
1257 "Delete a NS Virtual Connection\n"
1258 "NS over UDP\n"
1259 "A unique bind identifier created by ns bind\n"
1260 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1261 "Remote UDP Port\n"
1262 )
1263{
1264 struct gprs_ns2_vc_bind *bind;
1265 struct gprs_ns2_vc *nsvc;
1266 struct gprs_ns2_nse *nse = vty->index;
1267 const char *bind_name = argv[0];
1268 struct osmo_sockaddr_str remote_str;
1269 struct osmo_sockaddr remote;
1270 uint16_t port = atoi(argv[2]);
1271
1272 if (nse->ll != GPRS_NS2_LL_UDP) {
1273 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1274 return CMD_WARNING;
1275 }
1276
1277 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
1278 vty_out(vty, "This NSE doesn't support UDP with dialect static alive.%s", VTY_NEWLINE);
1279 return CMD_WARNING;
1280 }
1281
1282 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1283 if (!bind) {
1284 vty_out(vty, "Can not find bind with name %s%s",
1285 bind_name, VTY_NEWLINE);
1286 return CMD_WARNING;
1287 }
1288
1289 if (bind->ll != GPRS_NS2_LL_UDP) {
1290 vty_out(vty, "Bind %s is not an UDP bind.%s",
1291 bind_name, VTY_NEWLINE);
1292 return CMD_WARNING;
1293 }
1294
1295 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1296 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1297 return CMD_WARNING;
1298 }
1299
1300 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1301 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1302 return CMD_WARNING;
1303 }
1304
1305 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1306 if (!nsvc) {
1307 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1308 remote_str.ip, remote_str.port, VTY_NEWLINE);
1309 return CMD_WARNING;
1310 }
1311
1312 if (!nsvc->persistent) {
1313 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1314 remote_str.ip, remote_str.port, VTY_NEWLINE);
1315 return CMD_WARNING;
1316 }
1317
1318 if (nsvc->nse != nse) {
1319 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1320 return CMD_WARNING;
1321 }
1322
1323 gprs_ns2_free_nsvc(nsvc);
1324 if (llist_empty(&nse->nsvc)) {
1325 nse->ll = GPRS_NS2_LL_UNDEF;
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 }
1328
1329 return CMD_SUCCESS;
1330}
1331
1332DEFUN(cfg_ns_nse_nsvc_ipa, cfg_ns_nse_nsvc_ipa_cmd,
1333 "nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>" ,
1334 "NS Virtual Connection\n"
1335 "NS over UDP ip.access style (uses RESET/BLOCK)\n"
1336 "A unique bind identifier created by ns bind\n"
1337 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1338 "Remote UDP Port\n"
1339 NSVCI_STR
1340 NSVCI_STR
1341 )
1342{
1343 struct gprs_ns2_vc_bind *bind;
1344 struct gprs_ns2_vc *nsvc;
1345 struct gprs_ns2_nse *nse = vty->index;
1346 bool dialect_modified = false;
1347 bool ll_modified = false;
1348
1349 const char *bind_name = argv[0];
1350 struct osmo_sockaddr_str remote_str;
1351 struct osmo_sockaddr remote;
1352 uint16_t port = atoi(argv[2]);
1353 uint16_t nsvci = atoi(argv[3]);
1354
1355 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1356 nse->ll = GPRS_NS2_LL_UDP;
1357 ll_modified = true;
1358 }
1359
1360 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001361 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_IPACCESS);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001362 dialect_modified = true;
1363 }
1364
1365 if (nse->ll != GPRS_NS2_LL_UDP) {
1366 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1367 goto err;
1368 }
1369
1370 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1371 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1372 goto err;
1373 }
1374
1375 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1376 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1377 goto err;
1378 }
1379
1380 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1381 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1382 goto err;
1383 }
1384
1385 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1386 if (!bind) {
1387 vty_out(vty, "Can not find bind with name %s%s",
1388 bind_name, VTY_NEWLINE);
1389 goto err;
1390 }
1391
1392 if (bind->ll != GPRS_NS2_LL_UDP) {
1393 vty_out(vty, "Bind %s is not an UDP bind.%s",
1394 bind_name, VTY_NEWLINE);
1395 goto err;
1396 }
1397
1398 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, nsvci);
1399 if (!nsvc) {
1400 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
1401 goto err;
1402 }
1403 nsvc->persistent = true;
1404
1405 return CMD_SUCCESS;
1406
1407err:
1408 if (ll_modified)
1409 nse->ll = GPRS_NS2_LL_UNDEF;
1410 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001411 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001412 return CMD_WARNING;
1413}
1414
1415DEFUN(cfg_no_ns_nse_nsvc_ipa, cfg_no_ns_nse_nsvc_ipa_cmd,
1416 "no nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>",
1417 NO_STR
1418 "Delete a NS Virtual Connection\n"
1419 "NS over UDP\n"
1420 "A unique bind identifier created by ns bind\n"
1421 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1422 "Remote UDP Port\n"
1423 NSVCI_STR
1424 NSVCI_STR
1425 )
1426{
1427 struct gprs_ns2_vc_bind *bind;
1428 struct gprs_ns2_vc *nsvc;
1429 struct gprs_ns2_nse *nse = vty->index;
1430 const char *bind_name = argv[0];
1431 struct osmo_sockaddr_str remote_str;
1432 struct osmo_sockaddr remote;
1433 uint16_t port = atoi(argv[2]);
1434 uint16_t nsvci = atoi(argv[3]);
1435
1436 if (nse->ll != GPRS_NS2_LL_UDP) {
1437 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1438 return CMD_WARNING;
1439 }
1440
1441 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1442 vty_out(vty, "This NSE doesn't support UDP with dialect ipaccess.%s", VTY_NEWLINE);
1443 return CMD_WARNING;
1444 }
1445
1446 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1447 if (!bind) {
1448 vty_out(vty, "Can not find bind with name %s%s",
1449 bind_name, VTY_NEWLINE);
1450 return CMD_WARNING;
1451 }
1452
1453 if (bind->ll != GPRS_NS2_LL_UDP) {
1454 vty_out(vty, "Bind %s is not an UDP bind.%s",
1455 bind_name, VTY_NEWLINE);
1456 return CMD_WARNING;
1457 }
1458
1459 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1460 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1461 return CMD_WARNING;
1462 }
1463
1464 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1465 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1466 return CMD_WARNING;
1467 }
1468
1469 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1470 if (!nsvc) {
1471 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1472 remote_str.ip, remote_str.port, VTY_NEWLINE);
1473 return CMD_WARNING;
1474 }
1475
1476 if (!nsvc->persistent) {
1477 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1478 remote_str.ip, remote_str.port, VTY_NEWLINE);
1479 return CMD_WARNING;
1480 }
1481
1482 if (nsvc->nse != nse) {
1483 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1484 return CMD_WARNING;
1485 }
1486
1487 if (!nsvc->nsvci_is_valid) {
1488 vty_out(vty, "NS-VC doesn't have a nsvci!%s", VTY_NEWLINE);
1489 return CMD_WARNING;
1490 }
1491
1492 if (nsvc->nsvci != nsvci) {
1493 vty_out(vty, "NS-VC has a different nsvci (%u)!%s",
1494 nsvc->nsvci, VTY_NEWLINE);
1495 return CMD_WARNING;
1496 }
1497
1498 gprs_ns2_free_nsvc(nsvc);
1499 if (llist_empty(&nse->nsvc)) {
1500 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001501 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001502 }
1503
1504 return CMD_SUCCESS;
1505}
1506
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001507DEFUN(cfg_ns_nse_ip_sns_remote, cfg_ns_nse_ip_sns_remote_cmd,
1508 "ip-sns-remote " VTY_IPV46_CMD " <1-65535>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001509 "SNS Initial Endpoint\n"
1510 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1511 "SGSN UDP Port\n"
1512 )
1513{
1514 struct gprs_ns2_nse *nse = vty->index;
1515 bool dialect_modified = false;
1516 bool ll_modified = false;
1517 int rc;
1518
1519 /* argv[0] */
1520 struct osmo_sockaddr_str remote_str;
1521 struct osmo_sockaddr remote;
1522 uint16_t port = atoi(argv[1]);
1523
1524 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1525 nse->ll = GPRS_NS2_LL_UDP;
1526 ll_modified = true;
1527 }
1528
1529 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001530 if (ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_SNS) < 0)
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001531 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001532 dialect_modified = true;
1533 }
1534
1535 if (nse->ll != GPRS_NS2_LL_UDP) {
1536 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1537 goto err;
1538 }
1539
1540 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1541 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1542 goto err;
1543 }
1544
1545 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1546 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1547 goto err;
1548 }
1549
1550 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1551 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1552 goto err;
1553 }
1554
1555 rc = gprs_ns2_sns_add_endpoint(nse, &remote);
1556 switch (rc) {
1557 case 0:
1558 return CMD_SUCCESS;
1559 case -EADDRINUSE:
1560 vty_out(vty, "Specified SNS endpoint already part of the NSE.%s", VTY_NEWLINE);
1561 return CMD_WARNING;
1562 default:
1563 vty_out(vty, "Can not add specified SNS endpoint.%s", VTY_NEWLINE);
1564 return CMD_WARNING;
1565 }
1566
1567err:
1568 if (ll_modified)
1569 nse->ll = GPRS_NS2_LL_UNDEF;
1570 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001571 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001572 return CMD_WARNING;
1573}
1574
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001575DEFUN(cfg_no_ns_nse_ip_sns_remote, cfg_no_ns_nse_ip_sns_remote_cmd,
1576 "no ip-sns-remote " VTY_IPV46_CMD " <1-65535>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001577 NO_STR
1578 "Delete a SNS Initial Endpoint\n"
1579 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1580 "SGSN UDP Port\n"
1581 )
1582{
1583 struct gprs_ns2_nse *nse = vty->index;
1584 struct osmo_sockaddr_str remote_str; /* argv[0] */
1585 struct osmo_sockaddr remote;
1586 uint16_t port = atoi(argv[1]);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001587
1588 if (nse->ll != GPRS_NS2_LL_UDP) {
1589 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1590 return CMD_WARNING;
1591 }
1592
1593 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1594 vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%s", VTY_NEWLINE);
1595 return CMD_WARNING;
1596 }
1597
1598 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1599 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1600 return CMD_WARNING;
1601 }
1602
1603 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1604 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1605 return CMD_WARNING;
1606 }
1607
1608 if (gprs_ns2_sns_del_endpoint(nse, &remote)) {
1609 vty_out(vty, "Can not remove specified SNS endpoint.%s", VTY_NEWLINE);
1610 return CMD_WARNING;
1611 }
1612
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001613 if (vty_nse_check_sns(nse)) {
1614 /* there is still sns configuration valid */
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001615 return CMD_SUCCESS;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001616 } else {
1617 /* clean up nse to allow other nsvc commands */
Harald Welte06d9bf92021-03-05 10:20:11 +01001618 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001619 nse->ll = GPRS_NS2_LL_UNDEF;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001620 }
1621
1622 return CMD_SUCCESS;
1623}
1624
Harald Welted164ef82021-03-04 22:29:17 +01001625/* add all IP-SNS default binds to the given NSE */
1626int ns2_sns_add_sns_default_binds(struct gprs_ns2_nse *nse)
1627{
1628 struct vty_nse_bind *vnse_bind;
1629 int count = 0;
1630
1631 OSMO_ASSERT(nse->ll == GPRS_NS2_LL_UDP);
1632 OSMO_ASSERT(nse->dialect == GPRS_NS2_DIALECT_SNS);
1633
1634 llist_for_each_entry(vnse_bind, &ip_sns_default_binds, list) {
1635 struct gprs_ns2_vc_bind *bind = gprs_ns2_bind_by_name(vty_nsi, vnse_bind->vbind->name);
1636 /* the bind might not yet created because "listen" is missing. */
1637 if (!bind)
1638 continue;
1639 gprs_ns2_sns_add_bind(nse, bind);
1640 count++;
1641 }
1642 return count;
1643}
1644
1645DEFUN(cfg_ns_ip_sns_default_bind, cfg_ns_ip_sns_default_bind_cmd,
1646 "ip-sns-default bind ID",
1647 "Defaults for dynamically created NSEs created by IP-SNS in SGSN role\n"
1648 "IP SNS binds\n"
1649 "Name of NS udp bind whose IP endpoint will be used as IP-SNS local endpoint. Can be given multiple times.\n")
1650{
1651 struct vty_bind *vbind;
1652 struct vty_nse_bind *vnse_bind;
1653 const char *name = argv[0];
1654
1655 vbind = vty_bind_by_name(name);
1656 if (!vbind) {
1657 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1658 return CMD_WARNING;
1659 }
1660
1661 if (vbind->ll != GPRS_NS2_LL_UDP) {
1662 vty_out(vty, "ip-sns-default bind can only be used with UDP bind%s", VTY_NEWLINE);
1663 return CMD_WARNING;
1664 }
1665
1666 llist_for_each_entry(vnse_bind, &ip_sns_default_binds, list) {
1667 if (vnse_bind->vbind == vbind)
1668 return CMD_SUCCESS;
1669 }
1670
1671 vnse_bind = talloc(vty_nsi, struct vty_nse_bind);
1672 if (!vnse_bind)
1673 return CMD_WARNING;
1674 vnse_bind->vbind = vbind;
1675
1676 llist_add_tail(&vnse_bind->list, &ip_sns_default_binds);
1677
1678 return CMD_SUCCESS;
1679}
1680
1681DEFUN(cfg_no_ns_ip_sns_default_bind, cfg_no_ns_ip_sns_default_bind_cmd,
1682 "no ip-sns-default bind ID",
1683 NO_STR "Defaults for dynamically created NSEs created by IP-SNS in SGSN role\n"
1684 "IP SNS binds\n"
1685 "Name of NS udp bind whose IP endpoint will be removed as IP-SNS local endpoint.\n")
1686{
1687 struct vty_bind *vbind;
1688 struct vty_nse_bind *vnse_bind;
1689 const char *name = argv[0];
1690
1691 vbind = vty_bind_by_name(name);
1692 if (!vbind) {
1693 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1694 return CMD_WARNING;
1695 }
1696
1697 if (vbind->ll != GPRS_NS2_LL_UDP) {
1698 vty_out(vty, "ip-sns-default bind can only be used with UDP bind%s", VTY_NEWLINE);
1699 return CMD_WARNING;
1700 }
1701
1702 llist_for_each_entry(vnse_bind, &ip_sns_default_binds, list) {
1703 if (vnse_bind->vbind == vbind) {
1704 llist_del(&vnse_bind->list);
1705 talloc_free(vnse_bind);
1706 return CMD_SUCCESS;
1707 }
1708 }
1709
1710 vty_out(vty, "Bind '%s' was not an ip-sns-default bind%s", name, VTY_NEWLINE);
1711 return CMD_WARNING;
1712}
1713
Daniel Willmann3236fdf2023-08-29 16:24:56 +02001714DEFUN(cfg_ns_txqueue_max_length, cfg_ns_txqueue_max_length_cmd,
1715 "txqueue-max-length <1-4096>",
1716 "Set the maximum length of the txqueue (for UDP)\n"
1717 "Maximum length of the txqueue\n")
1718{
1719 struct gprs_ns2_vc_bind *bind;
1720 uint32_t max_length = atoi(argv[0]);
1721 vty_nsi->txqueue_max_length = max_length;
1722
1723
1724 llist_for_each_entry(bind, &vty_nsi->binding, list) {
1725 if (!gprs_ns2_is_ip_bind(bind))
1726 continue;
1727
1728 ns2_ip_set_txqueue_max_length(bind, max_length);
1729 }
1730
1731
1732 return CMD_SUCCESS;
1733}
1734
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001735DEFUN(cfg_ns_nse_ip_sns_bind, cfg_ns_nse_ip_sns_bind_cmd,
1736 "ip-sns-bind BINDID",
1737 "IP SNS binds\n"
Harald Welte2230a912021-03-04 20:09:50 +01001738 "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 +01001739{
1740 struct gprs_ns2_nse *nse = vty->index;
1741 struct gprs_ns2_vc_bind *bind;
1742 struct vty_bind *vbind;
1743 struct vty_nse *vnse;
1744 const char *name = argv[0];
1745 bool ll_modified = false;
1746 bool dialect_modified = false;
1747 int rc;
1748
1749 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1750 nse->ll = GPRS_NS2_LL_UDP;
1751 ll_modified = true;
1752 }
1753
1754 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001755 if (ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_SNS) < 0)
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001756 goto err;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001757 dialect_modified = true;
1758 }
1759
1760 if (nse->ll != GPRS_NS2_LL_UDP) {
1761 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1762 goto err;
1763 }
1764
1765 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1766 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1767 goto err;
1768 }
1769
1770 vbind = vty_bind_by_name(name);
1771 if (!vbind) {
1772 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1773 goto err;
1774 }
1775
1776 if (vbind->ll != GPRS_NS2_LL_UDP) {
1777 vty_out(vty, "ip-sns-bind can only be used with UDP bind%s",
1778 VTY_NEWLINE);
1779 goto err;
1780 }
1781
1782 /* the vnse has been created together when creating the nse node. The parent node should check this already! */
1783 vnse = vty_nse_by_nsei(nse->nsei);
1784 OSMO_ASSERT(vnse);
1785
1786 rc = vty_nse_add_vbind(vnse, vbind);
1787 switch (rc) {
1788 case 0:
1789 break;
1790 case -EALREADY:
1791 vty_out(vty, "Failed to add ip-sns-bind %s already present%s", name, VTY_NEWLINE);
1792 goto err;
1793 case -ENOMEM:
1794 vty_out(vty, "Failed to add ip-sns-bind %s out of memory%s", name, VTY_NEWLINE);
1795 goto err;
1796 default:
1797 vty_out(vty, "Failed to add ip-sns-bind %s! %d%s", name, rc, VTY_NEWLINE);
1798 goto err;
1799 }
1800
1801 /* the bind might not yet created because "listen" is missing. */
1802 bind = gprs_ns2_bind_by_name(vty_nsi, name);
1803 if (!bind)
1804 return CMD_SUCCESS;
1805
1806 rc = gprs_ns2_sns_add_bind(nse, bind);
1807 switch (rc) {
1808 case 0:
1809 break;
1810 case -EALREADY:
1811 vty_out(vty, "Failed to add ip-sns-bind %s already present%s", name, VTY_NEWLINE);
1812 goto err;
1813 case -ENOMEM:
1814 vty_out(vty, "Failed to add ip-sns-bind %s out of memory%s", name, VTY_NEWLINE);
1815 goto err;
1816 default:
1817 vty_out(vty, "Failed to add ip-sns-bind %s! %d%s", name, rc, VTY_NEWLINE);
1818 goto err;
1819 }
1820
1821 return CMD_SUCCESS;
1822err:
1823 if (ll_modified)
1824 nse->ll = GPRS_NS2_LL_UNDEF;
1825 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001826 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001827
1828 return CMD_WARNING;
1829}
1830
1831DEFUN(cfg_no_ns_nse_ip_sns_bind, cfg_no_ns_nse_ip_sns_bind_cmd,
1832 "no ip-sns-bind BINDID",
1833 NO_STR
1834 "IP SNS binds\n"
Harald Welte2230a912021-03-04 20:09:50 +01001835 "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 +01001836{
1837 struct gprs_ns2_nse *nse = vty->index;
1838 struct gprs_ns2_vc_bind *bind;
1839 struct vty_bind *vbind;
1840 struct vty_nse *vnse;
1841 const char *name = argv[0];
1842 int rc;
1843
1844 if (nse->ll != GPRS_NS2_LL_UDP) {
1845 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1846 return CMD_WARNING;
1847 }
1848
1849 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1850 vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%s", VTY_NEWLINE);
1851 return CMD_WARNING;
1852 }
1853
1854 vbind = vty_bind_by_name(name);
1855 if (!vbind) {
1856 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1857 return CMD_WARNING;
1858 }
1859
1860 if (vbind->ll != GPRS_NS2_LL_UDP) {
1861 vty_out(vty, "no ip-sns-bind can only be used with UDP bind%s",
1862 VTY_NEWLINE);
1863 return CMD_WARNING;
1864 }
1865
1866 /* the vnse has been created together when creating the nse node. The parent node should check this already! */
1867 vnse = vty_nse_by_nsei(nse->nsei);
1868 OSMO_ASSERT(vnse);
1869
1870 rc = vty_nse_remove_vbind(vnse, vbind);
1871 switch(rc) {
1872 case 0:
1873 break;
1874 case -ENOENT:
1875 vty_out(vty, "Bind %s is not part of this NSE%s", name, VTY_NEWLINE);
1876 return CMD_WARNING;
1877 case -EINVAL:
1878 vty_out(vty, "no ip-sns-bind can only be used with UDP bind%s",
1879 VTY_NEWLINE);
1880 return CMD_WARNING;
1881 default:
1882 return CMD_WARNING;
1883 }
1884
1885 /* the bind might not exists yet */
1886 bind = gprs_ns2_bind_by_name(vty_nsi, name);
1887 if (bind)
1888 gprs_ns2_sns_del_bind(nse, bind);
1889
1890 if (!vty_nse_check_sns(nse)) {
1891 /* clean up nse to allow other nsvc commands */
Harald Welte06d9bf92021-03-05 10:20:11 +01001892 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001893 nse->ll = GPRS_NS2_LL_UNDEF;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001894 }
1895
1896 return CMD_SUCCESS;
1897}
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001898
1899/* non-config commands */
Alexander Couzens75b61882021-03-21 16:18:17 +01001900void ns2_vty_dump_nsvc(struct vty *vty, struct gprs_ns2_vc *nsvc, bool stats)
Alexander Couzens6a161492020-07-12 13:45:50 +02001901{
Harald Weltedc2d0802020-12-01 18:17:28 +01001902 if (nsvc->nsvci_is_valid)
arehbein0d9b6b02022-10-27 18:28:52 +02001903 vty_out(vty, " NSVCI %05u: %s %s %s %s %ssince ", nsvc->nsvci,
Alexander Couzens5e040bf2021-06-15 23:19:42 +02001904 osmo_fsm_inst_state_name(nsvc->fi),
1905 nsvc->persistent ? "PERSIST" : "DYNAMIC",
Alexander Couzensca5ce0d2021-09-05 23:15:56 +02001906 gprs_ns2_ll_str(nsvc),
arehbein0d9b6b02022-10-27 18:28:52 +02001907 ns2_vc_is_unblocked(nsvc) ? "ALIVE" : "DEAD",
1908 nsvc->om_blocked ? "(blocked by O&M/vty) " :
1909 !ns2_vc_is_unblocked(nsvc) ? "(cause: remote) " : "");
Harald Weltedc2d0802020-12-01 18:17:28 +01001910 else
arehbein0d9b6b02022-10-27 18:28:52 +02001911 vty_out(vty, " %s %s sig_weight=%u data_weight=%u %s %s %ssince ",
Alexander Couzens5e040bf2021-06-15 23:19:42 +02001912 osmo_fsm_inst_state_name(nsvc->fi),
1913 nsvc->persistent ? "PERSIST" : "DYNAMIC",
1914 nsvc->sig_weight, nsvc->data_weight,
Alexander Couzensca5ce0d2021-09-05 23:15:56 +02001915 gprs_ns2_ll_str(nsvc),
arehbein0d9b6b02022-10-27 18:28:52 +02001916 ns2_vc_is_unblocked(nsvc) ? "ALIVE" : "DEAD",
1917 !ns2_vc_is_unblocked(nsvc) ? "(cause: remote) " : "");
Alexander Couzensca5ce0d2021-09-05 23:15:56 +02001918
1919 vty_out_uptime(vty, &nsvc->ts_alive_change);
1920 vty_out_newline(vty);
Alexander Couzens6a161492020-07-12 13:45:50 +02001921
1922 if (stats) {
Alexander Couzens1dd9cbf2021-03-21 16:22:08 +01001923 vty_out_rate_ctr_group(vty, " ", nsvc->ctrg);
1924 vty_out_stat_item_group(vty, " ", nsvc->statg);
Alexander Couzens6a161492020-07-12 13:45:50 +02001925 }
1926}
1927
1928static void dump_nse(struct vty *vty, const struct gprs_ns2_nse *nse, bool stats, bool persistent_only)
1929{
1930 struct gprs_ns2_vc *nsvc;
Alexander Couzens0ea4a4e2021-03-21 16:37:23 +01001931 unsigned int nsvcs = 0;
Alexander Couzens6a161492020-07-12 13:45:50 +02001932
Alexander Couzens3e539ed2021-03-21 16:25:18 +01001933 if (persistent_only && !nse->persistent)
1934 return;
1935
Alexander Couzens2c64c252021-09-05 23:15:29 +02001936 vty_out(vty, "NSEI %05u: %s, %s since ", nse->nsei, gprs_ns2_lltype_str(nse->ll),
1937 nse->alive ? "ALIVE" : "DEAD");
1938 vty_out_uptime(vty, &nse->ts_alive_change);
1939 vty_out_newline(vty);
Alexander Couzens6a161492020-07-12 13:45:50 +02001940
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001941 ns2_sns_dump_vty(vty, " ", nse, stats);
Alexander Couzens0ea4a4e2021-03-21 16:37:23 +01001942 llist_for_each_entry(nsvc, &nse->nsvc, list) {
1943 nsvcs++;
1944 }
1945 vty_out(vty, " %u NS-VC:%s", nsvcs, VTY_NEWLINE);
Alexander Couzens3e539ed2021-03-21 16:25:18 +01001946 llist_for_each_entry(nsvc, &nse->nsvc, list)
1947 ns2_vty_dump_nsvc(vty, nsvc, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001948}
1949
Alexander Couzens22f34712020-10-02 02:34:39 +02001950static void dump_bind(struct vty *vty, const struct gprs_ns2_vc_bind *bind, bool stats)
1951{
1952 if (bind->dump_vty)
1953 bind->dump_vty(bind, vty, stats);
Harald Welte76346072021-01-31 11:54:02 +01001954
1955 if (stats) {
1956 vty_out_stat_item_group(vty, " ", bind->statg);
1957 }
Alexander Couzens22f34712020-10-02 02:34:39 +02001958}
1959
Harald Welte2fce19a2020-12-01 17:52:55 +01001960static void dump_ns_bind(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats)
Alexander Couzens6a161492020-07-12 13:45:50 +02001961{
Alexander Couzens22f34712020-10-02 02:34:39 +02001962 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6a161492020-07-12 13:45:50 +02001963
Alexander Couzens22f34712020-10-02 02:34:39 +02001964 llist_for_each_entry(bind, &nsi->binding, list) {
1965 dump_bind(vty, bind, stats);
1966 }
Harald Welte2fce19a2020-12-01 17:52:55 +01001967}
1968
1969
1970static void dump_ns_entities(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats, bool persistent_only)
1971{
1972 struct gprs_ns2_nse *nse;
Alexander Couzens22f34712020-10-02 02:34:39 +02001973
Alexander Couzens6a161492020-07-12 13:45:50 +02001974 llist_for_each_entry(nse, &nsi->nse, list) {
1975 dump_nse(vty, nse, stats, persistent_only);
Alexander Couzens6a161492020-07-12 13:45:50 +02001976 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001977}
1978
Harald Welte25ee7552020-12-02 22:14:00 +01001979/* Backwards compatibility, among other things for the TestVTYGbproxy which expects
1980 * 'show ns' to output something about binds */
1981DEFUN_HIDDEN(show_ns, show_ns_cmd, "show ns",
1982 SHOW_STR SHOW_NS_STR)
1983{
1984 dump_ns_entities(vty, vty_nsi, false, false);
1985 dump_ns_bind(vty, vty_nsi, false);
Harald Welte069967b2021-03-30 12:05:31 +02001986 if (vty_fr_network && llist_count(&vty_fr_network->links))
1987 osmo_fr_network_dump_vty(vty, vty_fr_network);
Harald Welte25ee7552020-12-02 22:14:00 +01001988 return CMD_SUCCESS;
1989}
1990
1991
Harald Welte2fce19a2020-12-01 17:52:55 +01001992DEFUN(show_ns_binds, show_ns_binds_cmd, "show ns binds [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001993 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01001994 "Display information about the NS protocol binds\n"
1995 "Include statistic\n")
Alexander Couzens6a161492020-07-12 13:45:50 +02001996{
Harald Welte2fce19a2020-12-01 17:52:55 +01001997 bool stats = false;
1998 if (argc > 0)
1999 stats = true;
2000
2001 dump_ns_bind(vty, vty_nsi, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02002002 return CMD_SUCCESS;
2003}
2004
Harald Welte2fce19a2020-12-01 17:52:55 +01002005DEFUN(show_ns_entities, show_ns_entities_cmd, "show ns entities [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01002006 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01002007 "Display information about the NS protocol entities (NSEs)\n"
Alexander Couzens6a161492020-07-12 13:45:50 +02002008 "Include statistics\n")
2009{
Harald Welte2fce19a2020-12-01 17:52:55 +01002010 bool stats = false;
2011 if (argc > 0)
2012 stats = true;
2013
2014 dump_ns_entities(vty, vty_nsi, stats, false);
Alexander Couzens6a161492020-07-12 13:45:50 +02002015 return CMD_SUCCESS;
2016}
2017
2018DEFUN(show_ns_pers, show_ns_pers_cmd, "show ns persistent",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01002019 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02002020 "Show only persistent NS\n")
2021{
Harald Welte2fce19a2020-12-01 17:52:55 +01002022 dump_ns_entities(vty, vty_nsi, true, true);
Alexander Couzens6a161492020-07-12 13:45:50 +02002023 return CMD_SUCCESS;
2024}
2025
2026DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01002027 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02002028 "Select one NSE by its NSE Identifier\n"
2029 "Select one NSE by its NS-VC Identifier\n"
2030 "The Identifier of selected type\n"
2031 "Include Statistics\n")
2032{
2033 struct gprs_ns2_inst *nsi = vty_nsi;
2034 struct gprs_ns2_nse *nse;
2035 struct gprs_ns2_vc *nsvc;
2036 uint16_t id = atoi(argv[1]);
2037 bool show_stats = false;
2038
2039 if (argc >= 3)
2040 show_stats = true;
2041
2042 if (!strcmp(argv[0], "nsei")) {
2043 nse = gprs_ns2_nse_by_nsei(nsi, id);
2044 if (!nse) {
2045 return CMD_WARNING;
2046 }
2047
2048 dump_nse(vty, nse, show_stats, false);
2049 } else {
2050 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
2051
2052 if (!nsvc) {
2053 vty_out(vty, "No such NS Entity%s", VTY_NEWLINE);
2054 return CMD_WARNING;
2055 }
2056
Alexander Couzens75b61882021-03-21 16:18:17 +01002057 ns2_vty_dump_nsvc(vty, nsvc, show_stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02002058 }
2059
2060 return CMD_SUCCESS;
2061}
2062
Daniel Willmanndbab7142020-11-18 14:19:56 +01002063static int nsvc_force_unconf_cb(struct gprs_ns2_vc *nsvc, void *ctx)
2064{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01002065 ns2_vc_force_unconfigured(nsvc);
Harald Welte7fe8d712021-01-31 18:40:54 +01002066 ns2_vc_fsm_start(nsvc);
Daniel Willmanndbab7142020-11-18 14:19:56 +01002067 return 0;
2068}
2069
2070DEFUN_HIDDEN(nsvc_force_unconf, nsvc_force_unconf_cmd,
2071 "nsvc nsei <0-65535> force-unconfigured",
2072 "NS Virtual Connection\n"
2073 "The NSEI\n"
2074 "Reset the NSVCs back to initial state\n"
2075 )
2076{
2077 struct gprs_ns2_inst *nsi = vty_nsi;
2078 struct gprs_ns2_nse *nse;
2079
2080 uint16_t id = atoi(argv[0]);
2081
2082 nse = gprs_ns2_nse_by_nsei(nsi, id);
2083 if (!nse) {
2084 vty_out(vty, "Could not find NSE for NSEI %u%s", id, VTY_NEWLINE);
2085 return CMD_WARNING;
2086 }
2087
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002088 if (!nse->persistent) {
2089 gprs_ns2_free_nse(nse);
2090 } else if (nse->dialect == GPRS_NS2_DIALECT_SNS) {
Alexander Couzens280ed782020-12-21 18:25:41 +01002091 gprs_ns2_free_nsvcs(nse);
2092 } else {
2093 /* Perform the operation for all nsvc */
2094 gprs_ns2_nse_foreach_nsvc(nse, nsvc_force_unconf_cb, NULL);
2095 }
Daniel Willmanndbab7142020-11-18 14:19:56 +01002096
2097 return CMD_SUCCESS;
2098}
2099
Alexander Couzensd13faaa2021-03-01 03:14:19 +01002100DEFUN(nse_restart_sns, nse_restart_sns_cmd,
2101 "nse <0-65535> restart-sns",
2102 "NSE specific commands\n"
2103 "NS Entity ID (NSEI)\n"
2104 "Restart SNS procedure\n")
2105{
2106 struct gprs_ns2_inst *nsi = vty_nsi;
2107 struct gprs_ns2_nse *nse;
2108
2109 uint16_t id = atoi(argv[0]);
2110 nse = gprs_ns2_nse_by_nsei(nsi, id);
2111 if (!nse) {
2112 vty_out(vty, "Could not find NSE for NSEI %u%s", id, VTY_NEWLINE);
2113 return CMD_WARNING;
2114 }
2115
2116 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
2117 vty_out(vty, "Given NSEI %u doesn't use IP-SNS%s", id, VTY_NEWLINE);
2118 return CMD_WARNING;
2119 }
2120
2121 gprs_ns2_free_nsvcs(nse);
2122 return CMD_SUCCESS;
2123}
2124
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002125DEFUN(nsvc_block, nsvc_block_cmd,
Alexander Couzens27e58732021-03-21 17:12:08 +01002126 "nsvc <0-65535> (block|unblock|reset)",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002127 "NS Virtual Connection\n"
2128 NSVCI_STR
2129 "Block a NSVC. As cause code O&M intervention will be used.\n"
Alexander Couzens27e58732021-03-21 17:12:08 +01002130 "Unblock a NSVC. As cause code O&M intervention will be used.\n"
2131 "Reset a NSVC. As cause code O&M intervention will be used.\n")
Alexander Couzens841817e2020-11-19 00:41:29 +01002132{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002133 struct gprs_ns2_inst *nsi = vty_nsi;
2134 struct gprs_ns2_vc *nsvc;
Alexander Couzense7dfeac2021-03-21 17:28:36 +01002135 int rc;
Alexander Couzens841817e2020-11-19 00:41:29 +01002136
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002137 uint16_t id = atoi(argv[0]);
Alexander Couzens841817e2020-11-19 00:41:29 +01002138
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002139 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
2140 if (!nsvc) {
2141 vty_out(vty, "Could not find NSVCI %05u%s", id, VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +01002142 return CMD_WARNING;
2143 }
2144
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002145 if (!strcmp(argv[1], "block")) {
Alexander Couzense7dfeac2021-03-21 17:28:36 +01002146 rc = ns2_vc_block(nsvc);
2147 switch (rc) {
2148 case 0:
2149 vty_out(vty, "The NS-VC %05u will be blocked.%s", id, VTY_NEWLINE);
2150 return CMD_SUCCESS;
2151 case -EALREADY:
2152 vty_out(vty, "The NS-VC %05u is already blocked.%s", id, VTY_NEWLINE);
2153 return CMD_ERR_NOTHING_TODO;
2154 default:
2155 vty_out(vty, "An unknown error %d happend on NS-VC %05u.%s", rc, id, VTY_NEWLINE);
2156 return CMD_WARNING;
2157 }
Alexander Couzens27e58732021-03-21 17:12:08 +01002158 } else if (!strcmp(argv[1], "unblock")) {
Alexander Couzense7dfeac2021-03-21 17:28:36 +01002159 rc = ns2_vc_unblock(nsvc);
2160 switch (rc) {
2161 case 0:
2162 vty_out(vty, "The NS-VC %05u will be unblocked.%s", id, VTY_NEWLINE);
2163 return CMD_SUCCESS;
2164 case -EALREADY:
2165 vty_out(vty, "The NS-VC %05u is already unblocked.%s", id, VTY_NEWLINE);
2166 return CMD_ERR_NOTHING_TODO;
2167 default:
2168 vty_out(vty, "An unknown error %d happend on NS-VC %05u.%s", rc, id, VTY_NEWLINE);
2169 return CMD_WARNING;
2170 }
Alexander Couzens27e58732021-03-21 17:12:08 +01002171 } else {
2172 ns2_vc_reset(nsvc);
Alexander Couzense7dfeac2021-03-21 17:28:36 +01002173 vty_out(vty, "The NS-VC %05u has been resetted.%s", id, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02002174 }
2175
2176 return CMD_SUCCESS;
2177}
2178
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002179static void log_set_nse_filter(struct log_target *target,
2180 struct gprs_ns2_nse *nse)
Alexander Couzens6a161492020-07-12 13:45:50 +02002181{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002182 if (nse) {
2183 target->filter_map |= (1 << LOG_FLT_GB_NSE);
2184 target->filter_data[LOG_FLT_GB_NSE] = nse;
2185 } else if (target->filter_data[LOG_FLT_GB_NSE]) {
2186 target->filter_map = ~(1 << LOG_FLT_GB_NSE);
2187 target->filter_data[LOG_FLT_GB_NSE] = NULL;
2188 }
Alexander Couzens6a161492020-07-12 13:45:50 +02002189}
2190
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002191static void log_set_nsvc_filter(struct log_target *target,
2192 struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +02002193{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002194 if (nsvc) {
2195 target->filter_map |= (1 << LOG_FLT_GB_NSVC);
2196 target->filter_data[LOG_FLT_GB_NSVC] = nsvc;
2197 } else if (target->filter_data[LOG_FLT_GB_NSVC]) {
2198 target->filter_map = ~(1 << LOG_FLT_GB_NSVC);
2199 target->filter_data[LOG_FLT_GB_NSVC] = NULL;
2200 }
Alexander Couzens6a161492020-07-12 13:45:50 +02002201}
2202
Daniel Willmann751977b2020-12-02 18:59:44 +01002203DEFUN(logging_fltr_nse,
2204 logging_fltr_nse_cmd,
2205 "logging filter nse nsei <0-65535>",
2206 LOGGING_STR FILTER_STR
2207 "Filter based on NS Entity\n"
2208 "Identify NSE by NSEI\n"
2209 "Numeric identifier\n")
2210{
2211 struct log_target *tgt;
2212 struct gprs_ns2_nse *nse;
Daniel Willmann89106522020-12-04 01:36:59 +01002213 uint16_t id = atoi(argv[0]);
Daniel Willmann751977b2020-12-02 18:59:44 +01002214
2215 log_tgt_mutex_lock();
2216 tgt = osmo_log_vty2tgt(vty);
2217 if (!tgt) {
2218 log_tgt_mutex_unlock();
2219 return CMD_WARNING;
2220 }
2221
2222 nse = gprs_ns2_nse_by_nsei(vty_nsi, id);
2223 if (!nse) {
2224 vty_out(vty, "No NSE by that identifier%s", VTY_NEWLINE);
2225 log_tgt_mutex_unlock();
2226 return CMD_WARNING;
2227 }
2228
2229 log_set_nse_filter(tgt, nse);
2230 log_tgt_mutex_unlock();
2231 return CMD_SUCCESS;
2232}
2233
Alexander Couzens6a161492020-07-12 13:45:50 +02002234/* TODO: add filter for single connection by description */
2235DEFUN(logging_fltr_nsvc,
2236 logging_fltr_nsvc_cmd,
2237 "logging filter nsvc nsvci <0-65535>",
2238 LOGGING_STR FILTER_STR
2239 "Filter based on NS Virtual Connection\n"
2240 "Identify NS-VC by NSVCI\n"
2241 "Numeric identifier\n")
2242{
2243 struct log_target *tgt;
2244 struct gprs_ns2_vc *nsvc;
Daniel Willmann89106522020-12-04 01:36:59 +01002245 uint16_t id = atoi(argv[0]);
Alexander Couzens6a161492020-07-12 13:45:50 +02002246
2247 log_tgt_mutex_lock();
2248 tgt = osmo_log_vty2tgt(vty);
2249 if (!tgt) {
2250 log_tgt_mutex_unlock();
2251 return CMD_WARNING;
2252 }
2253
2254 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, id);
2255 if (!nsvc) {
2256 vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE);
2257 log_tgt_mutex_unlock();
2258 return CMD_WARNING;
2259 }
2260
2261 log_set_nsvc_filter(tgt, nsvc);
2262 log_tgt_mutex_unlock();
2263 return CMD_SUCCESS;
2264}
2265
Alexander Couzense43b46e2021-01-27 21:52:08 +01002266/*! initialized a reduced vty interface which excludes the configuration nodes besides timeouts.
2267 * This can be used by the PCU which can be only configured by the BTS/BSC and not by the vty.
2268 * \param[in] nsi NS instance on which we operate
2269 * \return 0 on success.
2270 */
2271int gprs_ns2_vty_init_reduced(struct gprs_ns2_inst *nsi)
Alexander Couzens6a161492020-07-12 13:45:50 +02002272{
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01002273 vty_nsi = nsi;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002274 INIT_LLIST_HEAD(&binds);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002275 INIT_LLIST_HEAD(&nses);
Harald Welted164ef82021-03-04 22:29:17 +01002276 INIT_LLIST_HEAD(&ip_sns_default_binds);
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01002277
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002278 vty_fr_network = osmo_fr_network_alloc(nsi);
2279 if (!vty_fr_network)
2280 return -ENOMEM;
Alexander Couzens6a161492020-07-12 13:45:50 +02002281
Harald Welte25ee7552020-12-02 22:14:00 +01002282 install_lib_element_ve(&show_ns_cmd);
Harald Welte2fce19a2020-12-01 17:52:55 +01002283 install_lib_element_ve(&show_ns_binds_cmd);
2284 install_lib_element_ve(&show_ns_entities_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002285 install_lib_element_ve(&show_ns_pers_cmd);
2286 install_lib_element_ve(&show_nse_cmd);
Daniel Willmann751977b2020-12-02 18:59:44 +01002287 install_lib_element_ve(&logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002288 install_lib_element_ve(&logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002289
Daniel Willmanndbab7142020-11-18 14:19:56 +01002290 install_lib_element(ENABLE_NODE, &nsvc_force_unconf_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002291 install_lib_element(ENABLE_NODE, &nsvc_block_cmd);
Alexander Couzensd13faaa2021-03-01 03:14:19 +01002292 install_lib_element(ENABLE_NODE, &nse_restart_sns_cmd);
Daniel Willmanndbab7142020-11-18 14:19:56 +01002293
Daniel Willmann751977b2020-12-02 18:59:44 +01002294 install_lib_element(CFG_LOG_NODE, &logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002295 install_lib_element(CFG_LOG_NODE, &logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002296
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002297 install_lib_element(CONFIG_NODE, &cfg_ns_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002298
Alexander Couzens6a161492020-07-12 13:45:50 +02002299 install_node(&ns_node, config_write_ns);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002300 /* TODO: convert into osmo timer */
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002301 install_lib_element(L_NS_NODE, &cfg_ns_timer_cmd);
Alexander Couzense43b46e2021-01-27 21:52:08 +01002302
2303 return 0;
2304}
2305
2306int gprs_ns2_vty_init(struct gprs_ns2_inst *nsi)
2307{
2308 int rc = gprs_ns2_vty_init_reduced(nsi);
2309 if (rc)
2310 return rc;
2311
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002312 install_lib_element(L_NS_NODE, &cfg_ns_nsei_cmd);
2313 install_lib_element(L_NS_NODE, &cfg_no_ns_nsei_cmd);
2314 install_lib_element(L_NS_NODE, &cfg_ns_bind_cmd);
2315 install_lib_element(L_NS_NODE, &cfg_no_ns_bind_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002316
Harald Welted164ef82021-03-04 22:29:17 +01002317 install_lib_element(L_NS_NODE, &cfg_ns_ip_sns_default_bind_cmd);
2318 install_lib_element(L_NS_NODE, &cfg_no_ns_ip_sns_default_bind_cmd);
2319
Daniel Willmann3236fdf2023-08-29 16:24:56 +02002320 install_lib_element(L_NS_NODE, &cfg_ns_txqueue_max_length_cmd);
2321
Alexander Couzens260cd522021-01-28 20:31:31 +01002322 install_node(&ns_bind_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002323 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_listen_cmd);
2324 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_listen_cmd);
2325 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_dscp_cmd);
2326 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_dscp_cmd);
Harald Welted99e4ee2021-04-28 19:57:12 +02002327 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_priority_cmd);
Alexander Couzensc4704762021-02-08 23:13:12 +01002328 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_ip_sns_weight_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002329 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_ipaccess_cmd);
2330 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_ipaccess_cmd);
2331 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_fr_cmd);
2332 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_fr_cmd);
Harald Welte42e36462021-03-03 18:12:09 +01002333 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_accept_sns_cmd);
2334 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_accept_sns_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002335
Alexander Couzens260cd522021-01-28 20:31:31 +01002336 install_node(&ns_nse_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002337 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_fr_cmd);
2338 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvci_cmd);
2339 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_fr_dlci_cmd);
2340 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_udp_cmd);
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01002341 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_udp_weights_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002342 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_udp_cmd);
2343 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_ipa_cmd);
2344 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_ipa_cmd);
Alexander Couzens5fa431c2021-02-08 23:21:54 +01002345 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_remote_cmd);
2346 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_remote_cmd);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002347 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_bind_cmd);
2348 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_bind_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002349
2350 return 0;
2351}