blob: a782c5cf5cb4fd0c05b780d40b412eb8a6e9fb7d [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>
39#include <osmocom/core/rate_ctr.h>
40#include <osmocom/core/select.h>
41#include <osmocom/core/talloc.h>
42#include <osmocom/core/sockaddr_str.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020043#include <osmocom/core/socket.h>
Alexander Couzens841817e2020-11-19 00:41:29 +010044#include <osmocom/gprs/frame_relay.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020045#include <osmocom/gprs/gprs_ns2.h>
46#include <osmocom/gsm/tlv.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020047#include <osmocom/vty/command.h>
48#include <osmocom/vty/logging.h>
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010049#include <osmocom/vty/misc.h>
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010050#include <osmocom/vty/telnet_interface.h>
51#include <osmocom/vty/vty.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020052
53#include "gprs_ns2_internal.h"
54
Daniel Willmanncb3e9b52020-12-02 15:50:22 +010055#define SHOW_NS_STR "Display information about the NS protocol\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010056#define NSVCI_STR "NS Virtual Connection ID (NS-VCI)\n"
57#define DLCI_STR "Data Link connection identifier\n"
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010058
59static struct gprs_ns2_inst *vty_nsi = NULL;
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010060static struct osmo_fr_network *vty_fr_network = NULL;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010061static struct llist_head binds;
Alexander Couzens6b9d2322021-02-12 03:17:59 +010062static struct llist_head nses;
Harald Welted164ef82021-03-04 22:29:17 +010063static struct llist_head ip_sns_default_binds;
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010064
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010065struct vty_bind {
66 struct llist_head list;
67 const char *name;
68 enum gprs_ns2_ll ll;
69 int dscp;
Harald Welted99e4ee2021-04-28 19:57:12 +020070 uint8_t priority;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010071 bool accept_ipaccess;
72 bool accept_sns;
Alexander Couzensc4704762021-02-08 23:13:12 +010073 uint8_t ip_sns_sig_weight;
74 uint8_t ip_sns_data_weight;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010075};
76
Alexander Couzens6b9d2322021-02-12 03:17:59 +010077struct vty_nse {
78 struct llist_head list;
79 uint16_t nsei;
80 /* list of binds which are valid for this nse. Only IP-SNS uses this
81 * to allow `no listen ..` in the bind context. So "half" created binds are valid for
82 * IP-SNS. This allows changing the bind ip without modifying all NSEs afterwards */
83 struct llist_head binds;
84};
85
86/* used by IP-SNS to connect multiple vty_nse_bind to a vty_nse */
87struct vty_nse_bind {
88 struct llist_head list;
89 struct vty_bind *vbind;
90};
91
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010092/* TODO: this should into osmo timer */
Alexander Couzens6a161492020-07-12 13:45:50 +020093static const struct value_string gprs_ns_timer_strs[] = {
94 { 0, "tns-block" },
95 { 1, "tns-block-retries" },
96 { 2, "tns-reset" },
97 { 3, "tns-reset-retries" },
98 { 4, "tns-test" },
99 { 5, "tns-alive" },
100 { 6, "tns-alive-retries" },
101 { 7, "tsns-prov" },
Harald Welte33c3c062020-12-16 11:59:19 +0100102 { 8, "tsns-size-retries" },
103 { 9, "tsns-config-retries" },
Alexander Couzens6a161492020-07-12 13:45:50 +0200104 { 0, NULL }
105};
106
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100107const struct value_string vty_fr_role_names[] = {
108 { FR_ROLE_USER_EQUIPMENT, "fr" },
109 { FR_ROLE_NETWORK_EQUIPMENT, "frnet" },
110 { 0, NULL }
111};
112
113const struct value_string vty_ll_names[] = {
114 { GPRS_NS2_LL_FR, "fr" },
115 { GPRS_NS2_LL_FR_GRE, "frgre" },
116 { GPRS_NS2_LL_UDP, "udp" },
117 { 0, NULL }
118};
119
120static struct vty_bind *vty_bind_by_name(const char *name)
Daniel Willmann751977b2020-12-02 18:59:44 +0100121{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100122 struct vty_bind *vbind;
123 llist_for_each_entry(vbind, &binds, list) {
Alexander Couzensb7921732021-02-12 03:08:42 +0100124 if (!strcmp(vbind->name, name))
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100125 return vbind;
Daniel Willmann751977b2020-12-02 18:59:44 +0100126 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100127 return NULL;
Daniel Willmann751977b2020-12-02 18:59:44 +0100128}
129
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100130static struct vty_bind *vty_bind_alloc(const char *name)
Alexander Couzens6a161492020-07-12 13:45:50 +0200131{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100132 struct vty_bind *vbind = talloc_zero(vty_nsi, struct vty_bind);
133 if (!vbind)
134 return NULL;
135
136 vbind->name = talloc_strdup(vty_nsi, name);
137 if (!vbind->name) {
138 talloc_free(vbind);
139 return NULL;
Alexander Couzens6a161492020-07-12 13:45:50 +0200140 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100141
Alexander Couzensc4704762021-02-08 23:13:12 +0100142 vbind->ip_sns_sig_weight = 1;
143 vbind->ip_sns_data_weight = 1;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100144 llist_add(&vbind->list, &binds);
145 return vbind;
146}
147
148static void vty_bind_free(struct vty_bind *vbind)
149{
150 if (!vbind)
151 return;
152
153 llist_del(&vbind->list);
Alexander Couzens3e2e4a02021-02-09 16:15:06 +0100154 talloc_free(vbind);
Alexander Couzens6a161492020-07-12 13:45:50 +0200155}
156
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100157static struct vty_nse *vty_nse_by_nsei(uint16_t nsei)
158{
159 struct vty_nse *vnse;
160 llist_for_each_entry(vnse, &nses, list) {
161 if (vnse->nsei == nsei)
162 return vnse;
163 }
164 return NULL;
165}
166
167static struct vty_nse *vty_nse_alloc(uint16_t nsei)
168{
169 struct vty_nse *vnse = talloc_zero(vty_nsi, struct vty_nse);
170 if (!vnse)
171 return NULL;
172
173 vnse->nsei = nsei;
174 INIT_LLIST_HEAD(&vnse->binds);
175 llist_add(&vnse->list, &nses);
176 return vnse;
177}
178
179static void vty_nse_free(struct vty_nse *vnse)
180{
181 if (!vnse)
182 return;
183
184 llist_del(&vnse->list);
185 /* all vbind of the nse will be freed by talloc */
186 talloc_free(vnse);
187}
188
189static int vty_nse_add_vbind(struct vty_nse *vnse, struct vty_bind *vbind)
190{
191 struct vty_nse_bind *vnse_bind;
192
193 if (vbind->ll != GPRS_NS2_LL_UDP)
194 return -EINVAL;
195
196 llist_for_each_entry(vnse_bind, &vnse->binds, list) {
197 if (vnse_bind->vbind == vbind)
198 return -EALREADY;
199 }
200
201 vnse_bind = talloc(vnse, struct vty_nse_bind);
202 if (!vnse_bind)
203 return -ENOMEM;
204 vnse_bind->vbind = vbind;
205
206 llist_add_tail(&vnse_bind->list, &vnse->binds);
207 return 0;
208}
209
210static int vty_nse_remove_vbind(struct vty_nse *vnse, struct vty_bind *vbind)
211{
212 struct vty_nse_bind *vnse_bind, *tmp;
213 if (vbind->ll != GPRS_NS2_LL_UDP)
214 return -EINVAL;
215
216 llist_for_each_entry_safe(vnse_bind, tmp, &vnse->binds, list) {
217 if (vnse_bind->vbind == vbind) {
218 llist_del(&vnse_bind->list);
219 talloc_free(vnse_bind);
220 }
221 }
222
223 return -ENOENT;
224}
225
226/* check if the NSE still has SNS configuration */
227static bool vty_nse_check_sns(struct gprs_ns2_nse *nse) {
228 struct vty_nse *vnse = vty_nse_by_nsei(nse->nsei);
229
230 int count = gprs_ns2_sns_count(nse);
231 if (count > 0) {
232 /* there are other sns endpoints */
233 return true;
234 }
235
236 if (!vnse)
237 return false;
238
239 if (llist_empty(&vnse->binds))
240 return false;
241
242 return true;
243}
244
Alexander Couzens6a161492020-07-12 13:45:50 +0200245static struct cmd_node ns_node = {
246 L_NS_NODE,
247 "%s(config-ns)# ",
248 1,
249};
250
Alexander Couzens6a161492020-07-12 13:45:50 +0200251DEFUN(cfg_ns, cfg_ns_cmd,
252 "ns",
253 "Configure the GPRS Network Service")
254{
255 vty->node = L_NS_NODE;
256 return CMD_SUCCESS;
257}
258
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100259DEFUN(cfg_ns_timer, cfg_ns_timer_cmd,
260 "timer " NS_TIMERS " <0-65535>",
261 "Network Service Timer\n"
262 NS_TIMERS_HELP "Timer Value\n")
263{
264 int idx = get_string_value(gprs_ns_timer_strs, argv[0]);
265 int val = atoi(argv[1]);
266
267 if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout))
268 return CMD_WARNING;
269
270 vty_nsi->timeout[idx] = val;
271
272 return CMD_SUCCESS;
273}
274
275DEFUN(cfg_ns_nsei, cfg_ns_nsei_cmd,
Harald Welte579699b2021-03-05 10:22:23 +0100276 "nse <0-65535> [ip-sns-role-sgsn]",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100277 "Persistent NS Entity\n"
278 "NS Entity ID (NSEI)\n"
Harald Welte579699b2021-03-05 10:22:23 +0100279 "Create NSE in SGSN role (default: BSS)\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100280 )
281{
282 struct gprs_ns2_nse *nse;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100283 struct vty_nse *vnse;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100284 uint16_t nsei = atoi(argv[0]);
Harald Welte579699b2021-03-05 10:22:23 +0100285 bool sgsn_role = false;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100286 bool free_vnse = false;
Harald Welte579699b2021-03-05 10:22:23 +0100287 if (argc > 1 && !strcmp(argv[1], "ip-sns-role-sgsn"))
288 sgsn_role = true;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100289
290 vnse = vty_nse_by_nsei(nsei);
291 if (!vnse) {
292 vnse = vty_nse_alloc(nsei);
293 if (!vnse) {
294 vty_out(vty, "Failed to create vty NSE!%s", VTY_NEWLINE);
295 return CMD_ERR_INCOMPLETE;
296 }
297 free_vnse = true;
298 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100299
300 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
301 if (!nse) {
Harald Welte579699b2021-03-05 10:22:23 +0100302 nse = gprs_ns2_create_nse2(vty_nsi, nsei, GPRS_NS2_LL_UNDEF, GPRS_NS2_DIALECT_UNDEF,
303 sgsn_role);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100304 if (!nse) {
305 vty_out(vty, "Failed to create NSE!%s", VTY_NEWLINE);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100306 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100307 }
308 nse->persistent = true;
309 }
310
311 if (!nse->persistent) {
312 /* TODO: should the dynamic NSE removed? */
313 vty_out(vty, "A dynamic NSE with the specified NSEI already exists%s", VTY_NEWLINE);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100314 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100315 }
316
317 vty->node = L_NS_NSE_NODE;
318 vty->index = nse;
319
320 return CMD_SUCCESS;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100321
322err:
323 if (free_vnse)
324 talloc_free(vnse);
325
326 return CMD_ERR_INCOMPLETE;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100327}
328
329DEFUN(cfg_no_ns_nsei, cfg_no_ns_nsei_cmd,
330 "no nse <0-65535>",
331 NO_STR
332 "Delete a Persistent NS Entity\n"
333 "NS Entity ID (NSEI)\n"
334 )
335{
336 struct gprs_ns2_nse *nse;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100337 struct vty_nse *vnse;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100338 uint16_t nsei = atoi(argv[0]);
339
340 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
341 if (!nse) {
342 vty_out(vty, "Can not find NS Entity %s%s", argv[0], VTY_NEWLINE);
343 return CMD_ERR_NOTHING_TODO;
344 }
345
346 if (!nse->persistent) {
347 vty_out(vty, "Ignoring non-persistent NS Entity%s", VTY_NEWLINE);
348 return CMD_WARNING;
349 }
350
351 vty_out(vty, "Deleting NS Entity %u%s", nse->nsei, VTY_NEWLINE);
352 gprs_ns2_free_nse(nse);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100353
354 vnse = vty_nse_by_nsei(nsei);
355 vty_nse_free(vnse);
356
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100357 return CMD_SUCCESS;
358}
359
360/* TODO: add fr/gre */
361DEFUN(cfg_ns_bind, cfg_ns_bind_cmd,
362 "bind (fr|udp) ID",
Harald Welte2230a912021-03-04 20:09:50 +0100363 "Configure local Bind\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100364 "Frame Relay\n" "UDP/IP\n"
Harald Welte2230a912021-03-04 20:09:50 +0100365 "Unique identifier for this bind (to reference from NS-VCs, NSEs, ...)\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100366 )
367{
368 const char *nstype = argv[0];
369 const char *name = argv[1];
370 struct vty_bind *vbind;
371 enum gprs_ns2_ll ll;
372 int rc;
373
374 rc = get_string_value(vty_ll_names, nstype);
375 if (rc < 0)
376 return CMD_WARNING;
377 ll = (enum gprs_ns2_ll) rc;
378
379 if (!osmo_identifier_valid(name)) {
380 vty_out(vty, "Invalid ID. The ID should be only alphanumeric.%s", VTY_NEWLINE);
381 return CMD_WARNING;
382 }
383
384 vbind = vty_bind_by_name(name);
385 if (vbind) {
386 if (vbind->ll != ll) {
387 vty_out(vty, "A bind with the specified ID already exists with a different type (fr|frgre|udp)!%s",
388 VTY_NEWLINE);
389 return CMD_WARNING;
390 }
391 } else {
392 vbind = vty_bind_alloc(name);
393 if (!vbind) {
394 vty_out(vty, "Can not create bind - out of memory%s", VTY_NEWLINE);
395 return CMD_WARNING;
396 }
397 vbind->ll = ll;
398 }
399
400 vty->index = vbind;
401 vty->node = L_NS_BIND_NODE;
402
403 return CMD_SUCCESS;
404}
405
406DEFUN(cfg_no_ns_bind, cfg_no_ns_bind_cmd,
407 "no bind ID",
408 NO_STR
Harald Welte2230a912021-03-04 20:09:50 +0100409 "Delete a bind\n"
410 "Unique identifier for this bind\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100411 )
412{
413 struct vty_bind *vbind;
414 struct gprs_ns2_vc_bind *bind;
415 const char *name = argv[0];
416
417 vbind = vty_bind_by_name(name);
418 if (!vbind) {
419 vty_out(vty, "bind %s does not exist!%s", name, VTY_NEWLINE);
420 return CMD_WARNING;
421 }
422 vty_bind_free(vbind);
423 bind = gprs_ns2_bind_by_name(vty_nsi, name);
424 if (bind)
425 bind->driver->free_bind(bind);
426 return CMD_SUCCESS;
427}
428
429
430static void config_write_vbind(struct vty *vty, struct vty_bind *vbind)
431{
432 struct gprs_ns2_vc_bind *bind;
433 const struct osmo_sockaddr *addr;
434 struct osmo_sockaddr_str addr_str;
435 const char *netif, *frrole_str, *llstr;
436 enum osmo_fr_role frrole;
437
438 llstr = get_value_string_or_null(vty_ll_names, vbind->ll);
439 if (!llstr)
440 return;
441 vty_out(vty, " bind %s %s%s", llstr, vbind->name, VTY_NEWLINE);
442
443 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
444 switch (vbind->ll) {
445 case GPRS_NS2_LL_FR:
446 if (bind) {
447 netif = gprs_ns2_fr_bind_netif(bind);
448 if (!netif)
449 return;
450 frrole = gprs_ns2_fr_bind_role(bind);
451 if ((int) frrole == -1)
452 return;
453 frrole_str = get_value_string_or_null(vty_fr_role_names, frrole);
454 if (netif && frrole_str)
455 vty_out(vty, " fr %s %s%s", netif, frrole_str, VTY_NEWLINE);
456 }
457 break;
458 case GPRS_NS2_LL_UDP:
459 if (bind) {
460 addr = gprs_ns2_ip_bind_sockaddr(bind);
461 if (!osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas)) {
462 vty_out(vty, " listen %s %u%s", addr_str.ip, addr_str.port,
463 VTY_NEWLINE);
464 }
465 }
466 if (vbind->accept_ipaccess)
467 vty_out(vty, " accept-ipaccess%s", VTY_NEWLINE);
Harald Welte42e36462021-03-03 18:12:09 +0100468 if (vbind->accept_sns)
469 vty_out(vty, " accept-dynamic-ip-sns%s", VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100470 if (vbind->dscp)
471 vty_out(vty, " dscp %u%s", vbind->dscp, VTY_NEWLINE);
Harald Welted99e4ee2021-04-28 19:57:12 +0200472 if (vbind->priority)
Harald Welte5782fec2021-04-29 21:28:53 +0200473 vty_out(vty, " socket-priority %u%s", vbind->priority, VTY_NEWLINE);
Daniel Willmann64db6362021-02-12 12:21:45 +0100474 vty_out(vty, " ip-sns signalling-weight %u data-weight %u%s",
Alexander Couzensc4704762021-02-08 23:13:12 +0100475 vbind->ip_sns_sig_weight, vbind->ip_sns_data_weight, VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100476 break;
477 default:
478 return;
479 }
480}
481
482static void config_write_nsvc(struct vty *vty, const struct gprs_ns2_vc *nsvc)
483{
484 const char *netif;
485 uint16_t dlci;
486 const struct osmo_sockaddr *addr;
487 struct osmo_sockaddr_str addr_str;
488
489 switch (nsvc->nse->ll) {
490 case GPRS_NS2_LL_UNDEF:
491 break;
492 case GPRS_NS2_LL_UDP:
493 switch (nsvc->nse->dialect) {
494 case GPRS_NS2_DIALECT_IPACCESS:
495 addr = gprs_ns2_ip_vc_remote(nsvc);
496 if (!addr)
497 break;
498 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas))
499 break;
500 vty_out(vty, " nsvc ipa %s %s %u nsvci %u%s",
501 nsvc->bind->name, addr_str.ip, addr_str.port,
502 nsvc->nsvci, VTY_NEWLINE);
503 break;
504 case GPRS_NS2_DIALECT_STATIC_ALIVE:
505 addr = gprs_ns2_ip_vc_remote(nsvc);
506 if (!addr)
507 break;
508 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas))
509 break;
510 vty_out(vty, " nsvc udp %s %s %u%s",
511 nsvc->bind->name, addr_str.ip, addr_str.port, VTY_NEWLINE);
512 break;
513 default:
514 break;
515 }
516 break;
517 case GPRS_NS2_LL_FR:
518 netif = gprs_ns2_fr_bind_netif(nsvc->bind);
519 if (!netif)
520 break;
521 dlci = gprs_ns2_fr_nsvc_dlci(nsvc);
522 if (!dlci)
523 break;
524 OSMO_ASSERT(nsvc->nsvci_is_valid);
525 vty_out(vty, " nsvc fr %s dlci %u nsvci %u%s",
526 netif, dlci, nsvc->nsvci, VTY_NEWLINE);
527 break;
528 case GPRS_NS2_LL_FR_GRE:
529 break;
530 }
531}
532
533static void _config_write_ns_nse(struct vty *vty, struct gprs_ns2_nse *nse)
534{
535 struct gprs_ns2_vc *nsvc;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100536 struct vty_nse *vnse = vty_nse_by_nsei(nse->nsei);
537 struct vty_nse_bind *vbind;
538
539 OSMO_ASSERT(vnse);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100540
Harald Welte579699b2021-03-05 10:22:23 +0100541 vty_out(vty, " nse %u%s%s", nse->nsei,
542 nse->ip_sns_role_sgsn ? " ip-sns-role-sgsn" : "", VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100543 switch (nse->dialect) {
544 case GPRS_NS2_DIALECT_SNS:
545 ns2_sns_write_vty(vty, nse);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100546 llist_for_each_entry(vbind, &vnse->binds, list) {
547 vty_out(vty, " ip-sns-bind %s%s", vbind->vbind->name, VTY_NEWLINE);
548 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100549 break;
550 default:
551 llist_for_each_entry(nsvc, &nse->nsvc, list) {
552 config_write_nsvc(vty, nsvc);
553 }
554 break;
555 }
556}
557
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100558static int config_write_ns_nse(struct vty *vty)
559{
560 struct gprs_ns2_nse *nse;
561
562 llist_for_each_entry(nse, &vty_nsi->nse, list) {
563 if (!nse->persistent)
564 continue;
565
566 _config_write_ns_nse(vty, nse);
567 }
568
569 return 0;
570}
571
572static int config_write_ns_bind(struct vty *vty)
573{
574 struct vty_bind *vbind;
575
576 llist_for_each_entry(vbind, &binds, list) {
577 config_write_vbind(vty, vbind);
578 }
579
580 return 0;
581}
582
Alexander Couzens260cd522021-01-28 20:31:31 +0100583static int config_write_ns(struct vty *vty)
584{
Harald Welted164ef82021-03-04 22:29:17 +0100585 struct vty_nse_bind *vbind;
Alexander Couzens260cd522021-01-28 20:31:31 +0100586 unsigned int i;
587 int ret;
588
589 vty_out(vty, "ns%s", VTY_NEWLINE);
590
591 for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++)
592 vty_out(vty, " timer %s %u%s",
593 get_value_string(gprs_ns_timer_strs, i),
594 vty_nsi->timeout[i], VTY_NEWLINE);
595
596 ret = config_write_ns_bind(vty);
597 if (ret)
598 return ret;
599
Harald Welted164ef82021-03-04 22:29:17 +0100600 llist_for_each_entry(vbind, &ip_sns_default_binds, list) {
601 vty_out(vty, " ip-sns-default bind %s%s", vbind->vbind->name, VTY_NEWLINE);
602 }
603
Alexander Couzens260cd522021-01-28 20:31:31 +0100604 ret = config_write_ns_nse(vty);
605 if (ret)
606 return ret;
607
608 return 0;
609}
610
611
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100612static struct cmd_node ns_bind_node = {
613 L_NS_BIND_NODE,
614 "%s(config-ns-bind)# ",
615 1,
616};
617
618DEFUN(cfg_ns_bind_listen, cfg_ns_bind_listen_cmd,
619 "listen " VTY_IPV46_CMD " <1-65535>",
Harald Welte2230a912021-03-04 20:09:50 +0100620 "Configure local IP + Port of this bind\n"
621 "Local IPv4 Address\n" "Local IPv6 Address\n"
622 "Local UDP Port\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100623 )
624{
625 struct vty_bind *vbind = vty->index;
626 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100627 int rc;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100628 const char *addr_str = argv[0];
629 unsigned int port = atoi(argv[1]);
630 struct osmo_sockaddr_str sockaddr_str;
631 struct osmo_sockaddr sockaddr;
632
633 if (vbind->ll != GPRS_NS2_LL_UDP) {
634 vty_out(vty, "listen can be only used with UDP bind%s",
635 VTY_NEWLINE);
636 return CMD_WARNING;
637 }
638
639 if (osmo_sockaddr_str_from_str(&sockaddr_str, addr_str, port)) {
640 vty_out(vty, "Can not parse the Address %s %s%s", argv[0], argv[1], VTY_NEWLINE);
641 return CMD_WARNING;
642 }
643 osmo_sockaddr_str_to_sockaddr(&sockaddr_str, &sockaddr.u.sas);
644 if (gprs_ns2_ip_bind_by_sockaddr(vty_nsi, &sockaddr)) {
645 vty_out(vty, "A bind with the specified address already exists!%s", VTY_NEWLINE);
646 return CMD_WARNING;
647 }
648
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100649 rc = gprs_ns2_ip_bind(vty_nsi, vbind->name, &sockaddr, vbind->dscp, &bind);
650 if (rc != 0) {
651 vty_out(vty, "Failed to create the bind (rc %d)!%s", rc, VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100652 return CMD_WARNING;
653 }
654
655 bind->accept_ipaccess = vbind->accept_ipaccess;
656 bind->accept_sns = vbind->accept_sns;
657
658 return CMD_SUCCESS;
659}
660
661DEFUN(cfg_no_ns_bind_listen, cfg_no_ns_bind_listen_cmd,
662 "no listen",
663 NO_STR
664 "Delete a IP/Port assignment\n"
665 )
666{
667 struct vty_bind *vbind = vty->index;
668 struct gprs_ns2_vc_bind *bind;
669
670 if (vbind->ll != GPRS_NS2_LL_UDP) {
671 vty_out(vty, "no listen can be only used with UDP bind%s", VTY_NEWLINE);
672 return CMD_WARNING;
673 }
674
675 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
676 if (!bind)
677 return CMD_ERR_NOTHING_TODO;
678
Daniel Willmann90432052021-01-26 16:09:18 +0100679 OSMO_ASSERT(bind->ll == GPRS_NS2_LL_UDP);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100680 bind->driver->free_bind(bind);
681 return CMD_SUCCESS;
682}
683
684DEFUN(cfg_ns_bind_dscp, cfg_ns_bind_dscp_cmd,
Harald Weltec96d7162021-04-27 21:56:25 +0200685 "dscp <0-63>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100686 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
687{
688 struct vty_bind *vbind = vty->index;
689 struct gprs_ns2_vc_bind *bind;
690 uint16_t dscp = atoi(argv[0]);
691
692 if (vbind->ll != GPRS_NS2_LL_UDP) {
693 vty_out(vty, "dscp can be only used with UDP bind%s",
694 VTY_NEWLINE);
695 return CMD_WARNING;
696 }
697
698 vbind->dscp = dscp;
699 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
700 if (bind)
701 gprs_ns2_ip_bind_set_dscp(bind, dscp);
702
703 return CMD_SUCCESS;
704}
705
706DEFUN(cfg_no_ns_bind_dscp, cfg_no_ns_bind_dscp_cmd,
707 "no dscp",
708 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
709{
710 struct vty_bind *vbind = vty->index;
711 struct gprs_ns2_vc_bind *bind;
712 uint16_t dscp = 0;
713
714 if (vbind->ll != GPRS_NS2_LL_UDP) {
715 vty_out(vty, "dscp can be only used with UDP bind%s",
716 VTY_NEWLINE);
717 return CMD_WARNING;
718 }
719
720 vbind->dscp = dscp;
721 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
722 if (bind)
723 gprs_ns2_ip_bind_set_dscp(bind, dscp);
724
725 return CMD_SUCCESS;
726}
727
Harald Welted99e4ee2021-04-28 19:57:12 +0200728DEFUN(cfg_ns_bind_priority, cfg_ns_bind_priority_cmd,
Harald Welte5782fec2021-04-29 21:28:53 +0200729 "socket-priority <0-255>",
Harald Welted99e4ee2021-04-28 19:57:12 +0200730 "Set socket priority on the UDP socket\n" "Priority Value (>6 requires CAP_NET_ADMIN)\n")
731{
732 struct vty_bind *vbind = vty->index;
733 struct gprs_ns2_vc_bind *bind;
734 uint8_t prio = atoi(argv[0]);
735
736 if (vbind->ll != GPRS_NS2_LL_UDP) {
737 vty_out(vty, "dscp can be only used with UDP bind%s",
738 VTY_NEWLINE);
739 return CMD_WARNING;
740 }
741
742 vbind->priority = prio;
743 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
744 if (bind)
745 gprs_ns2_ip_bind_set_priority(bind, prio);
746
747 return CMD_SUCCESS;
748}
749
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100750DEFUN(cfg_ns_bind_ipaccess, cfg_ns_bind_ipaccess_cmd,
751 "accept-ipaccess",
752 "Allow to create dynamic NS Entity by NS Reset PDU on UDP (ip.access style)\n"
753 )
754{
755 struct vty_bind *vbind = vty->index;
756 struct gprs_ns2_vc_bind *bind;
757
758 if (vbind->ll != GPRS_NS2_LL_UDP) {
759 vty_out(vty, "accept-ipaccess can be only used with UDP bind%s",
760 VTY_NEWLINE);
761 return CMD_WARNING;
762 }
763
764 vbind->accept_ipaccess = true;
765 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
766 if (bind)
767 bind->accept_ipaccess = true;
768
769 return CMD_SUCCESS;
770}
771
772DEFUN(cfg_no_ns_bind_ipaccess, cfg_no_ns_bind_ipaccess_cmd,
773 "no accept-ipaccess",
774 NO_STR
775 "Reject NS Reset PDU on UDP (ip.access style)\n"
776 )
777{
778 struct vty_bind *vbind = vty->index;
779 struct gprs_ns2_vc_bind *bind;
780
781 if (vbind->ll != GPRS_NS2_LL_UDP) {
782 vty_out(vty, "no accept-ipaccess can be only used with UDP bind%s",
783 VTY_NEWLINE);
784 return CMD_WARNING;
785 }
786
787 vbind->accept_ipaccess = false;
788 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
789 if (bind)
790 bind->accept_ipaccess = false;
791
792 return CMD_SUCCESS;
793}
794
Harald Welte42e36462021-03-03 18:12:09 +0100795DEFUN(cfg_ns_bind_accept_sns, cfg_ns_bind_accept_sns_cmd,
796 "accept-dynamic-ip-sns",
797 "Allow to create dynamic NS Entities by IP-SNS PDUs\n"
798 )
799{
800 struct vty_bind *vbind = vty->index;
801 struct gprs_ns2_vc_bind *bind;
802
803 if (vbind->ll != GPRS_NS2_LL_UDP) {
804 vty_out(vty, "accept-dynamic-ip-sns can be only used with UDP bind%s",
805 VTY_NEWLINE);
806 return CMD_WARNING;
807 }
808
809 vbind->accept_sns = true;
810 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
811 if (bind)
812 bind->accept_sns = true;
813
814 return CMD_SUCCESS;
815}
816
817DEFUN(cfg_no_ns_bind_accept_sns, cfg_no_ns_bind_accept_sns_cmd,
818 "no accept-dynamic-ip-sns",
819 NO_STR
820 "Disable dynamic creation of NS Entities by IP-SNS PDUs\n"
821 )
822{
823 struct vty_bind *vbind = vty->index;
824 struct gprs_ns2_vc_bind *bind;
825
826 if (vbind->ll != GPRS_NS2_LL_UDP) {
827 vty_out(vty, "no accept-dynamic-ip-sns can be only used with UDP bind%s",
828 VTY_NEWLINE);
829 return CMD_WARNING;
830 }
831
832 vbind->accept_sns = false;
833 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
834 if (bind)
835 bind->accept_sns = false;
836
837 return CMD_SUCCESS;
838}
839
Alexander Couzensc4704762021-02-08 23:13:12 +0100840DEFUN(cfg_ns_bind_ip_sns_weight, cfg_ns_bind_ip_sns_weight_cmd,
841 "ip-sns signalling-weight <0-254> data-weight <0-254>",
842 "IP SNS\n"
843 "signalling weight used by IP-SNS dynamic configuration\n"
844 "signalling weight used by IP-SNS dynamic configuration\n"
845 "data weight used by IP-SNS dynamic configuration\n"
846 "data weight used by IP-SNS dynamic configuration\n")
847{
848 struct vty_bind *vbind = vty->index;
849 struct gprs_ns2_vc_bind *bind;
850
851 int signalling = atoi(argv[0]);
852 int data = atoi(argv[1]);
853
854 if (vbind->ll != GPRS_NS2_LL_UDP) {
855 vty_out(vty, "ip-sns signalling-weight <0-254> data-weight <0-254> can be only used with UDP bind%s",
856 VTY_NEWLINE);
857 return CMD_WARNING;
858 }
859
860 vbind->ip_sns_data_weight = data;
861 vbind->ip_sns_sig_weight = signalling;
862 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
863 if (bind)
864 gprs_ns2_ip_bind_set_sns_weight(bind, signalling, data);
865
866 return CMD_SUCCESS;
867}
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100868
869DEFUN(cfg_ns_bind_fr, cfg_ns_bind_fr_cmd,
870 "fr NETIF (fr|frnet)",
871 "frame relay\n"
872 IFNAME_STR
873 "fr (user) is used by BSS or SGSN attached to UNI of a FR network\n"
874 "frnet (network) is used by SGSN if BSS is directly attached\n"
875 )
876{
877 struct vty_bind *vbind = vty->index;
878 struct gprs_ns2_vc_bind *bind;
879 const char *netif = argv[0];
880 const char *role = argv[1];
881
882 int rc = 0;
883 enum osmo_fr_role frrole;
884
885 if (vbind->ll != GPRS_NS2_LL_FR) {
886 vty_out(vty, "fr can be only used with frame relay bind%s", VTY_NEWLINE);
887 return CMD_WARNING;
888 }
889
890 if (!strcmp(role, "fr"))
891 frrole = FR_ROLE_USER_EQUIPMENT;
892 else if (!strcmp(role, "frnet"))
893 frrole = FR_ROLE_NETWORK_EQUIPMENT;
894 else
895 return CMD_WARNING;
896
897 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
898 if (bind) {
899 vty_out(vty, "Interface %s already used.%s", netif, VTY_NEWLINE);
900 return CMD_WARNING;
901 }
902
903 rc = gprs_ns2_fr_bind(vty_nsi, vbind->name, netif, vty_fr_network, frrole, &bind);
904 if (rc < 0) {
905 LOGP(DLNS, LOGL_ERROR, "Failed to bind interface %s on fr. Err: %d\n", netif, rc);
906 return CMD_WARNING;
907 }
908
909 return CMD_SUCCESS;
910}
911
912DEFUN(cfg_no_ns_bind_fr, cfg_no_ns_bind_fr_cmd,
913 "no fr NETIF",
914 NO_STR
915 "Delete a frame relay link\n"
916 "Delete a frame relay link\n"
917 IFNAME_STR
918 )
919{
920 struct vty_bind *vbind = vty->index;
921 struct gprs_ns2_vc_bind *bind;
922 const char *netif = argv[0];
923
924 if (vbind->ll != GPRS_NS2_LL_FR) {
925 vty_out(vty, "fr can be only used with frame relay bind%s",
926 VTY_NEWLINE);
927 return CMD_WARNING;
928 }
929
930 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
931 if (!bind) {
932 vty_out(vty, "Interface not found.%s", VTY_NEWLINE);
933 return CMD_WARNING;
934 }
935
936 if (strcmp(bind->name, vbind->name)) {
937 vty_out(vty, "The specified interface is not bound to this bind.%s", VTY_NEWLINE);
938 return CMD_WARNING;
939 }
940
941 bind->driver->free_bind(bind);
942 return CMD_SUCCESS;
943}
944
945
946static struct cmd_node ns_nse_node = {
947 L_NS_NSE_NODE,
948 "%s(config-ns-nse)# ",
949 1,
950};
951
952DEFUN(cfg_ns_nse_nsvc_fr, cfg_ns_nse_nsvc_fr_cmd,
953 "nsvc fr NETIF dlci <16-1007> nsvci <0-65535>",
954 "NS Virtual Connection\n"
955 "frame relay\n"
956 "frame relay interface. Must be registered via fr vty\n"
957 NSVCI_STR
958 NSVCI_STR
959 DLCI_STR
960 DLCI_STR
961 )
962{
963 struct gprs_ns2_vc_bind *bind;
964 struct gprs_ns2_vc *nsvc;
965 struct gprs_ns2_nse *nse = vty->index;
966 const char *netif = argv[0];
967 uint16_t dlci = atoi(argv[1]);
968 uint16_t nsvci = atoi(argv[2]);
969 bool dialect_modified = false;
970 bool ll_modified = false;
971
972 if (nse->ll != GPRS_NS2_LL_FR && nse->ll != GPRS_NS2_LL_UNDEF) {
973 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
974 goto err;
975 }
976
977 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_RESETBLOCK && nse->dialect != GPRS_NS2_DIALECT_UNDEF) {
978 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
979 goto err;
980 }
981
982 if (nse->ll == GPRS_NS2_LL_UNDEF) {
983 nse->ll = GPRS_NS2_LL_FR;
984 ll_modified = true;
985 }
986
987 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +0100988 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_STATIC_RESETBLOCK);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100989 dialect_modified = true;
990 }
991
992
993 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
994 if (!bind) {
995 vty_out(vty, "Can not find fr interface \"%s\". Please configure it via fr vty.%s",
996 netif, VTY_NEWLINE);
997 goto err;
998 }
999
1000 if (gprs_ns2_fr_nsvc_by_dlci(bind, dlci)) {
1001 vty_out(vty, "A NS-VC with the specified DLCI already exist!%s", VTY_NEWLINE);
1002 goto err;
1003 }
1004
1005 if (gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci)) {
1006 vty_out(vty, "A NS-VC with the specified NS-VCI already exist!%s", VTY_NEWLINE);
1007 goto err;
1008 }
1009
1010 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
1011 if (!nsvc) {
1012 /* Could not create NS-VC, connect failed */
1013 vty_out(vty, "Failed to create the NS-VC%s", VTY_NEWLINE);
1014 goto err;
1015 }
1016 nsvc->persistent = true;
1017 return CMD_SUCCESS;
1018
1019err:
1020 if (ll_modified)
1021 nse->ll = GPRS_NS2_LL_UNDEF;
1022 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001023 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001024
1025 return CMD_WARNING;
1026}
1027
1028DEFUN(cfg_no_ns_nse_nsvc_fr_dlci, cfg_no_ns_nse_nsvc_fr_dlci_cmd,
1029 "no nsvc fr NETIF dlci <16-1007>",
1030 NO_STR
1031 "Delete frame relay NS-VC\n"
1032 "frame relay\n"
1033 "frame relay interface. Must be registered via fr vty\n"
1034 DLCI_STR
1035 DLCI_STR
1036 )
1037{
1038 struct gprs_ns2_vc_bind *bind;
1039 struct gprs_ns2_vc *nsvc;
1040 struct gprs_ns2_nse *nse = vty->index;
1041 const char *netif = argv[0];
1042 uint16_t dlci = atoi(argv[1]);
1043
1044 if (nse->ll != GPRS_NS2_LL_FR) {
1045 vty_out(vty, "This NSE doesn't support frame relay.%s", VTY_NEWLINE);
1046 return CMD_WARNING;
1047 }
1048
1049 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
1050 if (!bind) {
1051 vty_out(vty, "Can not find fr interface \"%s\"%s",
1052 netif, VTY_NEWLINE);
1053 return CMD_ERR_NOTHING_TODO;
1054 }
1055
1056 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
1057 if (!nsvc) {
1058 vty_out(vty, "Can not find a NS-VC on fr interface %s with dlci %u%s",
1059 netif, dlci, VTY_NEWLINE);
1060 return CMD_WARNING;
1061 }
1062
1063 if (nse != nsvc->nse) {
1064 vty_out(vty, "The specified NS-VC is not a part of the NSE %u!%s"
1065 "To remove this NS-VC go to the vty node 'nse %u'%s",
1066 nse->nsei, VTY_NEWLINE,
1067 nsvc->nse->nsei, VTY_NEWLINE);
1068 return CMD_WARNING;
1069 }
1070
1071 gprs_ns2_free_nsvc(nsvc);
1072 if (llist_empty(&nse->nsvc)) {
1073 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001074 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001075 }
1076
1077 return CMD_SUCCESS;
1078}
1079
1080DEFUN(cfg_no_ns_nse_nsvci, cfg_no_ns_nse_nsvci_cmd,
1081 "no nsvc nsvci <0-65535>",
1082 NO_STR
1083 "Delete NSVC\n"
1084 NSVCI_STR
1085 NSVCI_STR
1086 )
1087{
1088 struct gprs_ns2_vc *nsvc;
1089 struct gprs_ns2_nse *nse = vty->index;
1090 uint16_t nsvci = atoi(argv[0]);
1091
1092 switch (nse->dialect) {
1093 case GPRS_NS2_DIALECT_SNS:
1094 case GPRS_NS2_DIALECT_STATIC_ALIVE:
1095 vty_out(vty, "NSE doesn't support NSVCI.%s", VTY_NEWLINE);
1096 return CMD_WARNING;
1097 case GPRS_NS2_DIALECT_UNDEF:
1098 vty_out(vty, "No NSVCs configured%s", VTY_NEWLINE);
1099 return CMD_WARNING;
1100 case GPRS_NS2_DIALECT_IPACCESS:
1101 case GPRS_NS2_DIALECT_STATIC_RESETBLOCK:
1102 break;
1103 }
1104
1105 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci);
1106 if (!nsvc) {
1107 vty_out(vty, "Can not find NS-VC with NS-VCI %u%s", nsvci, VTY_NEWLINE);
1108 return CMD_WARNING;
1109 }
1110
1111 if (nse != nsvc->nse) {
1112 vty_out(vty, "NS-VC with NS-VCI %u is not part of this NSE!%s",
1113 nsvci, VTY_NEWLINE);
1114 return CMD_WARNING;
1115 }
1116
1117 gprs_ns2_free_nsvc(nsvc);
1118 if (llist_empty(&nse->nsvc)) {
1119 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001120 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001121 }
1122
1123 return CMD_SUCCESS;
1124}
1125
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001126static int ns_nse_nsvc_udp_cmds(struct vty *vty, const char *bind_name, const char *remote_char, uint16_t port,
1127 uint16_t sig_weight, uint16_t data_weight)
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001128{
1129 struct gprs_ns2_vc_bind *bind;
1130 struct gprs_ns2_vc *nsvc;
1131 struct gprs_ns2_nse *nse = vty->index;
1132 bool dialect_modified = false;
1133 bool ll_modified = false;
1134
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001135 struct osmo_sockaddr_str remote_str;
1136 struct osmo_sockaddr remote;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001137
1138 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1139 nse->ll = GPRS_NS2_LL_UDP;
1140 ll_modified = true;
1141 }
1142
1143 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001144 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_STATIC_ALIVE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001145 dialect_modified = true;
1146 }
1147
1148 if (nse->ll != GPRS_NS2_LL_UDP) {
1149 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1150 goto err;
1151 }
1152
1153 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
1154 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1155 goto err;
1156 }
1157
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001158 if (osmo_sockaddr_str_from_str(&remote_str, remote_char, port)) {
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001159 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1160 goto err;
1161 }
1162
1163 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1164 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1165 goto err;
1166 }
1167
1168 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1169 if (!bind) {
1170 vty_out(vty, "Can not find bind with name %s%s",
1171 bind_name, VTY_NEWLINE);
1172 goto err;
1173 }
1174
1175 if (bind->ll != GPRS_NS2_LL_UDP) {
1176 vty_out(vty, "Bind %s is not an UDP bind.%s",
1177 bind_name, VTY_NEWLINE);
1178 goto err;
1179 }
1180
Alexander Couzens7bb39e32021-02-16 23:06:53 +01001181 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1182 if (nsvc) {
1183 if (nsvc->nse == nse)
1184 vty_out(vty, "Specified NSVC is already present in this NSE.%s", VTY_NEWLINE);
1185 else
1186 vty_out(vty, "Specified NSVC is already present in another NSE%05u.%s", nsvc->nse->nsei, VTY_NEWLINE);
1187 goto err;
1188 }
1189
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001190 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, 0);
1191 if (!nsvc) {
1192 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
1193 goto err;
1194 }
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001195 nsvc->sig_weight = sig_weight;
1196 nsvc->data_weight = data_weight;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001197 nsvc->persistent = true;
1198
1199 return CMD_SUCCESS;
1200
1201err:
1202 if (ll_modified)
1203 nse->ll = GPRS_NS2_LL_UNDEF;
1204 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001205 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001206 return CMD_WARNING;
1207}
1208
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001209DEFUN(cfg_ns_nse_nsvc_udp, cfg_ns_nse_nsvc_udp_cmd,
1210 "nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
1211 "NS Virtual Connection\n"
1212 "NS over UDP\n"
1213 "A unique bind identifier created by ns bind\n"
1214 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1215 "Remote UDP Port\n")
1216{
1217 const char *bind_name = argv[0];
1218 const char *remote = argv[1];
1219 uint16_t port = atoi(argv[2]);
1220 uint16_t sig_weight = 1;
1221 uint16_t data_weight = 1;
1222
1223 return ns_nse_nsvc_udp_cmds(vty, bind_name, remote, port, sig_weight, data_weight);
1224}
1225
1226DEFUN(cfg_ns_nse_nsvc_udp_weights, cfg_ns_nse_nsvc_udp_weights_cmd,
1227 "nsvc udp BIND " VTY_IPV46_CMD " <1-65535> signalling-weight <0-254> data-weight <0-254>",
1228 "NS Virtual Connection\n"
1229 "NS over UDP\n"
1230 "A unique bind identifier created by ns bind\n"
1231 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1232 "Remote UDP Port\n"
1233 "Signalling weight of the NSVC (default = 1)\n"
1234 "Signalling weight of the NSVC (default = 1)\n"
1235 "Data weight of the NSVC (default = 1)\n"
1236 "Data weight of the NSVC (default = 1)\n"
1237 )
1238{
1239 const char *bind_name = argv[0];
1240 const char *remote = argv[1];
1241 uint16_t port = atoi(argv[2]);
1242 uint16_t sig_weight = atoi(argv[3]);
1243 uint16_t data_weight = atoi(argv[4]);
1244
1245 return ns_nse_nsvc_udp_cmds(vty, bind_name, remote, port, sig_weight, data_weight);
1246}
1247
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001248DEFUN(cfg_no_ns_nse_nsvc_udp, cfg_no_ns_nse_nsvc_udp_cmd,
1249 "no nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
1250 NO_STR
1251 "Delete a NS Virtual Connection\n"
1252 "NS over UDP\n"
1253 "A unique bind identifier created by ns bind\n"
1254 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1255 "Remote UDP Port\n"
1256 )
1257{
1258 struct gprs_ns2_vc_bind *bind;
1259 struct gprs_ns2_vc *nsvc;
1260 struct gprs_ns2_nse *nse = vty->index;
1261 const char *bind_name = argv[0];
1262 struct osmo_sockaddr_str remote_str;
1263 struct osmo_sockaddr remote;
1264 uint16_t port = atoi(argv[2]);
1265
1266 if (nse->ll != GPRS_NS2_LL_UDP) {
1267 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1268 return CMD_WARNING;
1269 }
1270
1271 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
1272 vty_out(vty, "This NSE doesn't support UDP with dialect static alive.%s", VTY_NEWLINE);
1273 return CMD_WARNING;
1274 }
1275
1276 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1277 if (!bind) {
1278 vty_out(vty, "Can not find bind with name %s%s",
1279 bind_name, VTY_NEWLINE);
1280 return CMD_WARNING;
1281 }
1282
1283 if (bind->ll != GPRS_NS2_LL_UDP) {
1284 vty_out(vty, "Bind %s is not an UDP bind.%s",
1285 bind_name, VTY_NEWLINE);
1286 return CMD_WARNING;
1287 }
1288
1289 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1290 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1291 return CMD_WARNING;
1292 }
1293
1294 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1295 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1296 return CMD_WARNING;
1297 }
1298
1299 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1300 if (!nsvc) {
1301 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1302 remote_str.ip, remote_str.port, VTY_NEWLINE);
1303 return CMD_WARNING;
1304 }
1305
1306 if (!nsvc->persistent) {
1307 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1308 remote_str.ip, remote_str.port, VTY_NEWLINE);
1309 return CMD_WARNING;
1310 }
1311
1312 if (nsvc->nse != nse) {
1313 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1314 return CMD_WARNING;
1315 }
1316
1317 gprs_ns2_free_nsvc(nsvc);
1318 if (llist_empty(&nse->nsvc)) {
1319 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001320 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001321 }
1322
1323 return CMD_SUCCESS;
1324}
1325
1326DEFUN(cfg_ns_nse_nsvc_ipa, cfg_ns_nse_nsvc_ipa_cmd,
1327 "nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>" ,
1328 "NS Virtual Connection\n"
1329 "NS over UDP ip.access style (uses RESET/BLOCK)\n"
1330 "A unique bind identifier created by ns bind\n"
1331 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1332 "Remote UDP Port\n"
1333 NSVCI_STR
1334 NSVCI_STR
1335 )
1336{
1337 struct gprs_ns2_vc_bind *bind;
1338 struct gprs_ns2_vc *nsvc;
1339 struct gprs_ns2_nse *nse = vty->index;
1340 bool dialect_modified = false;
1341 bool ll_modified = false;
1342
1343 const char *bind_name = argv[0];
1344 struct osmo_sockaddr_str remote_str;
1345 struct osmo_sockaddr remote;
1346 uint16_t port = atoi(argv[2]);
1347 uint16_t nsvci = atoi(argv[3]);
1348
1349 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1350 nse->ll = GPRS_NS2_LL_UDP;
1351 ll_modified = true;
1352 }
1353
1354 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001355 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_IPACCESS);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001356 dialect_modified = true;
1357 }
1358
1359 if (nse->ll != GPRS_NS2_LL_UDP) {
1360 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1361 goto err;
1362 }
1363
1364 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1365 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1366 goto err;
1367 }
1368
1369 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1370 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1371 goto err;
1372 }
1373
1374 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1375 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1376 goto err;
1377 }
1378
1379 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1380 if (!bind) {
1381 vty_out(vty, "Can not find bind with name %s%s",
1382 bind_name, VTY_NEWLINE);
1383 goto err;
1384 }
1385
1386 if (bind->ll != GPRS_NS2_LL_UDP) {
1387 vty_out(vty, "Bind %s is not an UDP bind.%s",
1388 bind_name, VTY_NEWLINE);
1389 goto err;
1390 }
1391
1392 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, nsvci);
1393 if (!nsvc) {
1394 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
1395 goto err;
1396 }
1397 nsvc->persistent = true;
1398
1399 return CMD_SUCCESS;
1400
1401err:
1402 if (ll_modified)
1403 nse->ll = GPRS_NS2_LL_UNDEF;
1404 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001405 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001406 return CMD_WARNING;
1407}
1408
1409DEFUN(cfg_no_ns_nse_nsvc_ipa, cfg_no_ns_nse_nsvc_ipa_cmd,
1410 "no nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>",
1411 NO_STR
1412 "Delete a NS Virtual Connection\n"
1413 "NS over UDP\n"
1414 "A unique bind identifier created by ns bind\n"
1415 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1416 "Remote UDP Port\n"
1417 NSVCI_STR
1418 NSVCI_STR
1419 )
1420{
1421 struct gprs_ns2_vc_bind *bind;
1422 struct gprs_ns2_vc *nsvc;
1423 struct gprs_ns2_nse *nse = vty->index;
1424 const char *bind_name = argv[0];
1425 struct osmo_sockaddr_str remote_str;
1426 struct osmo_sockaddr remote;
1427 uint16_t port = atoi(argv[2]);
1428 uint16_t nsvci = atoi(argv[3]);
1429
1430 if (nse->ll != GPRS_NS2_LL_UDP) {
1431 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1432 return CMD_WARNING;
1433 }
1434
1435 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1436 vty_out(vty, "This NSE doesn't support UDP with dialect ipaccess.%s", VTY_NEWLINE);
1437 return CMD_WARNING;
1438 }
1439
1440 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1441 if (!bind) {
1442 vty_out(vty, "Can not find bind with name %s%s",
1443 bind_name, VTY_NEWLINE);
1444 return CMD_WARNING;
1445 }
1446
1447 if (bind->ll != GPRS_NS2_LL_UDP) {
1448 vty_out(vty, "Bind %s is not an UDP bind.%s",
1449 bind_name, VTY_NEWLINE);
1450 return CMD_WARNING;
1451 }
1452
1453 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1454 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1455 return CMD_WARNING;
1456 }
1457
1458 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1459 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1460 return CMD_WARNING;
1461 }
1462
1463 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1464 if (!nsvc) {
1465 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1466 remote_str.ip, remote_str.port, VTY_NEWLINE);
1467 return CMD_WARNING;
1468 }
1469
1470 if (!nsvc->persistent) {
1471 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1472 remote_str.ip, remote_str.port, VTY_NEWLINE);
1473 return CMD_WARNING;
1474 }
1475
1476 if (nsvc->nse != nse) {
1477 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1478 return CMD_WARNING;
1479 }
1480
1481 if (!nsvc->nsvci_is_valid) {
1482 vty_out(vty, "NS-VC doesn't have a nsvci!%s", VTY_NEWLINE);
1483 return CMD_WARNING;
1484 }
1485
1486 if (nsvc->nsvci != nsvci) {
1487 vty_out(vty, "NS-VC has a different nsvci (%u)!%s",
1488 nsvc->nsvci, VTY_NEWLINE);
1489 return CMD_WARNING;
1490 }
1491
1492 gprs_ns2_free_nsvc(nsvc);
1493 if (llist_empty(&nse->nsvc)) {
1494 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001495 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001496 }
1497
1498 return CMD_SUCCESS;
1499}
1500
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001501DEFUN(cfg_ns_nse_ip_sns_remote, cfg_ns_nse_ip_sns_remote_cmd,
1502 "ip-sns-remote " VTY_IPV46_CMD " <1-65535>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001503 "SNS Initial Endpoint\n"
1504 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1505 "SGSN UDP Port\n"
1506 )
1507{
1508 struct gprs_ns2_nse *nse = vty->index;
1509 bool dialect_modified = false;
1510 bool ll_modified = false;
1511 int rc;
1512
1513 /* argv[0] */
1514 struct osmo_sockaddr_str remote_str;
1515 struct osmo_sockaddr remote;
1516 uint16_t port = atoi(argv[1]);
1517
1518 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1519 nse->ll = GPRS_NS2_LL_UDP;
1520 ll_modified = true;
1521 }
1522
1523 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001524 if (ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_SNS) < 0)
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001525 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001526 dialect_modified = true;
1527 }
1528
1529 if (nse->ll != GPRS_NS2_LL_UDP) {
1530 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1531 goto err;
1532 }
1533
1534 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1535 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1536 goto err;
1537 }
1538
1539 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1540 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1541 goto err;
1542 }
1543
1544 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1545 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1546 goto err;
1547 }
1548
1549 rc = gprs_ns2_sns_add_endpoint(nse, &remote);
1550 switch (rc) {
1551 case 0:
1552 return CMD_SUCCESS;
1553 case -EADDRINUSE:
1554 vty_out(vty, "Specified SNS endpoint already part of the NSE.%s", VTY_NEWLINE);
1555 return CMD_WARNING;
1556 default:
1557 vty_out(vty, "Can not add specified SNS endpoint.%s", VTY_NEWLINE);
1558 return CMD_WARNING;
1559 }
1560
1561err:
1562 if (ll_modified)
1563 nse->ll = GPRS_NS2_LL_UNDEF;
1564 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001565 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001566 return CMD_WARNING;
1567}
1568
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001569DEFUN(cfg_no_ns_nse_ip_sns_remote, cfg_no_ns_nse_ip_sns_remote_cmd,
1570 "no ip-sns-remote " VTY_IPV46_CMD " <1-65535>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001571 NO_STR
1572 "Delete a SNS Initial Endpoint\n"
1573 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1574 "SGSN UDP Port\n"
1575 )
1576{
1577 struct gprs_ns2_nse *nse = vty->index;
1578 struct osmo_sockaddr_str remote_str; /* argv[0] */
1579 struct osmo_sockaddr remote;
1580 uint16_t port = atoi(argv[1]);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001581
1582 if (nse->ll != GPRS_NS2_LL_UDP) {
1583 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1584 return CMD_WARNING;
1585 }
1586
1587 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1588 vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%s", VTY_NEWLINE);
1589 return CMD_WARNING;
1590 }
1591
1592 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1593 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1594 return CMD_WARNING;
1595 }
1596
1597 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1598 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1599 return CMD_WARNING;
1600 }
1601
1602 if (gprs_ns2_sns_del_endpoint(nse, &remote)) {
1603 vty_out(vty, "Can not remove specified SNS endpoint.%s", VTY_NEWLINE);
1604 return CMD_WARNING;
1605 }
1606
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001607 if (vty_nse_check_sns(nse)) {
1608 /* there is still sns configuration valid */
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001609 return CMD_SUCCESS;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001610 } else {
1611 /* clean up nse to allow other nsvc commands */
Harald Welte06d9bf92021-03-05 10:20:11 +01001612 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001613 nse->ll = GPRS_NS2_LL_UNDEF;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001614 }
1615
1616 return CMD_SUCCESS;
1617}
1618
Harald Welted164ef82021-03-04 22:29:17 +01001619/* add all IP-SNS default binds to the given NSE */
1620int ns2_sns_add_sns_default_binds(struct gprs_ns2_nse *nse)
1621{
1622 struct vty_nse_bind *vnse_bind;
1623 int count = 0;
1624
1625 OSMO_ASSERT(nse->ll == GPRS_NS2_LL_UDP);
1626 OSMO_ASSERT(nse->dialect == GPRS_NS2_DIALECT_SNS);
1627
1628 llist_for_each_entry(vnse_bind, &ip_sns_default_binds, list) {
1629 struct gprs_ns2_vc_bind *bind = gprs_ns2_bind_by_name(vty_nsi, vnse_bind->vbind->name);
1630 /* the bind might not yet created because "listen" is missing. */
1631 if (!bind)
1632 continue;
1633 gprs_ns2_sns_add_bind(nse, bind);
1634 count++;
1635 }
1636 return count;
1637}
1638
1639DEFUN(cfg_ns_ip_sns_default_bind, cfg_ns_ip_sns_default_bind_cmd,
1640 "ip-sns-default bind ID",
1641 "Defaults for dynamically created NSEs created by IP-SNS in SGSN role\n"
1642 "IP SNS binds\n"
1643 "Name of NS udp bind whose IP endpoint will be used as IP-SNS local endpoint. Can be given multiple times.\n")
1644{
1645 struct vty_bind *vbind;
1646 struct vty_nse_bind *vnse_bind;
1647 const char *name = argv[0];
1648
1649 vbind = vty_bind_by_name(name);
1650 if (!vbind) {
1651 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1652 return CMD_WARNING;
1653 }
1654
1655 if (vbind->ll != GPRS_NS2_LL_UDP) {
1656 vty_out(vty, "ip-sns-default bind can only be used with UDP bind%s", VTY_NEWLINE);
1657 return CMD_WARNING;
1658 }
1659
1660 llist_for_each_entry(vnse_bind, &ip_sns_default_binds, list) {
1661 if (vnse_bind->vbind == vbind)
1662 return CMD_SUCCESS;
1663 }
1664
1665 vnse_bind = talloc(vty_nsi, struct vty_nse_bind);
1666 if (!vnse_bind)
1667 return CMD_WARNING;
1668 vnse_bind->vbind = vbind;
1669
1670 llist_add_tail(&vnse_bind->list, &ip_sns_default_binds);
1671
1672 return CMD_SUCCESS;
1673}
1674
1675DEFUN(cfg_no_ns_ip_sns_default_bind, cfg_no_ns_ip_sns_default_bind_cmd,
1676 "no ip-sns-default bind ID",
1677 NO_STR "Defaults for dynamically created NSEs created by IP-SNS in SGSN role\n"
1678 "IP SNS binds\n"
1679 "Name of NS udp bind whose IP endpoint will be removed as IP-SNS local endpoint.\n")
1680{
1681 struct vty_bind *vbind;
1682 struct vty_nse_bind *vnse_bind;
1683 const char *name = argv[0];
1684
1685 vbind = vty_bind_by_name(name);
1686 if (!vbind) {
1687 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1688 return CMD_WARNING;
1689 }
1690
1691 if (vbind->ll != GPRS_NS2_LL_UDP) {
1692 vty_out(vty, "ip-sns-default bind can only be used with UDP bind%s", VTY_NEWLINE);
1693 return CMD_WARNING;
1694 }
1695
1696 llist_for_each_entry(vnse_bind, &ip_sns_default_binds, list) {
1697 if (vnse_bind->vbind == vbind) {
1698 llist_del(&vnse_bind->list);
1699 talloc_free(vnse_bind);
1700 return CMD_SUCCESS;
1701 }
1702 }
1703
1704 vty_out(vty, "Bind '%s' was not an ip-sns-default bind%s", name, VTY_NEWLINE);
1705 return CMD_WARNING;
1706}
1707
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001708DEFUN(cfg_ns_nse_ip_sns_bind, cfg_ns_nse_ip_sns_bind_cmd,
1709 "ip-sns-bind BINDID",
1710 "IP SNS binds\n"
Harald Welte2230a912021-03-04 20:09:50 +01001711 "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 +01001712{
1713 struct gprs_ns2_nse *nse = vty->index;
1714 struct gprs_ns2_vc_bind *bind;
1715 struct vty_bind *vbind;
1716 struct vty_nse *vnse;
1717 const char *name = argv[0];
1718 bool ll_modified = false;
1719 bool dialect_modified = false;
1720 int rc;
1721
1722 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1723 nse->ll = GPRS_NS2_LL_UDP;
1724 ll_modified = true;
1725 }
1726
1727 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001728 if (ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_SNS) < 0)
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001729 goto err;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001730 dialect_modified = true;
1731 }
1732
1733 if (nse->ll != GPRS_NS2_LL_UDP) {
1734 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1735 goto err;
1736 }
1737
1738 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1739 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1740 goto err;
1741 }
1742
1743 vbind = vty_bind_by_name(name);
1744 if (!vbind) {
1745 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1746 goto err;
1747 }
1748
1749 if (vbind->ll != GPRS_NS2_LL_UDP) {
1750 vty_out(vty, "ip-sns-bind can only be used with UDP bind%s",
1751 VTY_NEWLINE);
1752 goto err;
1753 }
1754
1755 /* the vnse has been created together when creating the nse node. The parent node should check this already! */
1756 vnse = vty_nse_by_nsei(nse->nsei);
1757 OSMO_ASSERT(vnse);
1758
1759 rc = vty_nse_add_vbind(vnse, vbind);
1760 switch (rc) {
1761 case 0:
1762 break;
1763 case -EALREADY:
1764 vty_out(vty, "Failed to add ip-sns-bind %s already present%s", name, VTY_NEWLINE);
1765 goto err;
1766 case -ENOMEM:
1767 vty_out(vty, "Failed to add ip-sns-bind %s out of memory%s", name, VTY_NEWLINE);
1768 goto err;
1769 default:
1770 vty_out(vty, "Failed to add ip-sns-bind %s! %d%s", name, rc, VTY_NEWLINE);
1771 goto err;
1772 }
1773
1774 /* the bind might not yet created because "listen" is missing. */
1775 bind = gprs_ns2_bind_by_name(vty_nsi, name);
1776 if (!bind)
1777 return CMD_SUCCESS;
1778
1779 rc = gprs_ns2_sns_add_bind(nse, bind);
1780 switch (rc) {
1781 case 0:
1782 break;
1783 case -EALREADY:
1784 vty_out(vty, "Failed to add ip-sns-bind %s already present%s", name, VTY_NEWLINE);
1785 goto err;
1786 case -ENOMEM:
1787 vty_out(vty, "Failed to add ip-sns-bind %s out of memory%s", name, VTY_NEWLINE);
1788 goto err;
1789 default:
1790 vty_out(vty, "Failed to add ip-sns-bind %s! %d%s", name, rc, VTY_NEWLINE);
1791 goto err;
1792 }
1793
1794 return CMD_SUCCESS;
1795err:
1796 if (ll_modified)
1797 nse->ll = GPRS_NS2_LL_UNDEF;
1798 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001799 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001800
1801 return CMD_WARNING;
1802}
1803
1804DEFUN(cfg_no_ns_nse_ip_sns_bind, cfg_no_ns_nse_ip_sns_bind_cmd,
1805 "no ip-sns-bind BINDID",
1806 NO_STR
1807 "IP SNS binds\n"
Harald Welte2230a912021-03-04 20:09:50 +01001808 "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 +01001809{
1810 struct gprs_ns2_nse *nse = vty->index;
1811 struct gprs_ns2_vc_bind *bind;
1812 struct vty_bind *vbind;
1813 struct vty_nse *vnse;
1814 const char *name = argv[0];
1815 int rc;
1816
1817 if (nse->ll != GPRS_NS2_LL_UDP) {
1818 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1819 return CMD_WARNING;
1820 }
1821
1822 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1823 vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%s", VTY_NEWLINE);
1824 return CMD_WARNING;
1825 }
1826
1827 vbind = vty_bind_by_name(name);
1828 if (!vbind) {
1829 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1830 return CMD_WARNING;
1831 }
1832
1833 if (vbind->ll != GPRS_NS2_LL_UDP) {
1834 vty_out(vty, "no ip-sns-bind can only be used with UDP bind%s",
1835 VTY_NEWLINE);
1836 return CMD_WARNING;
1837 }
1838
1839 /* the vnse has been created together when creating the nse node. The parent node should check this already! */
1840 vnse = vty_nse_by_nsei(nse->nsei);
1841 OSMO_ASSERT(vnse);
1842
1843 rc = vty_nse_remove_vbind(vnse, vbind);
1844 switch(rc) {
1845 case 0:
1846 break;
1847 case -ENOENT:
1848 vty_out(vty, "Bind %s is not part of this NSE%s", name, VTY_NEWLINE);
1849 return CMD_WARNING;
1850 case -EINVAL:
1851 vty_out(vty, "no ip-sns-bind can only be used with UDP bind%s",
1852 VTY_NEWLINE);
1853 return CMD_WARNING;
1854 default:
1855 return CMD_WARNING;
1856 }
1857
1858 /* the bind might not exists yet */
1859 bind = gprs_ns2_bind_by_name(vty_nsi, name);
1860 if (bind)
1861 gprs_ns2_sns_del_bind(nse, bind);
1862
1863 if (!vty_nse_check_sns(nse)) {
1864 /* clean up nse to allow other nsvc commands */
Harald Welte06d9bf92021-03-05 10:20:11 +01001865 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001866 nse->ll = GPRS_NS2_LL_UNDEF;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001867 }
1868
1869 return CMD_SUCCESS;
1870}
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001871
1872/* non-config commands */
Alexander Couzens75b61882021-03-21 16:18:17 +01001873void ns2_vty_dump_nsvc(struct vty *vty, struct gprs_ns2_vc *nsvc, bool stats)
Alexander Couzens6a161492020-07-12 13:45:50 +02001874{
Harald Weltedc2d0802020-12-01 18:17:28 +01001875 char nsvci_str[32];
1876
1877 if (nsvc->nsvci_is_valid)
1878 snprintf(nsvci_str, sizeof(nsvci_str), "%05u", nsvc->nsvci);
1879 else
1880 snprintf(nsvci_str, sizeof(nsvci_str), "none");
1881
Alexander Couzens1dd9cbf2021-03-21 16:22:08 +01001882 vty_out(vty, " NSVCI %s: %s %s data_weight=%u sig_weight=%u %s%s", nsvci_str,
Harald Weltedc2d0802020-12-01 18:17:28 +01001883 osmo_fsm_inst_state_name(nsvc->fi),
1884 nsvc->persistent ? "PERSIST" : "DYNAMIC",
1885 nsvc->data_weight, nsvc->sig_weight,
1886 gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001887
1888 if (stats) {
Alexander Couzens1dd9cbf2021-03-21 16:22:08 +01001889 vty_out_rate_ctr_group(vty, " ", nsvc->ctrg);
1890 vty_out_stat_item_group(vty, " ", nsvc->statg);
Alexander Couzens6a161492020-07-12 13:45:50 +02001891 }
1892}
1893
1894static void dump_nse(struct vty *vty, const struct gprs_ns2_nse *nse, bool stats, bool persistent_only)
1895{
1896 struct gprs_ns2_vc *nsvc;
Alexander Couzens0ea4a4e2021-03-21 16:37:23 +01001897 unsigned int nsvcs = 0;
Alexander Couzens6a161492020-07-12 13:45:50 +02001898
Alexander Couzens3e539ed2021-03-21 16:25:18 +01001899 if (persistent_only && !nse->persistent)
1900 return;
1901
Harald Welte0ff12ad2020-12-01 17:51:07 +01001902 vty_out(vty, "NSEI %05u: %s, %s%s", nse->nsei, gprs_ns2_lltype_str(nse->ll),
1903 nse->alive ? "ALIVE" : "DEAD", VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001904
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001905 ns2_sns_dump_vty(vty, " ", nse, stats);
Alexander Couzens0ea4a4e2021-03-21 16:37:23 +01001906 llist_for_each_entry(nsvc, &nse->nsvc, list) {
1907 nsvcs++;
1908 }
1909 vty_out(vty, " %u NS-VC:%s", nsvcs, VTY_NEWLINE);
Alexander Couzens3e539ed2021-03-21 16:25:18 +01001910 llist_for_each_entry(nsvc, &nse->nsvc, list)
1911 ns2_vty_dump_nsvc(vty, nsvc, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001912}
1913
Alexander Couzens22f34712020-10-02 02:34:39 +02001914static void dump_bind(struct vty *vty, const struct gprs_ns2_vc_bind *bind, bool stats)
1915{
1916 if (bind->dump_vty)
1917 bind->dump_vty(bind, vty, stats);
Harald Welte76346072021-01-31 11:54:02 +01001918
1919 if (stats) {
1920 vty_out_stat_item_group(vty, " ", bind->statg);
1921 }
Alexander Couzens22f34712020-10-02 02:34:39 +02001922}
1923
Harald Welte2fce19a2020-12-01 17:52:55 +01001924static void dump_ns_bind(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats)
Alexander Couzens6a161492020-07-12 13:45:50 +02001925{
Alexander Couzens22f34712020-10-02 02:34:39 +02001926 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6a161492020-07-12 13:45:50 +02001927
Alexander Couzens22f34712020-10-02 02:34:39 +02001928 llist_for_each_entry(bind, &nsi->binding, list) {
1929 dump_bind(vty, bind, stats);
1930 }
Harald Welte2fce19a2020-12-01 17:52:55 +01001931}
1932
1933
1934static void dump_ns_entities(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats, bool persistent_only)
1935{
1936 struct gprs_ns2_nse *nse;
Alexander Couzens22f34712020-10-02 02:34:39 +02001937
Alexander Couzens6a161492020-07-12 13:45:50 +02001938 llist_for_each_entry(nse, &nsi->nse, list) {
1939 dump_nse(vty, nse, stats, persistent_only);
Alexander Couzens6a161492020-07-12 13:45:50 +02001940 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001941}
1942
Harald Welte25ee7552020-12-02 22:14:00 +01001943/* Backwards compatibility, among other things for the TestVTYGbproxy which expects
1944 * 'show ns' to output something about binds */
1945DEFUN_HIDDEN(show_ns, show_ns_cmd, "show ns",
1946 SHOW_STR SHOW_NS_STR)
1947{
1948 dump_ns_entities(vty, vty_nsi, false, false);
1949 dump_ns_bind(vty, vty_nsi, false);
Harald Welte069967b2021-03-30 12:05:31 +02001950 if (vty_fr_network && llist_count(&vty_fr_network->links))
1951 osmo_fr_network_dump_vty(vty, vty_fr_network);
Harald Welte25ee7552020-12-02 22:14:00 +01001952 return CMD_SUCCESS;
1953}
1954
1955
Harald Welte2fce19a2020-12-01 17:52:55 +01001956DEFUN(show_ns_binds, show_ns_binds_cmd, "show ns binds [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001957 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01001958 "Display information about the NS protocol binds\n"
1959 "Include statistic\n")
Alexander Couzens6a161492020-07-12 13:45:50 +02001960{
Harald Welte2fce19a2020-12-01 17:52:55 +01001961 bool stats = false;
1962 if (argc > 0)
1963 stats = true;
1964
1965 dump_ns_bind(vty, vty_nsi, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001966 return CMD_SUCCESS;
1967}
1968
Harald Welte2fce19a2020-12-01 17:52:55 +01001969DEFUN(show_ns_entities, show_ns_entities_cmd, "show ns entities [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001970 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01001971 "Display information about the NS protocol entities (NSEs)\n"
Alexander Couzens6a161492020-07-12 13:45:50 +02001972 "Include statistics\n")
1973{
Harald Welte2fce19a2020-12-01 17:52:55 +01001974 bool stats = false;
1975 if (argc > 0)
1976 stats = true;
1977
1978 dump_ns_entities(vty, vty_nsi, stats, false);
Alexander Couzens6a161492020-07-12 13:45:50 +02001979 return CMD_SUCCESS;
1980}
1981
1982DEFUN(show_ns_pers, show_ns_pers_cmd, "show ns persistent",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001983 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02001984 "Show only persistent NS\n")
1985{
Harald Welte2fce19a2020-12-01 17:52:55 +01001986 dump_ns_entities(vty, vty_nsi, true, true);
Alexander Couzens6a161492020-07-12 13:45:50 +02001987 return CMD_SUCCESS;
1988}
1989
1990DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001991 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02001992 "Select one NSE by its NSE Identifier\n"
1993 "Select one NSE by its NS-VC Identifier\n"
1994 "The Identifier of selected type\n"
1995 "Include Statistics\n")
1996{
1997 struct gprs_ns2_inst *nsi = vty_nsi;
1998 struct gprs_ns2_nse *nse;
1999 struct gprs_ns2_vc *nsvc;
2000 uint16_t id = atoi(argv[1]);
2001 bool show_stats = false;
2002
2003 if (argc >= 3)
2004 show_stats = true;
2005
2006 if (!strcmp(argv[0], "nsei")) {
2007 nse = gprs_ns2_nse_by_nsei(nsi, id);
2008 if (!nse) {
2009 return CMD_WARNING;
2010 }
2011
2012 dump_nse(vty, nse, show_stats, false);
2013 } else {
2014 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
2015
2016 if (!nsvc) {
2017 vty_out(vty, "No such NS Entity%s", VTY_NEWLINE);
2018 return CMD_WARNING;
2019 }
2020
Alexander Couzens75b61882021-03-21 16:18:17 +01002021 ns2_vty_dump_nsvc(vty, nsvc, show_stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02002022 }
2023
2024 return CMD_SUCCESS;
2025}
2026
Daniel Willmanndbab7142020-11-18 14:19:56 +01002027static int nsvc_force_unconf_cb(struct gprs_ns2_vc *nsvc, void *ctx)
2028{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01002029 ns2_vc_force_unconfigured(nsvc);
Harald Welte7fe8d712021-01-31 18:40:54 +01002030 ns2_vc_fsm_start(nsvc);
Daniel Willmanndbab7142020-11-18 14:19:56 +01002031 return 0;
2032}
2033
2034DEFUN_HIDDEN(nsvc_force_unconf, nsvc_force_unconf_cmd,
2035 "nsvc nsei <0-65535> force-unconfigured",
2036 "NS Virtual Connection\n"
2037 "The NSEI\n"
2038 "Reset the NSVCs back to initial state\n"
2039 )
2040{
2041 struct gprs_ns2_inst *nsi = vty_nsi;
2042 struct gprs_ns2_nse *nse;
2043
2044 uint16_t id = atoi(argv[0]);
2045
2046 nse = gprs_ns2_nse_by_nsei(nsi, id);
2047 if (!nse) {
2048 vty_out(vty, "Could not find NSE for NSEI %u%s", id, VTY_NEWLINE);
2049 return CMD_WARNING;
2050 }
2051
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002052 if (!nse->persistent) {
2053 gprs_ns2_free_nse(nse);
2054 } else if (nse->dialect == GPRS_NS2_DIALECT_SNS) {
Alexander Couzens280ed782020-12-21 18:25:41 +01002055 gprs_ns2_free_nsvcs(nse);
2056 } else {
2057 /* Perform the operation for all nsvc */
2058 gprs_ns2_nse_foreach_nsvc(nse, nsvc_force_unconf_cb, NULL);
2059 }
Daniel Willmanndbab7142020-11-18 14:19:56 +01002060
2061 return CMD_SUCCESS;
2062}
2063
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002064DEFUN(nsvc_block, nsvc_block_cmd,
Alexander Couzens27e58732021-03-21 17:12:08 +01002065 "nsvc <0-65535> (block|unblock|reset)",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002066 "NS Virtual Connection\n"
2067 NSVCI_STR
2068 "Block a NSVC. As cause code O&M intervention will be used.\n"
Alexander Couzens27e58732021-03-21 17:12:08 +01002069 "Unblock a NSVC. As cause code O&M intervention will be used.\n"
2070 "Reset a NSVC. As cause code O&M intervention will be used.\n")
Alexander Couzens841817e2020-11-19 00:41:29 +01002071{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002072 struct gprs_ns2_inst *nsi = vty_nsi;
2073 struct gprs_ns2_vc *nsvc;
Alexander Couzense7dfeac2021-03-21 17:28:36 +01002074 int rc;
Alexander Couzens841817e2020-11-19 00:41:29 +01002075
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002076 uint16_t id = atoi(argv[0]);
Alexander Couzens841817e2020-11-19 00:41:29 +01002077
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002078 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
2079 if (!nsvc) {
2080 vty_out(vty, "Could not find NSVCI %05u%s", id, VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +01002081 return CMD_WARNING;
2082 }
2083
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002084 if (!strcmp(argv[1], "block")) {
Alexander Couzense7dfeac2021-03-21 17:28:36 +01002085 rc = ns2_vc_block(nsvc);
2086 switch (rc) {
2087 case 0:
2088 vty_out(vty, "The NS-VC %05u will be blocked.%s", id, VTY_NEWLINE);
2089 return CMD_SUCCESS;
2090 case -EALREADY:
2091 vty_out(vty, "The NS-VC %05u is already blocked.%s", id, VTY_NEWLINE);
2092 return CMD_ERR_NOTHING_TODO;
2093 default:
2094 vty_out(vty, "An unknown error %d happend on NS-VC %05u.%s", rc, id, VTY_NEWLINE);
2095 return CMD_WARNING;
2096 }
Alexander Couzens27e58732021-03-21 17:12:08 +01002097 } else if (!strcmp(argv[1], "unblock")) {
Alexander Couzense7dfeac2021-03-21 17:28:36 +01002098 rc = ns2_vc_unblock(nsvc);
2099 switch (rc) {
2100 case 0:
2101 vty_out(vty, "The NS-VC %05u will be unblocked.%s", id, VTY_NEWLINE);
2102 return CMD_SUCCESS;
2103 case -EALREADY:
2104 vty_out(vty, "The NS-VC %05u is already unblocked.%s", id, VTY_NEWLINE);
2105 return CMD_ERR_NOTHING_TODO;
2106 default:
2107 vty_out(vty, "An unknown error %d happend on NS-VC %05u.%s", rc, id, VTY_NEWLINE);
2108 return CMD_WARNING;
2109 }
Alexander Couzens27e58732021-03-21 17:12:08 +01002110 } else {
2111 ns2_vc_reset(nsvc);
Alexander Couzense7dfeac2021-03-21 17:28:36 +01002112 vty_out(vty, "The NS-VC %05u has been resetted.%s", id, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02002113 }
2114
2115 return CMD_SUCCESS;
2116}
2117
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002118static void log_set_nse_filter(struct log_target *target,
2119 struct gprs_ns2_nse *nse)
Alexander Couzens6a161492020-07-12 13:45:50 +02002120{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002121 if (nse) {
2122 target->filter_map |= (1 << LOG_FLT_GB_NSE);
2123 target->filter_data[LOG_FLT_GB_NSE] = nse;
2124 } else if (target->filter_data[LOG_FLT_GB_NSE]) {
2125 target->filter_map = ~(1 << LOG_FLT_GB_NSE);
2126 target->filter_data[LOG_FLT_GB_NSE] = NULL;
2127 }
Alexander Couzens6a161492020-07-12 13:45:50 +02002128}
2129
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002130static void log_set_nsvc_filter(struct log_target *target,
2131 struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +02002132{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002133 if (nsvc) {
2134 target->filter_map |= (1 << LOG_FLT_GB_NSVC);
2135 target->filter_data[LOG_FLT_GB_NSVC] = nsvc;
2136 } else if (target->filter_data[LOG_FLT_GB_NSVC]) {
2137 target->filter_map = ~(1 << LOG_FLT_GB_NSVC);
2138 target->filter_data[LOG_FLT_GB_NSVC] = NULL;
2139 }
Alexander Couzens6a161492020-07-12 13:45:50 +02002140}
2141
Daniel Willmann751977b2020-12-02 18:59:44 +01002142DEFUN(logging_fltr_nse,
2143 logging_fltr_nse_cmd,
2144 "logging filter nse nsei <0-65535>",
2145 LOGGING_STR FILTER_STR
2146 "Filter based on NS Entity\n"
2147 "Identify NSE by NSEI\n"
2148 "Numeric identifier\n")
2149{
2150 struct log_target *tgt;
2151 struct gprs_ns2_nse *nse;
Daniel Willmann89106522020-12-04 01:36:59 +01002152 uint16_t id = atoi(argv[0]);
Daniel Willmann751977b2020-12-02 18:59:44 +01002153
2154 log_tgt_mutex_lock();
2155 tgt = osmo_log_vty2tgt(vty);
2156 if (!tgt) {
2157 log_tgt_mutex_unlock();
2158 return CMD_WARNING;
2159 }
2160
2161 nse = gprs_ns2_nse_by_nsei(vty_nsi, id);
2162 if (!nse) {
2163 vty_out(vty, "No NSE by that identifier%s", VTY_NEWLINE);
2164 log_tgt_mutex_unlock();
2165 return CMD_WARNING;
2166 }
2167
2168 log_set_nse_filter(tgt, nse);
2169 log_tgt_mutex_unlock();
2170 return CMD_SUCCESS;
2171}
2172
Alexander Couzens6a161492020-07-12 13:45:50 +02002173/* TODO: add filter for single connection by description */
2174DEFUN(logging_fltr_nsvc,
2175 logging_fltr_nsvc_cmd,
2176 "logging filter nsvc nsvci <0-65535>",
2177 LOGGING_STR FILTER_STR
2178 "Filter based on NS Virtual Connection\n"
2179 "Identify NS-VC by NSVCI\n"
2180 "Numeric identifier\n")
2181{
2182 struct log_target *tgt;
2183 struct gprs_ns2_vc *nsvc;
Daniel Willmann89106522020-12-04 01:36:59 +01002184 uint16_t id = atoi(argv[0]);
Alexander Couzens6a161492020-07-12 13:45:50 +02002185
2186 log_tgt_mutex_lock();
2187 tgt = osmo_log_vty2tgt(vty);
2188 if (!tgt) {
2189 log_tgt_mutex_unlock();
2190 return CMD_WARNING;
2191 }
2192
2193 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, id);
2194 if (!nsvc) {
2195 vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE);
2196 log_tgt_mutex_unlock();
2197 return CMD_WARNING;
2198 }
2199
2200 log_set_nsvc_filter(tgt, nsvc);
2201 log_tgt_mutex_unlock();
2202 return CMD_SUCCESS;
2203}
2204
Alexander Couzense43b46e2021-01-27 21:52:08 +01002205/*! initialized a reduced vty interface which excludes the configuration nodes besides timeouts.
2206 * This can be used by the PCU which can be only configured by the BTS/BSC and not by the vty.
2207 * \param[in] nsi NS instance on which we operate
2208 * \return 0 on success.
2209 */
2210int gprs_ns2_vty_init_reduced(struct gprs_ns2_inst *nsi)
Alexander Couzens6a161492020-07-12 13:45:50 +02002211{
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01002212 vty_nsi = nsi;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002213 INIT_LLIST_HEAD(&binds);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002214 INIT_LLIST_HEAD(&nses);
Harald Welted164ef82021-03-04 22:29:17 +01002215 INIT_LLIST_HEAD(&ip_sns_default_binds);
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01002216
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002217 vty_fr_network = osmo_fr_network_alloc(nsi);
2218 if (!vty_fr_network)
2219 return -ENOMEM;
Alexander Couzens6a161492020-07-12 13:45:50 +02002220
Harald Welte25ee7552020-12-02 22:14:00 +01002221 install_lib_element_ve(&show_ns_cmd);
Harald Welte2fce19a2020-12-01 17:52:55 +01002222 install_lib_element_ve(&show_ns_binds_cmd);
2223 install_lib_element_ve(&show_ns_entities_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002224 install_lib_element_ve(&show_ns_pers_cmd);
2225 install_lib_element_ve(&show_nse_cmd);
Daniel Willmann751977b2020-12-02 18:59:44 +01002226 install_lib_element_ve(&logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002227 install_lib_element_ve(&logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002228
Daniel Willmanndbab7142020-11-18 14:19:56 +01002229 install_lib_element(ENABLE_NODE, &nsvc_force_unconf_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002230 install_lib_element(ENABLE_NODE, &nsvc_block_cmd);
Daniel Willmanndbab7142020-11-18 14:19:56 +01002231
Daniel Willmann751977b2020-12-02 18:59:44 +01002232 install_lib_element(CFG_LOG_NODE, &logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002233 install_lib_element(CFG_LOG_NODE, &logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002234
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002235 install_lib_element(CONFIG_NODE, &cfg_ns_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002236
Alexander Couzens6a161492020-07-12 13:45:50 +02002237 install_node(&ns_node, config_write_ns);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002238 /* TODO: convert into osmo timer */
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002239 install_lib_element(L_NS_NODE, &cfg_ns_timer_cmd);
Alexander Couzense43b46e2021-01-27 21:52:08 +01002240
2241 return 0;
2242}
2243
2244int gprs_ns2_vty_init(struct gprs_ns2_inst *nsi)
2245{
2246 int rc = gprs_ns2_vty_init_reduced(nsi);
2247 if (rc)
2248 return rc;
2249
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002250 install_lib_element(L_NS_NODE, &cfg_ns_nsei_cmd);
2251 install_lib_element(L_NS_NODE, &cfg_no_ns_nsei_cmd);
2252 install_lib_element(L_NS_NODE, &cfg_ns_bind_cmd);
2253 install_lib_element(L_NS_NODE, &cfg_no_ns_bind_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002254
Harald Welted164ef82021-03-04 22:29:17 +01002255 install_lib_element(L_NS_NODE, &cfg_ns_ip_sns_default_bind_cmd);
2256 install_lib_element(L_NS_NODE, &cfg_no_ns_ip_sns_default_bind_cmd);
2257
Alexander Couzens260cd522021-01-28 20:31:31 +01002258 install_node(&ns_bind_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002259 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_listen_cmd);
2260 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_listen_cmd);
2261 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_dscp_cmd);
2262 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_dscp_cmd);
Harald Welted99e4ee2021-04-28 19:57:12 +02002263 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_priority_cmd);
Alexander Couzensc4704762021-02-08 23:13:12 +01002264 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_ip_sns_weight_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002265 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_ipaccess_cmd);
2266 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_ipaccess_cmd);
2267 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_fr_cmd);
2268 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_fr_cmd);
Harald Welte42e36462021-03-03 18:12:09 +01002269 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_accept_sns_cmd);
2270 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_accept_sns_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002271
Alexander Couzens260cd522021-01-28 20:31:31 +01002272 install_node(&ns_nse_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002273 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_fr_cmd);
2274 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvci_cmd);
2275 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_fr_dlci_cmd);
2276 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_udp_cmd);
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01002277 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_udp_weights_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002278 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_udp_cmd);
2279 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_ipa_cmd);
2280 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_ipa_cmd);
Alexander Couzens5fa431c2021-02-08 23:21:54 +01002281 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_remote_cmd);
2282 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_remote_cmd);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002283 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_bind_cmd);
2284 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_bind_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002285
2286 return 0;
2287}