blob: 52ce2073683aaa301211a48c869ddee2592d90a8 [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 Couzens1f3193d2021-06-05 22:08:11 +0200104 {10, "tsns-procedures-retries" },
Alexander Couzens6a161492020-07-12 13:45:50 +0200105 { 0, NULL }
106};
107
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100108const struct value_string vty_fr_role_names[] = {
109 { FR_ROLE_USER_EQUIPMENT, "fr" },
110 { FR_ROLE_NETWORK_EQUIPMENT, "frnet" },
111 { 0, NULL }
112};
113
114const struct value_string vty_ll_names[] = {
115 { GPRS_NS2_LL_FR, "fr" },
116 { GPRS_NS2_LL_FR_GRE, "frgre" },
117 { GPRS_NS2_LL_UDP, "udp" },
118 { 0, NULL }
119};
120
121static struct vty_bind *vty_bind_by_name(const char *name)
Daniel Willmann751977b2020-12-02 18:59:44 +0100122{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100123 struct vty_bind *vbind;
124 llist_for_each_entry(vbind, &binds, list) {
Alexander Couzensb7921732021-02-12 03:08:42 +0100125 if (!strcmp(vbind->name, name))
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100126 return vbind;
Daniel Willmann751977b2020-12-02 18:59:44 +0100127 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100128 return NULL;
Daniel Willmann751977b2020-12-02 18:59:44 +0100129}
130
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100131static struct vty_bind *vty_bind_alloc(const char *name)
Alexander Couzens6a161492020-07-12 13:45:50 +0200132{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100133 struct vty_bind *vbind = talloc_zero(vty_nsi, struct vty_bind);
134 if (!vbind)
135 return NULL;
136
137 vbind->name = talloc_strdup(vty_nsi, name);
138 if (!vbind->name) {
139 talloc_free(vbind);
140 return NULL;
Alexander Couzens6a161492020-07-12 13:45:50 +0200141 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100142
Alexander Couzensc4704762021-02-08 23:13:12 +0100143 vbind->ip_sns_sig_weight = 1;
144 vbind->ip_sns_data_weight = 1;
Alexander Couzensd5cd8c62021-06-15 20:59:03 +0200145 llist_add_tail(&vbind->list, &binds);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100146 return vbind;
147}
148
149static void vty_bind_free(struct vty_bind *vbind)
150{
151 if (!vbind)
152 return;
153
154 llist_del(&vbind->list);
Alexander Couzens3e2e4a02021-02-09 16:15:06 +0100155 talloc_free(vbind);
Alexander Couzens6a161492020-07-12 13:45:50 +0200156}
157
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100158static struct vty_nse *vty_nse_by_nsei(uint16_t nsei)
159{
160 struct vty_nse *vnse;
161 llist_for_each_entry(vnse, &nses, list) {
162 if (vnse->nsei == nsei)
163 return vnse;
164 }
165 return NULL;
166}
167
168static struct vty_nse *vty_nse_alloc(uint16_t nsei)
169{
170 struct vty_nse *vnse = talloc_zero(vty_nsi, struct vty_nse);
171 if (!vnse)
172 return NULL;
173
174 vnse->nsei = nsei;
175 INIT_LLIST_HEAD(&vnse->binds);
Alexander Couzensd5cd8c62021-06-15 20:59:03 +0200176 llist_add_tail(&vnse->list, &nses);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100177 return vnse;
178}
179
180static void vty_nse_free(struct vty_nse *vnse)
181{
182 if (!vnse)
183 return;
184
185 llist_del(&vnse->list);
186 /* all vbind of the nse will be freed by talloc */
187 talloc_free(vnse);
188}
189
190static int vty_nse_add_vbind(struct vty_nse *vnse, struct vty_bind *vbind)
191{
192 struct vty_nse_bind *vnse_bind;
193
194 if (vbind->ll != GPRS_NS2_LL_UDP)
195 return -EINVAL;
196
197 llist_for_each_entry(vnse_bind, &vnse->binds, list) {
198 if (vnse_bind->vbind == vbind)
199 return -EALREADY;
200 }
201
202 vnse_bind = talloc(vnse, struct vty_nse_bind);
203 if (!vnse_bind)
204 return -ENOMEM;
205 vnse_bind->vbind = vbind;
206
207 llist_add_tail(&vnse_bind->list, &vnse->binds);
208 return 0;
209}
210
211static int vty_nse_remove_vbind(struct vty_nse *vnse, struct vty_bind *vbind)
212{
213 struct vty_nse_bind *vnse_bind, *tmp;
214 if (vbind->ll != GPRS_NS2_LL_UDP)
215 return -EINVAL;
216
217 llist_for_each_entry_safe(vnse_bind, tmp, &vnse->binds, list) {
218 if (vnse_bind->vbind == vbind) {
219 llist_del(&vnse_bind->list);
220 talloc_free(vnse_bind);
Alexander Couzens15596892021-04-19 03:31:05 +0200221 return 0;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100222 }
223 }
224
225 return -ENOENT;
226}
227
228/* check if the NSE still has SNS configuration */
229static bool vty_nse_check_sns(struct gprs_ns2_nse *nse) {
230 struct vty_nse *vnse = vty_nse_by_nsei(nse->nsei);
231
232 int count = gprs_ns2_sns_count(nse);
233 if (count > 0) {
234 /* there are other sns endpoints */
235 return true;
236 }
237
238 if (!vnse)
239 return false;
240
241 if (llist_empty(&vnse->binds))
242 return false;
243
244 return true;
245}
246
Alexander Couzens6a161492020-07-12 13:45:50 +0200247static struct cmd_node ns_node = {
248 L_NS_NODE,
249 "%s(config-ns)# ",
250 1,
251};
252
Alexander Couzens6a161492020-07-12 13:45:50 +0200253DEFUN(cfg_ns, cfg_ns_cmd,
254 "ns",
255 "Configure the GPRS Network Service")
256{
257 vty->node = L_NS_NODE;
258 return CMD_SUCCESS;
259}
260
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100261DEFUN(cfg_ns_timer, cfg_ns_timer_cmd,
262 "timer " NS_TIMERS " <0-65535>",
263 "Network Service Timer\n"
264 NS_TIMERS_HELP "Timer Value\n")
265{
266 int idx = get_string_value(gprs_ns_timer_strs, argv[0]);
267 int val = atoi(argv[1]);
268
269 if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout))
270 return CMD_WARNING;
271
272 vty_nsi->timeout[idx] = val;
273
274 return CMD_SUCCESS;
275}
276
277DEFUN(cfg_ns_nsei, cfg_ns_nsei_cmd,
Harald Welte579699b2021-03-05 10:22:23 +0100278 "nse <0-65535> [ip-sns-role-sgsn]",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100279 "Persistent NS Entity\n"
280 "NS Entity ID (NSEI)\n"
Harald Welte579699b2021-03-05 10:22:23 +0100281 "Create NSE in SGSN role (default: BSS)\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100282 )
283{
284 struct gprs_ns2_nse *nse;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100285 struct vty_nse *vnse;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100286 uint16_t nsei = atoi(argv[0]);
Harald Welte579699b2021-03-05 10:22:23 +0100287 bool sgsn_role = false;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100288 bool free_vnse = false;
Harald Welte579699b2021-03-05 10:22:23 +0100289 if (argc > 1 && !strcmp(argv[1], "ip-sns-role-sgsn"))
290 sgsn_role = true;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100291
292 vnse = vty_nse_by_nsei(nsei);
293 if (!vnse) {
294 vnse = vty_nse_alloc(nsei);
295 if (!vnse) {
296 vty_out(vty, "Failed to create vty NSE!%s", VTY_NEWLINE);
297 return CMD_ERR_INCOMPLETE;
298 }
299 free_vnse = true;
300 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100301
302 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
303 if (!nse) {
Harald Welte579699b2021-03-05 10:22:23 +0100304 nse = gprs_ns2_create_nse2(vty_nsi, nsei, GPRS_NS2_LL_UNDEF, GPRS_NS2_DIALECT_UNDEF,
305 sgsn_role);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100306 if (!nse) {
307 vty_out(vty, "Failed to create NSE!%s", VTY_NEWLINE);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100308 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100309 }
310 nse->persistent = true;
311 }
312
313 if (!nse->persistent) {
314 /* TODO: should the dynamic NSE removed? */
315 vty_out(vty, "A dynamic NSE with the specified NSEI already exists%s", VTY_NEWLINE);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100316 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100317 }
318
319 vty->node = L_NS_NSE_NODE;
320 vty->index = nse;
321
322 return CMD_SUCCESS;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100323
324err:
325 if (free_vnse)
326 talloc_free(vnse);
327
328 return CMD_ERR_INCOMPLETE;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100329}
330
331DEFUN(cfg_no_ns_nsei, cfg_no_ns_nsei_cmd,
332 "no nse <0-65535>",
333 NO_STR
334 "Delete a Persistent NS Entity\n"
335 "NS Entity ID (NSEI)\n"
336 )
337{
338 struct gprs_ns2_nse *nse;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100339 struct vty_nse *vnse;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100340 uint16_t nsei = atoi(argv[0]);
341
342 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
343 if (!nse) {
344 vty_out(vty, "Can not find NS Entity %s%s", argv[0], VTY_NEWLINE);
345 return CMD_ERR_NOTHING_TODO;
346 }
347
348 if (!nse->persistent) {
349 vty_out(vty, "Ignoring non-persistent NS Entity%s", VTY_NEWLINE);
350 return CMD_WARNING;
351 }
352
353 vty_out(vty, "Deleting NS Entity %u%s", nse->nsei, VTY_NEWLINE);
354 gprs_ns2_free_nse(nse);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100355
356 vnse = vty_nse_by_nsei(nsei);
357 vty_nse_free(vnse);
358
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100359 return CMD_SUCCESS;
360}
361
362/* TODO: add fr/gre */
363DEFUN(cfg_ns_bind, cfg_ns_bind_cmd,
364 "bind (fr|udp) ID",
Harald Welte2230a912021-03-04 20:09:50 +0100365 "Configure local Bind\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100366 "Frame Relay\n" "UDP/IP\n"
Harald Welte2230a912021-03-04 20:09:50 +0100367 "Unique identifier for this bind (to reference from NS-VCs, NSEs, ...)\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100368 )
369{
370 const char *nstype = argv[0];
371 const char *name = argv[1];
372 struct vty_bind *vbind;
373 enum gprs_ns2_ll ll;
374 int rc;
375
376 rc = get_string_value(vty_ll_names, nstype);
377 if (rc < 0)
378 return CMD_WARNING;
379 ll = (enum gprs_ns2_ll) rc;
380
381 if (!osmo_identifier_valid(name)) {
382 vty_out(vty, "Invalid ID. The ID should be only alphanumeric.%s", VTY_NEWLINE);
383 return CMD_WARNING;
384 }
385
386 vbind = vty_bind_by_name(name);
387 if (vbind) {
388 if (vbind->ll != ll) {
389 vty_out(vty, "A bind with the specified ID already exists with a different type (fr|frgre|udp)!%s",
390 VTY_NEWLINE);
391 return CMD_WARNING;
392 }
393 } else {
394 vbind = vty_bind_alloc(name);
395 if (!vbind) {
396 vty_out(vty, "Can not create bind - out of memory%s", VTY_NEWLINE);
397 return CMD_WARNING;
398 }
399 vbind->ll = ll;
400 }
401
402 vty->index = vbind;
403 vty->node = L_NS_BIND_NODE;
404
405 return CMD_SUCCESS;
406}
407
408DEFUN(cfg_no_ns_bind, cfg_no_ns_bind_cmd,
409 "no bind ID",
410 NO_STR
Harald Welte2230a912021-03-04 20:09:50 +0100411 "Delete a bind\n"
412 "Unique identifier for this bind\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100413 )
414{
415 struct vty_bind *vbind;
416 struct gprs_ns2_vc_bind *bind;
417 const char *name = argv[0];
418
419 vbind = vty_bind_by_name(name);
420 if (!vbind) {
421 vty_out(vty, "bind %s does not exist!%s", name, VTY_NEWLINE);
422 return CMD_WARNING;
423 }
424 vty_bind_free(vbind);
425 bind = gprs_ns2_bind_by_name(vty_nsi, name);
426 if (bind)
Alexander Couzens56287d22021-07-06 10:56:55 +0200427 gprs_ns2_free_bind(bind);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100428 return CMD_SUCCESS;
429}
430
431
432static void config_write_vbind(struct vty *vty, struct vty_bind *vbind)
433{
434 struct gprs_ns2_vc_bind *bind;
435 const struct osmo_sockaddr *addr;
436 struct osmo_sockaddr_str addr_str;
437 const char *netif, *frrole_str, *llstr;
438 enum osmo_fr_role frrole;
439
440 llstr = get_value_string_or_null(vty_ll_names, vbind->ll);
441 if (!llstr)
442 return;
443 vty_out(vty, " bind %s %s%s", llstr, vbind->name, VTY_NEWLINE);
444
445 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
446 switch (vbind->ll) {
447 case GPRS_NS2_LL_FR:
448 if (bind) {
449 netif = gprs_ns2_fr_bind_netif(bind);
450 if (!netif)
451 return;
452 frrole = gprs_ns2_fr_bind_role(bind);
453 if ((int) frrole == -1)
454 return;
455 frrole_str = get_value_string_or_null(vty_fr_role_names, frrole);
456 if (netif && frrole_str)
457 vty_out(vty, " fr %s %s%s", netif, frrole_str, VTY_NEWLINE);
458 }
459 break;
460 case GPRS_NS2_LL_UDP:
461 if (bind) {
462 addr = gprs_ns2_ip_bind_sockaddr(bind);
463 if (!osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas)) {
464 vty_out(vty, " listen %s %u%s", addr_str.ip, addr_str.port,
465 VTY_NEWLINE);
466 }
467 }
468 if (vbind->accept_ipaccess)
469 vty_out(vty, " accept-ipaccess%s", VTY_NEWLINE);
Harald Welte42e36462021-03-03 18:12:09 +0100470 if (vbind->accept_sns)
471 vty_out(vty, " accept-dynamic-ip-sns%s", VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100472 if (vbind->dscp)
473 vty_out(vty, " dscp %u%s", vbind->dscp, VTY_NEWLINE);
Harald Welted99e4ee2021-04-28 19:57:12 +0200474 if (vbind->priority)
Harald Welte5782fec2021-04-29 21:28:53 +0200475 vty_out(vty, " socket-priority %u%s", vbind->priority, VTY_NEWLINE);
Daniel Willmann64db6362021-02-12 12:21:45 +0100476 vty_out(vty, " ip-sns signalling-weight %u data-weight %u%s",
Alexander Couzensc4704762021-02-08 23:13:12 +0100477 vbind->ip_sns_sig_weight, vbind->ip_sns_data_weight, VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100478 break;
479 default:
480 return;
481 }
482}
483
484static void config_write_nsvc(struct vty *vty, const struct gprs_ns2_vc *nsvc)
485{
486 const char *netif;
487 uint16_t dlci;
488 const struct osmo_sockaddr *addr;
489 struct osmo_sockaddr_str addr_str;
490
491 switch (nsvc->nse->ll) {
492 case GPRS_NS2_LL_UNDEF:
493 break;
494 case GPRS_NS2_LL_UDP:
495 switch (nsvc->nse->dialect) {
496 case GPRS_NS2_DIALECT_IPACCESS:
497 addr = gprs_ns2_ip_vc_remote(nsvc);
498 if (!addr)
499 break;
500 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas))
501 break;
502 vty_out(vty, " nsvc ipa %s %s %u nsvci %u%s",
503 nsvc->bind->name, addr_str.ip, addr_str.port,
504 nsvc->nsvci, VTY_NEWLINE);
505 break;
506 case GPRS_NS2_DIALECT_STATIC_ALIVE:
507 addr = gprs_ns2_ip_vc_remote(nsvc);
508 if (!addr)
509 break;
510 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas))
511 break;
512 vty_out(vty, " nsvc udp %s %s %u%s",
513 nsvc->bind->name, addr_str.ip, addr_str.port, VTY_NEWLINE);
514 break;
515 default:
516 break;
517 }
518 break;
519 case GPRS_NS2_LL_FR:
520 netif = gprs_ns2_fr_bind_netif(nsvc->bind);
521 if (!netif)
522 break;
523 dlci = gprs_ns2_fr_nsvc_dlci(nsvc);
524 if (!dlci)
525 break;
526 OSMO_ASSERT(nsvc->nsvci_is_valid);
527 vty_out(vty, " nsvc fr %s dlci %u nsvci %u%s",
528 netif, dlci, nsvc->nsvci, VTY_NEWLINE);
529 break;
530 case GPRS_NS2_LL_FR_GRE:
531 break;
532 }
533}
534
535static void _config_write_ns_nse(struct vty *vty, struct gprs_ns2_nse *nse)
536{
537 struct gprs_ns2_vc *nsvc;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100538 struct vty_nse *vnse = vty_nse_by_nsei(nse->nsei);
539 struct vty_nse_bind *vbind;
540
541 OSMO_ASSERT(vnse);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100542
Harald Welte579699b2021-03-05 10:22:23 +0100543 vty_out(vty, " nse %u%s%s", nse->nsei,
544 nse->ip_sns_role_sgsn ? " ip-sns-role-sgsn" : "", VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100545 switch (nse->dialect) {
546 case GPRS_NS2_DIALECT_SNS:
547 ns2_sns_write_vty(vty, nse);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100548 llist_for_each_entry(vbind, &vnse->binds, list) {
549 vty_out(vty, " ip-sns-bind %s%s", vbind->vbind->name, VTY_NEWLINE);
550 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100551 break;
552 default:
553 llist_for_each_entry(nsvc, &nse->nsvc, list) {
554 config_write_nsvc(vty, nsvc);
555 }
556 break;
557 }
558}
559
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100560static int config_write_ns_nse(struct vty *vty)
561{
562 struct gprs_ns2_nse *nse;
563
564 llist_for_each_entry(nse, &vty_nsi->nse, list) {
565 if (!nse->persistent)
566 continue;
567
568 _config_write_ns_nse(vty, nse);
569 }
570
571 return 0;
572}
573
574static int config_write_ns_bind(struct vty *vty)
575{
576 struct vty_bind *vbind;
577
578 llist_for_each_entry(vbind, &binds, list) {
579 config_write_vbind(vty, vbind);
580 }
581
582 return 0;
583}
584
Alexander Couzens260cd522021-01-28 20:31:31 +0100585static int config_write_ns(struct vty *vty)
586{
Harald Welted164ef82021-03-04 22:29:17 +0100587 struct vty_nse_bind *vbind;
Alexander Couzens260cd522021-01-28 20:31:31 +0100588 unsigned int i;
589 int ret;
590
591 vty_out(vty, "ns%s", VTY_NEWLINE);
592
593 for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++)
594 vty_out(vty, " timer %s %u%s",
595 get_value_string(gprs_ns_timer_strs, i),
596 vty_nsi->timeout[i], VTY_NEWLINE);
597
598 ret = config_write_ns_bind(vty);
599 if (ret)
600 return ret;
601
Harald Welted164ef82021-03-04 22:29:17 +0100602 llist_for_each_entry(vbind, &ip_sns_default_binds, list) {
603 vty_out(vty, " ip-sns-default bind %s%s", vbind->vbind->name, VTY_NEWLINE);
604 }
605
Alexander Couzens260cd522021-01-28 20:31:31 +0100606 ret = config_write_ns_nse(vty);
607 if (ret)
608 return ret;
609
610 return 0;
611}
612
613
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100614static struct cmd_node ns_bind_node = {
615 L_NS_BIND_NODE,
616 "%s(config-ns-bind)# ",
617 1,
618};
619
620DEFUN(cfg_ns_bind_listen, cfg_ns_bind_listen_cmd,
621 "listen " VTY_IPV46_CMD " <1-65535>",
Harald Welte2230a912021-03-04 20:09:50 +0100622 "Configure local IP + Port of this bind\n"
623 "Local IPv4 Address\n" "Local IPv6 Address\n"
624 "Local UDP Port\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100625 )
626{
627 struct vty_bind *vbind = vty->index;
628 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100629 int rc;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100630 const char *addr_str = argv[0];
631 unsigned int port = atoi(argv[1]);
632 struct osmo_sockaddr_str sockaddr_str;
633 struct osmo_sockaddr sockaddr;
634
635 if (vbind->ll != GPRS_NS2_LL_UDP) {
636 vty_out(vty, "listen can be only used with UDP bind%s",
637 VTY_NEWLINE);
638 return CMD_WARNING;
639 }
640
641 if (osmo_sockaddr_str_from_str(&sockaddr_str, addr_str, port)) {
642 vty_out(vty, "Can not parse the Address %s %s%s", argv[0], argv[1], VTY_NEWLINE);
643 return CMD_WARNING;
644 }
645 osmo_sockaddr_str_to_sockaddr(&sockaddr_str, &sockaddr.u.sas);
646 if (gprs_ns2_ip_bind_by_sockaddr(vty_nsi, &sockaddr)) {
647 vty_out(vty, "A bind with the specified address already exists!%s", VTY_NEWLINE);
648 return CMD_WARNING;
649 }
650
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100651 rc = gprs_ns2_ip_bind(vty_nsi, vbind->name, &sockaddr, vbind->dscp, &bind);
652 if (rc != 0) {
653 vty_out(vty, "Failed to create the bind (rc %d)!%s", rc, VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100654 return CMD_WARNING;
655 }
656
657 bind->accept_ipaccess = vbind->accept_ipaccess;
658 bind->accept_sns = vbind->accept_sns;
659
660 return CMD_SUCCESS;
661}
662
663DEFUN(cfg_no_ns_bind_listen, cfg_no_ns_bind_listen_cmd,
664 "no listen",
665 NO_STR
666 "Delete a IP/Port assignment\n"
667 )
668{
669 struct vty_bind *vbind = vty->index;
670 struct gprs_ns2_vc_bind *bind;
671
672 if (vbind->ll != GPRS_NS2_LL_UDP) {
673 vty_out(vty, "no listen can be only used with UDP bind%s", VTY_NEWLINE);
674 return CMD_WARNING;
675 }
676
677 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
678 if (!bind)
679 return CMD_ERR_NOTHING_TODO;
680
Daniel Willmann90432052021-01-26 16:09:18 +0100681 OSMO_ASSERT(bind->ll == GPRS_NS2_LL_UDP);
Alexander Couzens56287d22021-07-06 10:56:55 +0200682 gprs_ns2_free_bind(bind);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100683 return CMD_SUCCESS;
684}
685
686DEFUN(cfg_ns_bind_dscp, cfg_ns_bind_dscp_cmd,
Harald Weltec96d7162021-04-27 21:56:25 +0200687 "dscp <0-63>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100688 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
689{
690 struct vty_bind *vbind = vty->index;
691 struct gprs_ns2_vc_bind *bind;
692 uint16_t dscp = atoi(argv[0]);
693
694 if (vbind->ll != GPRS_NS2_LL_UDP) {
695 vty_out(vty, "dscp can be only used with UDP bind%s",
696 VTY_NEWLINE);
697 return CMD_WARNING;
698 }
699
700 vbind->dscp = dscp;
701 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
702 if (bind)
703 gprs_ns2_ip_bind_set_dscp(bind, dscp);
704
705 return CMD_SUCCESS;
706}
707
708DEFUN(cfg_no_ns_bind_dscp, cfg_no_ns_bind_dscp_cmd,
709 "no dscp",
710 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
711{
712 struct vty_bind *vbind = vty->index;
713 struct gprs_ns2_vc_bind *bind;
714 uint16_t dscp = 0;
715
716 if (vbind->ll != GPRS_NS2_LL_UDP) {
717 vty_out(vty, "dscp can be only used with UDP bind%s",
718 VTY_NEWLINE);
719 return CMD_WARNING;
720 }
721
722 vbind->dscp = dscp;
723 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
724 if (bind)
725 gprs_ns2_ip_bind_set_dscp(bind, dscp);
726
727 return CMD_SUCCESS;
728}
729
Harald Welted99e4ee2021-04-28 19:57:12 +0200730DEFUN(cfg_ns_bind_priority, cfg_ns_bind_priority_cmd,
Harald Welte5782fec2021-04-29 21:28:53 +0200731 "socket-priority <0-255>",
Harald Welted99e4ee2021-04-28 19:57:12 +0200732 "Set socket priority on the UDP socket\n" "Priority Value (>6 requires CAP_NET_ADMIN)\n")
733{
734 struct vty_bind *vbind = vty->index;
735 struct gprs_ns2_vc_bind *bind;
736 uint8_t prio = atoi(argv[0]);
737
738 if (vbind->ll != GPRS_NS2_LL_UDP) {
739 vty_out(vty, "dscp can be only used with UDP bind%s",
740 VTY_NEWLINE);
741 return CMD_WARNING;
742 }
743
744 vbind->priority = prio;
745 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
746 if (bind)
747 gprs_ns2_ip_bind_set_priority(bind, prio);
748
749 return CMD_SUCCESS;
750}
751
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100752DEFUN(cfg_ns_bind_ipaccess, cfg_ns_bind_ipaccess_cmd,
753 "accept-ipaccess",
754 "Allow to create dynamic NS Entity by NS Reset PDU on UDP (ip.access style)\n"
755 )
756{
757 struct vty_bind *vbind = vty->index;
758 struct gprs_ns2_vc_bind *bind;
759
760 if (vbind->ll != GPRS_NS2_LL_UDP) {
761 vty_out(vty, "accept-ipaccess can be only used with UDP bind%s",
762 VTY_NEWLINE);
763 return CMD_WARNING;
764 }
765
766 vbind->accept_ipaccess = true;
767 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
768 if (bind)
769 bind->accept_ipaccess = true;
770
771 return CMD_SUCCESS;
772}
773
774DEFUN(cfg_no_ns_bind_ipaccess, cfg_no_ns_bind_ipaccess_cmd,
775 "no accept-ipaccess",
776 NO_STR
777 "Reject NS Reset PDU on UDP (ip.access style)\n"
778 )
779{
780 struct vty_bind *vbind = vty->index;
781 struct gprs_ns2_vc_bind *bind;
782
783 if (vbind->ll != GPRS_NS2_LL_UDP) {
784 vty_out(vty, "no accept-ipaccess can be only used with UDP bind%s",
785 VTY_NEWLINE);
786 return CMD_WARNING;
787 }
788
789 vbind->accept_ipaccess = false;
790 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
791 if (bind)
792 bind->accept_ipaccess = false;
793
794 return CMD_SUCCESS;
795}
796
Harald Welte42e36462021-03-03 18:12:09 +0100797DEFUN(cfg_ns_bind_accept_sns, cfg_ns_bind_accept_sns_cmd,
798 "accept-dynamic-ip-sns",
799 "Allow to create dynamic NS Entities by IP-SNS PDUs\n"
800 )
801{
802 struct vty_bind *vbind = vty->index;
803 struct gprs_ns2_vc_bind *bind;
804
805 if (vbind->ll != GPRS_NS2_LL_UDP) {
806 vty_out(vty, "accept-dynamic-ip-sns can be only used with UDP bind%s",
807 VTY_NEWLINE);
808 return CMD_WARNING;
809 }
810
811 vbind->accept_sns = true;
812 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
813 if (bind)
814 bind->accept_sns = true;
815
816 return CMD_SUCCESS;
817}
818
819DEFUN(cfg_no_ns_bind_accept_sns, cfg_no_ns_bind_accept_sns_cmd,
820 "no accept-dynamic-ip-sns",
821 NO_STR
822 "Disable dynamic creation of NS Entities by IP-SNS PDUs\n"
823 )
824{
825 struct vty_bind *vbind = vty->index;
826 struct gprs_ns2_vc_bind *bind;
827
828 if (vbind->ll != GPRS_NS2_LL_UDP) {
829 vty_out(vty, "no accept-dynamic-ip-sns can be only used with UDP bind%s",
830 VTY_NEWLINE);
831 return CMD_WARNING;
832 }
833
834 vbind->accept_sns = false;
835 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
836 if (bind)
837 bind->accept_sns = false;
838
839 return CMD_SUCCESS;
840}
841
Alexander Couzensc4704762021-02-08 23:13:12 +0100842DEFUN(cfg_ns_bind_ip_sns_weight, cfg_ns_bind_ip_sns_weight_cmd,
843 "ip-sns signalling-weight <0-254> data-weight <0-254>",
844 "IP SNS\n"
845 "signalling weight used by IP-SNS dynamic configuration\n"
846 "signalling weight used by IP-SNS dynamic configuration\n"
847 "data weight used by IP-SNS dynamic configuration\n"
848 "data weight used by IP-SNS dynamic configuration\n")
849{
850 struct vty_bind *vbind = vty->index;
851 struct gprs_ns2_vc_bind *bind;
852
853 int signalling = atoi(argv[0]);
854 int data = atoi(argv[1]);
855
856 if (vbind->ll != GPRS_NS2_LL_UDP) {
857 vty_out(vty, "ip-sns signalling-weight <0-254> data-weight <0-254> can be only used with UDP bind%s",
858 VTY_NEWLINE);
859 return CMD_WARNING;
860 }
861
862 vbind->ip_sns_data_weight = data;
863 vbind->ip_sns_sig_weight = signalling;
864 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
865 if (bind)
866 gprs_ns2_ip_bind_set_sns_weight(bind, signalling, data);
867
868 return CMD_SUCCESS;
869}
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100870
871DEFUN(cfg_ns_bind_fr, cfg_ns_bind_fr_cmd,
872 "fr NETIF (fr|frnet)",
873 "frame relay\n"
874 IFNAME_STR
875 "fr (user) is used by BSS or SGSN attached to UNI of a FR network\n"
876 "frnet (network) is used by SGSN if BSS is directly attached\n"
877 )
878{
879 struct vty_bind *vbind = vty->index;
880 struct gprs_ns2_vc_bind *bind;
881 const char *netif = argv[0];
882 const char *role = argv[1];
883
884 int rc = 0;
885 enum osmo_fr_role frrole;
886
887 if (vbind->ll != GPRS_NS2_LL_FR) {
888 vty_out(vty, "fr can be only used with frame relay bind%s", VTY_NEWLINE);
889 return CMD_WARNING;
890 }
891
892 if (!strcmp(role, "fr"))
893 frrole = FR_ROLE_USER_EQUIPMENT;
894 else if (!strcmp(role, "frnet"))
895 frrole = FR_ROLE_NETWORK_EQUIPMENT;
896 else
897 return CMD_WARNING;
898
899 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
900 if (bind) {
901 vty_out(vty, "Interface %s already used.%s", netif, VTY_NEWLINE);
902 return CMD_WARNING;
903 }
904
905 rc = gprs_ns2_fr_bind(vty_nsi, vbind->name, netif, vty_fr_network, frrole, &bind);
906 if (rc < 0) {
907 LOGP(DLNS, LOGL_ERROR, "Failed to bind interface %s on fr. Err: %d\n", netif, rc);
908 return CMD_WARNING;
909 }
910
911 return CMD_SUCCESS;
912}
913
914DEFUN(cfg_no_ns_bind_fr, cfg_no_ns_bind_fr_cmd,
915 "no fr NETIF",
916 NO_STR
917 "Delete a frame relay link\n"
918 "Delete a frame relay link\n"
919 IFNAME_STR
920 )
921{
922 struct vty_bind *vbind = vty->index;
923 struct gprs_ns2_vc_bind *bind;
924 const char *netif = argv[0];
925
926 if (vbind->ll != GPRS_NS2_LL_FR) {
927 vty_out(vty, "fr can be only used with frame relay bind%s",
928 VTY_NEWLINE);
929 return CMD_WARNING;
930 }
931
932 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
933 if (!bind) {
934 vty_out(vty, "Interface not found.%s", VTY_NEWLINE);
935 return CMD_WARNING;
936 }
937
938 if (strcmp(bind->name, vbind->name)) {
939 vty_out(vty, "The specified interface is not bound to this bind.%s", VTY_NEWLINE);
940 return CMD_WARNING;
941 }
942
Alexander Couzens56287d22021-07-06 10:56:55 +0200943 gprs_ns2_free_bind(bind);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100944 return CMD_SUCCESS;
945}
946
947
948static struct cmd_node ns_nse_node = {
949 L_NS_NSE_NODE,
950 "%s(config-ns-nse)# ",
951 1,
952};
953
954DEFUN(cfg_ns_nse_nsvc_fr, cfg_ns_nse_nsvc_fr_cmd,
955 "nsvc fr NETIF dlci <16-1007> nsvci <0-65535>",
956 "NS Virtual Connection\n"
957 "frame relay\n"
958 "frame relay interface. Must be registered via fr vty\n"
959 NSVCI_STR
960 NSVCI_STR
961 DLCI_STR
962 DLCI_STR
963 )
964{
965 struct gprs_ns2_vc_bind *bind;
966 struct gprs_ns2_vc *nsvc;
967 struct gprs_ns2_nse *nse = vty->index;
968 const char *netif = argv[0];
969 uint16_t dlci = atoi(argv[1]);
970 uint16_t nsvci = atoi(argv[2]);
971 bool dialect_modified = false;
972 bool ll_modified = false;
973
974 if (nse->ll != GPRS_NS2_LL_FR && nse->ll != GPRS_NS2_LL_UNDEF) {
975 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
976 goto err;
977 }
978
979 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_RESETBLOCK && nse->dialect != GPRS_NS2_DIALECT_UNDEF) {
980 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
981 goto err;
982 }
983
984 if (nse->ll == GPRS_NS2_LL_UNDEF) {
985 nse->ll = GPRS_NS2_LL_FR;
986 ll_modified = true;
987 }
988
989 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +0100990 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_STATIC_RESETBLOCK);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100991 dialect_modified = true;
992 }
993
994
995 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
996 if (!bind) {
997 vty_out(vty, "Can not find fr interface \"%s\". Please configure it via fr vty.%s",
998 netif, VTY_NEWLINE);
999 goto err;
1000 }
1001
1002 if (gprs_ns2_fr_nsvc_by_dlci(bind, dlci)) {
1003 vty_out(vty, "A NS-VC with the specified DLCI already exist!%s", VTY_NEWLINE);
1004 goto err;
1005 }
1006
1007 if (gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci)) {
1008 vty_out(vty, "A NS-VC with the specified NS-VCI already exist!%s", VTY_NEWLINE);
1009 goto err;
1010 }
1011
1012 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
1013 if (!nsvc) {
1014 /* Could not create NS-VC, connect failed */
1015 vty_out(vty, "Failed to create the NS-VC%s", VTY_NEWLINE);
1016 goto err;
1017 }
1018 nsvc->persistent = true;
1019 return CMD_SUCCESS;
1020
1021err:
1022 if (ll_modified)
1023 nse->ll = GPRS_NS2_LL_UNDEF;
1024 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001025 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001026
1027 return CMD_WARNING;
1028}
1029
1030DEFUN(cfg_no_ns_nse_nsvc_fr_dlci, cfg_no_ns_nse_nsvc_fr_dlci_cmd,
1031 "no nsvc fr NETIF dlci <16-1007>",
1032 NO_STR
1033 "Delete frame relay NS-VC\n"
1034 "frame relay\n"
1035 "frame relay interface. Must be registered via fr vty\n"
1036 DLCI_STR
1037 DLCI_STR
1038 )
1039{
1040 struct gprs_ns2_vc_bind *bind;
1041 struct gprs_ns2_vc *nsvc;
1042 struct gprs_ns2_nse *nse = vty->index;
1043 const char *netif = argv[0];
1044 uint16_t dlci = atoi(argv[1]);
1045
1046 if (nse->ll != GPRS_NS2_LL_FR) {
1047 vty_out(vty, "This NSE doesn't support frame relay.%s", VTY_NEWLINE);
1048 return CMD_WARNING;
1049 }
1050
1051 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
1052 if (!bind) {
1053 vty_out(vty, "Can not find fr interface \"%s\"%s",
1054 netif, VTY_NEWLINE);
1055 return CMD_ERR_NOTHING_TODO;
1056 }
1057
1058 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
1059 if (!nsvc) {
1060 vty_out(vty, "Can not find a NS-VC on fr interface %s with dlci %u%s",
1061 netif, dlci, VTY_NEWLINE);
1062 return CMD_WARNING;
1063 }
1064
1065 if (nse != nsvc->nse) {
1066 vty_out(vty, "The specified NS-VC is not a part of the NSE %u!%s"
1067 "To remove this NS-VC go to the vty node 'nse %u'%s",
1068 nse->nsei, VTY_NEWLINE,
1069 nsvc->nse->nsei, VTY_NEWLINE);
1070 return CMD_WARNING;
1071 }
1072
1073 gprs_ns2_free_nsvc(nsvc);
1074 if (llist_empty(&nse->nsvc)) {
1075 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001076 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001077 }
1078
1079 return CMD_SUCCESS;
1080}
1081
1082DEFUN(cfg_no_ns_nse_nsvci, cfg_no_ns_nse_nsvci_cmd,
1083 "no nsvc nsvci <0-65535>",
1084 NO_STR
1085 "Delete NSVC\n"
1086 NSVCI_STR
1087 NSVCI_STR
1088 )
1089{
1090 struct gprs_ns2_vc *nsvc;
1091 struct gprs_ns2_nse *nse = vty->index;
1092 uint16_t nsvci = atoi(argv[0]);
1093
1094 switch (nse->dialect) {
1095 case GPRS_NS2_DIALECT_SNS:
1096 case GPRS_NS2_DIALECT_STATIC_ALIVE:
1097 vty_out(vty, "NSE doesn't support NSVCI.%s", VTY_NEWLINE);
1098 return CMD_WARNING;
1099 case GPRS_NS2_DIALECT_UNDEF:
1100 vty_out(vty, "No NSVCs configured%s", VTY_NEWLINE);
1101 return CMD_WARNING;
1102 case GPRS_NS2_DIALECT_IPACCESS:
1103 case GPRS_NS2_DIALECT_STATIC_RESETBLOCK:
1104 break;
1105 }
1106
1107 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci);
1108 if (!nsvc) {
1109 vty_out(vty, "Can not find NS-VC with NS-VCI %u%s", nsvci, VTY_NEWLINE);
1110 return CMD_WARNING;
1111 }
1112
1113 if (nse != nsvc->nse) {
1114 vty_out(vty, "NS-VC with NS-VCI %u is not part of this NSE!%s",
1115 nsvci, VTY_NEWLINE);
1116 return CMD_WARNING;
1117 }
1118
1119 gprs_ns2_free_nsvc(nsvc);
1120 if (llist_empty(&nse->nsvc)) {
1121 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001122 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001123 }
1124
1125 return CMD_SUCCESS;
1126}
1127
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001128static int ns_nse_nsvc_udp_cmds(struct vty *vty, const char *bind_name, const char *remote_char, uint16_t port,
1129 uint16_t sig_weight, uint16_t data_weight)
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001130{
1131 struct gprs_ns2_vc_bind *bind;
1132 struct gprs_ns2_vc *nsvc;
1133 struct gprs_ns2_nse *nse = vty->index;
1134 bool dialect_modified = false;
1135 bool ll_modified = false;
1136
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001137 struct osmo_sockaddr_str remote_str;
1138 struct osmo_sockaddr remote;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001139
1140 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1141 nse->ll = GPRS_NS2_LL_UDP;
1142 ll_modified = true;
1143 }
1144
1145 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001146 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_STATIC_ALIVE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001147 dialect_modified = true;
1148 }
1149
1150 if (nse->ll != GPRS_NS2_LL_UDP) {
1151 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1152 goto err;
1153 }
1154
1155 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
1156 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1157 goto err;
1158 }
1159
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001160 if (osmo_sockaddr_str_from_str(&remote_str, remote_char, port)) {
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001161 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1162 goto err;
1163 }
1164
1165 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1166 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1167 goto err;
1168 }
1169
1170 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1171 if (!bind) {
1172 vty_out(vty, "Can not find bind with name %s%s",
1173 bind_name, VTY_NEWLINE);
1174 goto err;
1175 }
1176
1177 if (bind->ll != GPRS_NS2_LL_UDP) {
1178 vty_out(vty, "Bind %s is not an UDP bind.%s",
1179 bind_name, VTY_NEWLINE);
1180 goto err;
1181 }
1182
Alexander Couzens7bb39e32021-02-16 23:06:53 +01001183 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1184 if (nsvc) {
1185 if (nsvc->nse == nse)
1186 vty_out(vty, "Specified NSVC is already present in this NSE.%s", VTY_NEWLINE);
1187 else
1188 vty_out(vty, "Specified NSVC is already present in another NSE%05u.%s", nsvc->nse->nsei, VTY_NEWLINE);
1189 goto err;
1190 }
1191
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001192 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, 0);
1193 if (!nsvc) {
1194 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
1195 goto err;
1196 }
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001197 nsvc->sig_weight = sig_weight;
1198 nsvc->data_weight = data_weight;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001199 nsvc->persistent = true;
1200
1201 return CMD_SUCCESS;
1202
1203err:
1204 if (ll_modified)
1205 nse->ll = GPRS_NS2_LL_UNDEF;
1206 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001207 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001208 return CMD_WARNING;
1209}
1210
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001211DEFUN(cfg_ns_nse_nsvc_udp, cfg_ns_nse_nsvc_udp_cmd,
1212 "nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
1213 "NS Virtual Connection\n"
1214 "NS over UDP\n"
1215 "A unique bind identifier created by ns bind\n"
1216 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1217 "Remote UDP Port\n")
1218{
1219 const char *bind_name = argv[0];
1220 const char *remote = argv[1];
1221 uint16_t port = atoi(argv[2]);
1222 uint16_t sig_weight = 1;
1223 uint16_t data_weight = 1;
1224
1225 return ns_nse_nsvc_udp_cmds(vty, bind_name, remote, port, sig_weight, data_weight);
1226}
1227
1228DEFUN(cfg_ns_nse_nsvc_udp_weights, cfg_ns_nse_nsvc_udp_weights_cmd,
1229 "nsvc udp BIND " VTY_IPV46_CMD " <1-65535> signalling-weight <0-254> data-weight <0-254>",
1230 "NS Virtual Connection\n"
1231 "NS over UDP\n"
1232 "A unique bind identifier created by ns bind\n"
1233 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1234 "Remote UDP Port\n"
1235 "Signalling weight of the NSVC (default = 1)\n"
1236 "Signalling weight of the NSVC (default = 1)\n"
1237 "Data weight of the NSVC (default = 1)\n"
1238 "Data weight of the NSVC (default = 1)\n"
1239 )
1240{
1241 const char *bind_name = argv[0];
1242 const char *remote = argv[1];
1243 uint16_t port = atoi(argv[2]);
1244 uint16_t sig_weight = atoi(argv[3]);
1245 uint16_t data_weight = atoi(argv[4]);
1246
1247 return ns_nse_nsvc_udp_cmds(vty, bind_name, remote, port, sig_weight, data_weight);
1248}
1249
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001250DEFUN(cfg_no_ns_nse_nsvc_udp, cfg_no_ns_nse_nsvc_udp_cmd,
1251 "no nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
1252 NO_STR
1253 "Delete a NS Virtual Connection\n"
1254 "NS over UDP\n"
1255 "A unique bind identifier created by ns bind\n"
1256 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1257 "Remote UDP Port\n"
1258 )
1259{
1260 struct gprs_ns2_vc_bind *bind;
1261 struct gprs_ns2_vc *nsvc;
1262 struct gprs_ns2_nse *nse = vty->index;
1263 const char *bind_name = argv[0];
1264 struct osmo_sockaddr_str remote_str;
1265 struct osmo_sockaddr remote;
1266 uint16_t port = atoi(argv[2]);
1267
1268 if (nse->ll != GPRS_NS2_LL_UDP) {
1269 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1270 return CMD_WARNING;
1271 }
1272
1273 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
1274 vty_out(vty, "This NSE doesn't support UDP with dialect static alive.%s", VTY_NEWLINE);
1275 return CMD_WARNING;
1276 }
1277
1278 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1279 if (!bind) {
1280 vty_out(vty, "Can not find bind with name %s%s",
1281 bind_name, VTY_NEWLINE);
1282 return CMD_WARNING;
1283 }
1284
1285 if (bind->ll != GPRS_NS2_LL_UDP) {
1286 vty_out(vty, "Bind %s is not an UDP bind.%s",
1287 bind_name, VTY_NEWLINE);
1288 return CMD_WARNING;
1289 }
1290
1291 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1292 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1293 return CMD_WARNING;
1294 }
1295
1296 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1297 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1298 return CMD_WARNING;
1299 }
1300
1301 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1302 if (!nsvc) {
1303 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1304 remote_str.ip, remote_str.port, VTY_NEWLINE);
1305 return CMD_WARNING;
1306 }
1307
1308 if (!nsvc->persistent) {
1309 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1310 remote_str.ip, remote_str.port, VTY_NEWLINE);
1311 return CMD_WARNING;
1312 }
1313
1314 if (nsvc->nse != nse) {
1315 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1316 return CMD_WARNING;
1317 }
1318
1319 gprs_ns2_free_nsvc(nsvc);
1320 if (llist_empty(&nse->nsvc)) {
1321 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001322 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001323 }
1324
1325 return CMD_SUCCESS;
1326}
1327
1328DEFUN(cfg_ns_nse_nsvc_ipa, cfg_ns_nse_nsvc_ipa_cmd,
1329 "nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>" ,
1330 "NS Virtual Connection\n"
1331 "NS over UDP ip.access style (uses RESET/BLOCK)\n"
1332 "A unique bind identifier created by ns bind\n"
1333 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1334 "Remote UDP Port\n"
1335 NSVCI_STR
1336 NSVCI_STR
1337 )
1338{
1339 struct gprs_ns2_vc_bind *bind;
1340 struct gprs_ns2_vc *nsvc;
1341 struct gprs_ns2_nse *nse = vty->index;
1342 bool dialect_modified = false;
1343 bool ll_modified = false;
1344
1345 const char *bind_name = argv[0];
1346 struct osmo_sockaddr_str remote_str;
1347 struct osmo_sockaddr remote;
1348 uint16_t port = atoi(argv[2]);
1349 uint16_t nsvci = atoi(argv[3]);
1350
1351 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1352 nse->ll = GPRS_NS2_LL_UDP;
1353 ll_modified = true;
1354 }
1355
1356 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001357 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_IPACCESS);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001358 dialect_modified = true;
1359 }
1360
1361 if (nse->ll != GPRS_NS2_LL_UDP) {
1362 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1363 goto err;
1364 }
1365
1366 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1367 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1368 goto err;
1369 }
1370
1371 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1372 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1373 goto err;
1374 }
1375
1376 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1377 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1378 goto err;
1379 }
1380
1381 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1382 if (!bind) {
1383 vty_out(vty, "Can not find bind with name %s%s",
1384 bind_name, VTY_NEWLINE);
1385 goto err;
1386 }
1387
1388 if (bind->ll != GPRS_NS2_LL_UDP) {
1389 vty_out(vty, "Bind %s is not an UDP bind.%s",
1390 bind_name, VTY_NEWLINE);
1391 goto err;
1392 }
1393
1394 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, nsvci);
1395 if (!nsvc) {
1396 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
1397 goto err;
1398 }
1399 nsvc->persistent = true;
1400
1401 return CMD_SUCCESS;
1402
1403err:
1404 if (ll_modified)
1405 nse->ll = GPRS_NS2_LL_UNDEF;
1406 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001407 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001408 return CMD_WARNING;
1409}
1410
1411DEFUN(cfg_no_ns_nse_nsvc_ipa, cfg_no_ns_nse_nsvc_ipa_cmd,
1412 "no nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>",
1413 NO_STR
1414 "Delete a NS Virtual Connection\n"
1415 "NS over UDP\n"
1416 "A unique bind identifier created by ns bind\n"
1417 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1418 "Remote UDP Port\n"
1419 NSVCI_STR
1420 NSVCI_STR
1421 )
1422{
1423 struct gprs_ns2_vc_bind *bind;
1424 struct gprs_ns2_vc *nsvc;
1425 struct gprs_ns2_nse *nse = vty->index;
1426 const char *bind_name = argv[0];
1427 struct osmo_sockaddr_str remote_str;
1428 struct osmo_sockaddr remote;
1429 uint16_t port = atoi(argv[2]);
1430 uint16_t nsvci = atoi(argv[3]);
1431
1432 if (nse->ll != GPRS_NS2_LL_UDP) {
1433 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1434 return CMD_WARNING;
1435 }
1436
1437 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1438 vty_out(vty, "This NSE doesn't support UDP with dialect ipaccess.%s", VTY_NEWLINE);
1439 return CMD_WARNING;
1440 }
1441
1442 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1443 if (!bind) {
1444 vty_out(vty, "Can not find bind with name %s%s",
1445 bind_name, VTY_NEWLINE);
1446 return CMD_WARNING;
1447 }
1448
1449 if (bind->ll != GPRS_NS2_LL_UDP) {
1450 vty_out(vty, "Bind %s is not an UDP bind.%s",
1451 bind_name, VTY_NEWLINE);
1452 return CMD_WARNING;
1453 }
1454
1455 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1456 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1457 return CMD_WARNING;
1458 }
1459
1460 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1461 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1462 return CMD_WARNING;
1463 }
1464
1465 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1466 if (!nsvc) {
1467 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1468 remote_str.ip, remote_str.port, VTY_NEWLINE);
1469 return CMD_WARNING;
1470 }
1471
1472 if (!nsvc->persistent) {
1473 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1474 remote_str.ip, remote_str.port, VTY_NEWLINE);
1475 return CMD_WARNING;
1476 }
1477
1478 if (nsvc->nse != nse) {
1479 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1480 return CMD_WARNING;
1481 }
1482
1483 if (!nsvc->nsvci_is_valid) {
1484 vty_out(vty, "NS-VC doesn't have a nsvci!%s", VTY_NEWLINE);
1485 return CMD_WARNING;
1486 }
1487
1488 if (nsvc->nsvci != nsvci) {
1489 vty_out(vty, "NS-VC has a different nsvci (%u)!%s",
1490 nsvc->nsvci, VTY_NEWLINE);
1491 return CMD_WARNING;
1492 }
1493
1494 gprs_ns2_free_nsvc(nsvc);
1495 if (llist_empty(&nse->nsvc)) {
1496 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001497 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001498 }
1499
1500 return CMD_SUCCESS;
1501}
1502
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001503DEFUN(cfg_ns_nse_ip_sns_remote, cfg_ns_nse_ip_sns_remote_cmd,
1504 "ip-sns-remote " VTY_IPV46_CMD " <1-65535>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001505 "SNS Initial Endpoint\n"
1506 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1507 "SGSN UDP Port\n"
1508 )
1509{
1510 struct gprs_ns2_nse *nse = vty->index;
1511 bool dialect_modified = false;
1512 bool ll_modified = false;
1513 int rc;
1514
1515 /* argv[0] */
1516 struct osmo_sockaddr_str remote_str;
1517 struct osmo_sockaddr remote;
1518 uint16_t port = atoi(argv[1]);
1519
1520 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1521 nse->ll = GPRS_NS2_LL_UDP;
1522 ll_modified = true;
1523 }
1524
1525 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001526 if (ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_SNS) < 0)
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001527 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001528 dialect_modified = true;
1529 }
1530
1531 if (nse->ll != GPRS_NS2_LL_UDP) {
1532 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1533 goto err;
1534 }
1535
1536 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1537 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1538 goto err;
1539 }
1540
1541 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1542 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1543 goto err;
1544 }
1545
1546 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1547 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1548 goto err;
1549 }
1550
1551 rc = gprs_ns2_sns_add_endpoint(nse, &remote);
1552 switch (rc) {
1553 case 0:
1554 return CMD_SUCCESS;
1555 case -EADDRINUSE:
1556 vty_out(vty, "Specified SNS endpoint already part of the NSE.%s", VTY_NEWLINE);
1557 return CMD_WARNING;
1558 default:
1559 vty_out(vty, "Can not add specified SNS endpoint.%s", VTY_NEWLINE);
1560 return CMD_WARNING;
1561 }
1562
1563err:
1564 if (ll_modified)
1565 nse->ll = GPRS_NS2_LL_UNDEF;
1566 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001567 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001568 return CMD_WARNING;
1569}
1570
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001571DEFUN(cfg_no_ns_nse_ip_sns_remote, cfg_no_ns_nse_ip_sns_remote_cmd,
1572 "no ip-sns-remote " VTY_IPV46_CMD " <1-65535>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001573 NO_STR
1574 "Delete a SNS Initial Endpoint\n"
1575 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1576 "SGSN UDP Port\n"
1577 )
1578{
1579 struct gprs_ns2_nse *nse = vty->index;
1580 struct osmo_sockaddr_str remote_str; /* argv[0] */
1581 struct osmo_sockaddr remote;
1582 uint16_t port = atoi(argv[1]);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001583
1584 if (nse->ll != GPRS_NS2_LL_UDP) {
1585 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1586 return CMD_WARNING;
1587 }
1588
1589 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1590 vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%s", VTY_NEWLINE);
1591 return CMD_WARNING;
1592 }
1593
1594 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1595 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1596 return CMD_WARNING;
1597 }
1598
1599 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1600 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1601 return CMD_WARNING;
1602 }
1603
1604 if (gprs_ns2_sns_del_endpoint(nse, &remote)) {
1605 vty_out(vty, "Can not remove specified SNS endpoint.%s", VTY_NEWLINE);
1606 return CMD_WARNING;
1607 }
1608
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001609 if (vty_nse_check_sns(nse)) {
1610 /* there is still sns configuration valid */
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001611 return CMD_SUCCESS;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001612 } else {
1613 /* clean up nse to allow other nsvc commands */
Harald Welte06d9bf92021-03-05 10:20:11 +01001614 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001615 nse->ll = GPRS_NS2_LL_UNDEF;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001616 }
1617
1618 return CMD_SUCCESS;
1619}
1620
Harald Welted164ef82021-03-04 22:29:17 +01001621/* add all IP-SNS default binds to the given NSE */
1622int ns2_sns_add_sns_default_binds(struct gprs_ns2_nse *nse)
1623{
1624 struct vty_nse_bind *vnse_bind;
1625 int count = 0;
1626
1627 OSMO_ASSERT(nse->ll == GPRS_NS2_LL_UDP);
1628 OSMO_ASSERT(nse->dialect == GPRS_NS2_DIALECT_SNS);
1629
1630 llist_for_each_entry(vnse_bind, &ip_sns_default_binds, list) {
1631 struct gprs_ns2_vc_bind *bind = gprs_ns2_bind_by_name(vty_nsi, vnse_bind->vbind->name);
1632 /* the bind might not yet created because "listen" is missing. */
1633 if (!bind)
1634 continue;
1635 gprs_ns2_sns_add_bind(nse, bind);
1636 count++;
1637 }
1638 return count;
1639}
1640
1641DEFUN(cfg_ns_ip_sns_default_bind, cfg_ns_ip_sns_default_bind_cmd,
1642 "ip-sns-default bind ID",
1643 "Defaults for dynamically created NSEs created by IP-SNS in SGSN role\n"
1644 "IP SNS binds\n"
1645 "Name of NS udp bind whose IP endpoint will be used as IP-SNS local endpoint. Can be given multiple times.\n")
1646{
1647 struct vty_bind *vbind;
1648 struct vty_nse_bind *vnse_bind;
1649 const char *name = argv[0];
1650
1651 vbind = vty_bind_by_name(name);
1652 if (!vbind) {
1653 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1654 return CMD_WARNING;
1655 }
1656
1657 if (vbind->ll != GPRS_NS2_LL_UDP) {
1658 vty_out(vty, "ip-sns-default bind can only be used with UDP bind%s", VTY_NEWLINE);
1659 return CMD_WARNING;
1660 }
1661
1662 llist_for_each_entry(vnse_bind, &ip_sns_default_binds, list) {
1663 if (vnse_bind->vbind == vbind)
1664 return CMD_SUCCESS;
1665 }
1666
1667 vnse_bind = talloc(vty_nsi, struct vty_nse_bind);
1668 if (!vnse_bind)
1669 return CMD_WARNING;
1670 vnse_bind->vbind = vbind;
1671
1672 llist_add_tail(&vnse_bind->list, &ip_sns_default_binds);
1673
1674 return CMD_SUCCESS;
1675}
1676
1677DEFUN(cfg_no_ns_ip_sns_default_bind, cfg_no_ns_ip_sns_default_bind_cmd,
1678 "no ip-sns-default bind ID",
1679 NO_STR "Defaults for dynamically created NSEs created by IP-SNS in SGSN role\n"
1680 "IP SNS binds\n"
1681 "Name of NS udp bind whose IP endpoint will be removed as IP-SNS local endpoint.\n")
1682{
1683 struct vty_bind *vbind;
1684 struct vty_nse_bind *vnse_bind;
1685 const char *name = argv[0];
1686
1687 vbind = vty_bind_by_name(name);
1688 if (!vbind) {
1689 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1690 return CMD_WARNING;
1691 }
1692
1693 if (vbind->ll != GPRS_NS2_LL_UDP) {
1694 vty_out(vty, "ip-sns-default bind can only be used with UDP bind%s", VTY_NEWLINE);
1695 return CMD_WARNING;
1696 }
1697
1698 llist_for_each_entry(vnse_bind, &ip_sns_default_binds, list) {
1699 if (vnse_bind->vbind == vbind) {
1700 llist_del(&vnse_bind->list);
1701 talloc_free(vnse_bind);
1702 return CMD_SUCCESS;
1703 }
1704 }
1705
1706 vty_out(vty, "Bind '%s' was not an ip-sns-default bind%s", name, VTY_NEWLINE);
1707 return CMD_WARNING;
1708}
1709
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001710DEFUN(cfg_ns_nse_ip_sns_bind, cfg_ns_nse_ip_sns_bind_cmd,
1711 "ip-sns-bind BINDID",
1712 "IP SNS binds\n"
Harald Welte2230a912021-03-04 20:09:50 +01001713 "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 +01001714{
1715 struct gprs_ns2_nse *nse = vty->index;
1716 struct gprs_ns2_vc_bind *bind;
1717 struct vty_bind *vbind;
1718 struct vty_nse *vnse;
1719 const char *name = argv[0];
1720 bool ll_modified = false;
1721 bool dialect_modified = false;
1722 int rc;
1723
1724 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1725 nse->ll = GPRS_NS2_LL_UDP;
1726 ll_modified = true;
1727 }
1728
1729 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001730 if (ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_SNS) < 0)
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001731 goto err;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001732 dialect_modified = true;
1733 }
1734
1735 if (nse->ll != GPRS_NS2_LL_UDP) {
1736 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1737 goto err;
1738 }
1739
1740 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1741 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1742 goto err;
1743 }
1744
1745 vbind = vty_bind_by_name(name);
1746 if (!vbind) {
1747 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1748 goto err;
1749 }
1750
1751 if (vbind->ll != GPRS_NS2_LL_UDP) {
1752 vty_out(vty, "ip-sns-bind can only be used with UDP bind%s",
1753 VTY_NEWLINE);
1754 goto err;
1755 }
1756
1757 /* the vnse has been created together when creating the nse node. The parent node should check this already! */
1758 vnse = vty_nse_by_nsei(nse->nsei);
1759 OSMO_ASSERT(vnse);
1760
1761 rc = vty_nse_add_vbind(vnse, vbind);
1762 switch (rc) {
1763 case 0:
1764 break;
1765 case -EALREADY:
1766 vty_out(vty, "Failed to add ip-sns-bind %s already present%s", name, VTY_NEWLINE);
1767 goto err;
1768 case -ENOMEM:
1769 vty_out(vty, "Failed to add ip-sns-bind %s out of memory%s", name, VTY_NEWLINE);
1770 goto err;
1771 default:
1772 vty_out(vty, "Failed to add ip-sns-bind %s! %d%s", name, rc, VTY_NEWLINE);
1773 goto err;
1774 }
1775
1776 /* the bind might not yet created because "listen" is missing. */
1777 bind = gprs_ns2_bind_by_name(vty_nsi, name);
1778 if (!bind)
1779 return CMD_SUCCESS;
1780
1781 rc = gprs_ns2_sns_add_bind(nse, bind);
1782 switch (rc) {
1783 case 0:
1784 break;
1785 case -EALREADY:
1786 vty_out(vty, "Failed to add ip-sns-bind %s already present%s", name, VTY_NEWLINE);
1787 goto err;
1788 case -ENOMEM:
1789 vty_out(vty, "Failed to add ip-sns-bind %s out of memory%s", name, VTY_NEWLINE);
1790 goto err;
1791 default:
1792 vty_out(vty, "Failed to add ip-sns-bind %s! %d%s", name, rc, VTY_NEWLINE);
1793 goto err;
1794 }
1795
1796 return CMD_SUCCESS;
1797err:
1798 if (ll_modified)
1799 nse->ll = GPRS_NS2_LL_UNDEF;
1800 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001801 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001802
1803 return CMD_WARNING;
1804}
1805
1806DEFUN(cfg_no_ns_nse_ip_sns_bind, cfg_no_ns_nse_ip_sns_bind_cmd,
1807 "no ip-sns-bind BINDID",
1808 NO_STR
1809 "IP SNS binds\n"
Harald Welte2230a912021-03-04 20:09:50 +01001810 "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 +01001811{
1812 struct gprs_ns2_nse *nse = vty->index;
1813 struct gprs_ns2_vc_bind *bind;
1814 struct vty_bind *vbind;
1815 struct vty_nse *vnse;
1816 const char *name = argv[0];
1817 int rc;
1818
1819 if (nse->ll != GPRS_NS2_LL_UDP) {
1820 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1821 return CMD_WARNING;
1822 }
1823
1824 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1825 vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%s", VTY_NEWLINE);
1826 return CMD_WARNING;
1827 }
1828
1829 vbind = vty_bind_by_name(name);
1830 if (!vbind) {
1831 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1832 return CMD_WARNING;
1833 }
1834
1835 if (vbind->ll != GPRS_NS2_LL_UDP) {
1836 vty_out(vty, "no ip-sns-bind can only be used with UDP bind%s",
1837 VTY_NEWLINE);
1838 return CMD_WARNING;
1839 }
1840
1841 /* the vnse has been created together when creating the nse node. The parent node should check this already! */
1842 vnse = vty_nse_by_nsei(nse->nsei);
1843 OSMO_ASSERT(vnse);
1844
1845 rc = vty_nse_remove_vbind(vnse, vbind);
1846 switch(rc) {
1847 case 0:
1848 break;
1849 case -ENOENT:
1850 vty_out(vty, "Bind %s is not part of this NSE%s", name, VTY_NEWLINE);
1851 return CMD_WARNING;
1852 case -EINVAL:
1853 vty_out(vty, "no ip-sns-bind can only be used with UDP bind%s",
1854 VTY_NEWLINE);
1855 return CMD_WARNING;
1856 default:
1857 return CMD_WARNING;
1858 }
1859
1860 /* the bind might not exists yet */
1861 bind = gprs_ns2_bind_by_name(vty_nsi, name);
1862 if (bind)
1863 gprs_ns2_sns_del_bind(nse, bind);
1864
1865 if (!vty_nse_check_sns(nse)) {
1866 /* clean up nse to allow other nsvc commands */
Harald Welte06d9bf92021-03-05 10:20:11 +01001867 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001868 nse->ll = GPRS_NS2_LL_UNDEF;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001869 }
1870
1871 return CMD_SUCCESS;
1872}
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001873
1874/* non-config commands */
Alexander Couzens75b61882021-03-21 16:18:17 +01001875void ns2_vty_dump_nsvc(struct vty *vty, struct gprs_ns2_vc *nsvc, bool stats)
Alexander Couzens6a161492020-07-12 13:45:50 +02001876{
Harald Weltedc2d0802020-12-01 18:17:28 +01001877 if (nsvc->nsvci_is_valid)
Alexander Couzens5e040bf2021-06-15 23:19:42 +02001878 vty_out(vty, " NSVCI %05u: %s %s %s%s", nsvc->nsvci,
1879 osmo_fsm_inst_state_name(nsvc->fi),
1880 nsvc->persistent ? "PERSIST" : "DYNAMIC",
1881 gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Harald Weltedc2d0802020-12-01 18:17:28 +01001882 else
Alexander Couzens5e040bf2021-06-15 23:19:42 +02001883 vty_out(vty, " %s %s sig_weight=%u data_weight=%u %s%s",
1884 osmo_fsm_inst_state_name(nsvc->fi),
1885 nsvc->persistent ? "PERSIST" : "DYNAMIC",
1886 nsvc->sig_weight, nsvc->data_weight,
1887 gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001888
1889 if (stats) {
Alexander Couzens1dd9cbf2021-03-21 16:22:08 +01001890 vty_out_rate_ctr_group(vty, " ", nsvc->ctrg);
1891 vty_out_stat_item_group(vty, " ", nsvc->statg);
Alexander Couzens6a161492020-07-12 13:45:50 +02001892 }
1893}
1894
1895static void dump_nse(struct vty *vty, const struct gprs_ns2_nse *nse, bool stats, bool persistent_only)
1896{
1897 struct gprs_ns2_vc *nsvc;
Alexander Couzens0ea4a4e2021-03-21 16:37:23 +01001898 unsigned int nsvcs = 0;
Alexander Couzens6a161492020-07-12 13:45:50 +02001899
Alexander Couzens3e539ed2021-03-21 16:25:18 +01001900 if (persistent_only && !nse->persistent)
1901 return;
1902
Harald Welte0ff12ad2020-12-01 17:51:07 +01001903 vty_out(vty, "NSEI %05u: %s, %s%s", nse->nsei, gprs_ns2_lltype_str(nse->ll),
1904 nse->alive ? "ALIVE" : "DEAD", VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001905
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001906 ns2_sns_dump_vty(vty, " ", nse, stats);
Alexander Couzens0ea4a4e2021-03-21 16:37:23 +01001907 llist_for_each_entry(nsvc, &nse->nsvc, list) {
1908 nsvcs++;
1909 }
1910 vty_out(vty, " %u NS-VC:%s", nsvcs, VTY_NEWLINE);
Alexander Couzens3e539ed2021-03-21 16:25:18 +01001911 llist_for_each_entry(nsvc, &nse->nsvc, list)
1912 ns2_vty_dump_nsvc(vty, nsvc, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001913}
1914
Alexander Couzens22f34712020-10-02 02:34:39 +02001915static void dump_bind(struct vty *vty, const struct gprs_ns2_vc_bind *bind, bool stats)
1916{
1917 if (bind->dump_vty)
1918 bind->dump_vty(bind, vty, stats);
Harald Welte76346072021-01-31 11:54:02 +01001919
1920 if (stats) {
1921 vty_out_stat_item_group(vty, " ", bind->statg);
1922 }
Alexander Couzens22f34712020-10-02 02:34:39 +02001923}
1924
Harald Welte2fce19a2020-12-01 17:52:55 +01001925static void dump_ns_bind(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats)
Alexander Couzens6a161492020-07-12 13:45:50 +02001926{
Alexander Couzens22f34712020-10-02 02:34:39 +02001927 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6a161492020-07-12 13:45:50 +02001928
Alexander Couzens22f34712020-10-02 02:34:39 +02001929 llist_for_each_entry(bind, &nsi->binding, list) {
1930 dump_bind(vty, bind, stats);
1931 }
Harald Welte2fce19a2020-12-01 17:52:55 +01001932}
1933
1934
1935static void dump_ns_entities(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats, bool persistent_only)
1936{
1937 struct gprs_ns2_nse *nse;
Alexander Couzens22f34712020-10-02 02:34:39 +02001938
Alexander Couzens6a161492020-07-12 13:45:50 +02001939 llist_for_each_entry(nse, &nsi->nse, list) {
1940 dump_nse(vty, nse, stats, persistent_only);
Alexander Couzens6a161492020-07-12 13:45:50 +02001941 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001942}
1943
Harald Welte25ee7552020-12-02 22:14:00 +01001944/* Backwards compatibility, among other things for the TestVTYGbproxy which expects
1945 * 'show ns' to output something about binds */
1946DEFUN_HIDDEN(show_ns, show_ns_cmd, "show ns",
1947 SHOW_STR SHOW_NS_STR)
1948{
1949 dump_ns_entities(vty, vty_nsi, false, false);
1950 dump_ns_bind(vty, vty_nsi, false);
Harald Welte069967b2021-03-30 12:05:31 +02001951 if (vty_fr_network && llist_count(&vty_fr_network->links))
1952 osmo_fr_network_dump_vty(vty, vty_fr_network);
Harald Welte25ee7552020-12-02 22:14:00 +01001953 return CMD_SUCCESS;
1954}
1955
1956
Harald Welte2fce19a2020-12-01 17:52:55 +01001957DEFUN(show_ns_binds, show_ns_binds_cmd, "show ns binds [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001958 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01001959 "Display information about the NS protocol binds\n"
1960 "Include statistic\n")
Alexander Couzens6a161492020-07-12 13:45:50 +02001961{
Harald Welte2fce19a2020-12-01 17:52:55 +01001962 bool stats = false;
1963 if (argc > 0)
1964 stats = true;
1965
1966 dump_ns_bind(vty, vty_nsi, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001967 return CMD_SUCCESS;
1968}
1969
Harald Welte2fce19a2020-12-01 17:52:55 +01001970DEFUN(show_ns_entities, show_ns_entities_cmd, "show ns entities [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001971 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01001972 "Display information about the NS protocol entities (NSEs)\n"
Alexander Couzens6a161492020-07-12 13:45:50 +02001973 "Include statistics\n")
1974{
Harald Welte2fce19a2020-12-01 17:52:55 +01001975 bool stats = false;
1976 if (argc > 0)
1977 stats = true;
1978
1979 dump_ns_entities(vty, vty_nsi, stats, false);
Alexander Couzens6a161492020-07-12 13:45:50 +02001980 return CMD_SUCCESS;
1981}
1982
1983DEFUN(show_ns_pers, show_ns_pers_cmd, "show ns persistent",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001984 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02001985 "Show only persistent NS\n")
1986{
Harald Welte2fce19a2020-12-01 17:52:55 +01001987 dump_ns_entities(vty, vty_nsi, true, true);
Alexander Couzens6a161492020-07-12 13:45:50 +02001988 return CMD_SUCCESS;
1989}
1990
1991DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001992 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02001993 "Select one NSE by its NSE Identifier\n"
1994 "Select one NSE by its NS-VC Identifier\n"
1995 "The Identifier of selected type\n"
1996 "Include Statistics\n")
1997{
1998 struct gprs_ns2_inst *nsi = vty_nsi;
1999 struct gprs_ns2_nse *nse;
2000 struct gprs_ns2_vc *nsvc;
2001 uint16_t id = atoi(argv[1]);
2002 bool show_stats = false;
2003
2004 if (argc >= 3)
2005 show_stats = true;
2006
2007 if (!strcmp(argv[0], "nsei")) {
2008 nse = gprs_ns2_nse_by_nsei(nsi, id);
2009 if (!nse) {
2010 return CMD_WARNING;
2011 }
2012
2013 dump_nse(vty, nse, show_stats, false);
2014 } else {
2015 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
2016
2017 if (!nsvc) {
2018 vty_out(vty, "No such NS Entity%s", VTY_NEWLINE);
2019 return CMD_WARNING;
2020 }
2021
Alexander Couzens75b61882021-03-21 16:18:17 +01002022 ns2_vty_dump_nsvc(vty, nsvc, show_stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02002023 }
2024
2025 return CMD_SUCCESS;
2026}
2027
Daniel Willmanndbab7142020-11-18 14:19:56 +01002028static int nsvc_force_unconf_cb(struct gprs_ns2_vc *nsvc, void *ctx)
2029{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01002030 ns2_vc_force_unconfigured(nsvc);
Harald Welte7fe8d712021-01-31 18:40:54 +01002031 ns2_vc_fsm_start(nsvc);
Daniel Willmanndbab7142020-11-18 14:19:56 +01002032 return 0;
2033}
2034
2035DEFUN_HIDDEN(nsvc_force_unconf, nsvc_force_unconf_cmd,
2036 "nsvc nsei <0-65535> force-unconfigured",
2037 "NS Virtual Connection\n"
2038 "The NSEI\n"
2039 "Reset the NSVCs back to initial state\n"
2040 )
2041{
2042 struct gprs_ns2_inst *nsi = vty_nsi;
2043 struct gprs_ns2_nse *nse;
2044
2045 uint16_t id = atoi(argv[0]);
2046
2047 nse = gprs_ns2_nse_by_nsei(nsi, id);
2048 if (!nse) {
2049 vty_out(vty, "Could not find NSE for NSEI %u%s", id, VTY_NEWLINE);
2050 return CMD_WARNING;
2051 }
2052
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002053 if (!nse->persistent) {
2054 gprs_ns2_free_nse(nse);
2055 } else if (nse->dialect == GPRS_NS2_DIALECT_SNS) {
Alexander Couzens280ed782020-12-21 18:25:41 +01002056 gprs_ns2_free_nsvcs(nse);
2057 } else {
2058 /* Perform the operation for all nsvc */
2059 gprs_ns2_nse_foreach_nsvc(nse, nsvc_force_unconf_cb, NULL);
2060 }
Daniel Willmanndbab7142020-11-18 14:19:56 +01002061
2062 return CMD_SUCCESS;
2063}
2064
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002065DEFUN(nsvc_block, nsvc_block_cmd,
Alexander Couzens27e58732021-03-21 17:12:08 +01002066 "nsvc <0-65535> (block|unblock|reset)",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002067 "NS Virtual Connection\n"
2068 NSVCI_STR
2069 "Block a NSVC. As cause code O&M intervention will be used.\n"
Alexander Couzens27e58732021-03-21 17:12:08 +01002070 "Unblock a NSVC. As cause code O&M intervention will be used.\n"
2071 "Reset a NSVC. As cause code O&M intervention will be used.\n")
Alexander Couzens841817e2020-11-19 00:41:29 +01002072{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002073 struct gprs_ns2_inst *nsi = vty_nsi;
2074 struct gprs_ns2_vc *nsvc;
Alexander Couzense7dfeac2021-03-21 17:28:36 +01002075 int rc;
Alexander Couzens841817e2020-11-19 00:41:29 +01002076
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002077 uint16_t id = atoi(argv[0]);
Alexander Couzens841817e2020-11-19 00:41:29 +01002078
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002079 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
2080 if (!nsvc) {
2081 vty_out(vty, "Could not find NSVCI %05u%s", id, VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +01002082 return CMD_WARNING;
2083 }
2084
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002085 if (!strcmp(argv[1], "block")) {
Alexander Couzense7dfeac2021-03-21 17:28:36 +01002086 rc = ns2_vc_block(nsvc);
2087 switch (rc) {
2088 case 0:
2089 vty_out(vty, "The NS-VC %05u will be blocked.%s", id, VTY_NEWLINE);
2090 return CMD_SUCCESS;
2091 case -EALREADY:
2092 vty_out(vty, "The NS-VC %05u is already blocked.%s", id, VTY_NEWLINE);
2093 return CMD_ERR_NOTHING_TODO;
2094 default:
2095 vty_out(vty, "An unknown error %d happend on NS-VC %05u.%s", rc, id, VTY_NEWLINE);
2096 return CMD_WARNING;
2097 }
Alexander Couzens27e58732021-03-21 17:12:08 +01002098 } else if (!strcmp(argv[1], "unblock")) {
Alexander Couzense7dfeac2021-03-21 17:28:36 +01002099 rc = ns2_vc_unblock(nsvc);
2100 switch (rc) {
2101 case 0:
2102 vty_out(vty, "The NS-VC %05u will be unblocked.%s", id, VTY_NEWLINE);
2103 return CMD_SUCCESS;
2104 case -EALREADY:
2105 vty_out(vty, "The NS-VC %05u is already unblocked.%s", id, VTY_NEWLINE);
2106 return CMD_ERR_NOTHING_TODO;
2107 default:
2108 vty_out(vty, "An unknown error %d happend on NS-VC %05u.%s", rc, id, VTY_NEWLINE);
2109 return CMD_WARNING;
2110 }
Alexander Couzens27e58732021-03-21 17:12:08 +01002111 } else {
2112 ns2_vc_reset(nsvc);
Alexander Couzense7dfeac2021-03-21 17:28:36 +01002113 vty_out(vty, "The NS-VC %05u has been resetted.%s", id, VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02002114 }
2115
2116 return CMD_SUCCESS;
2117}
2118
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002119static void log_set_nse_filter(struct log_target *target,
2120 struct gprs_ns2_nse *nse)
Alexander Couzens6a161492020-07-12 13:45:50 +02002121{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002122 if (nse) {
2123 target->filter_map |= (1 << LOG_FLT_GB_NSE);
2124 target->filter_data[LOG_FLT_GB_NSE] = nse;
2125 } else if (target->filter_data[LOG_FLT_GB_NSE]) {
2126 target->filter_map = ~(1 << LOG_FLT_GB_NSE);
2127 target->filter_data[LOG_FLT_GB_NSE] = NULL;
2128 }
Alexander Couzens6a161492020-07-12 13:45:50 +02002129}
2130
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002131static void log_set_nsvc_filter(struct log_target *target,
2132 struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +02002133{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002134 if (nsvc) {
2135 target->filter_map |= (1 << LOG_FLT_GB_NSVC);
2136 target->filter_data[LOG_FLT_GB_NSVC] = nsvc;
2137 } else if (target->filter_data[LOG_FLT_GB_NSVC]) {
2138 target->filter_map = ~(1 << LOG_FLT_GB_NSVC);
2139 target->filter_data[LOG_FLT_GB_NSVC] = NULL;
2140 }
Alexander Couzens6a161492020-07-12 13:45:50 +02002141}
2142
Daniel Willmann751977b2020-12-02 18:59:44 +01002143DEFUN(logging_fltr_nse,
2144 logging_fltr_nse_cmd,
2145 "logging filter nse nsei <0-65535>",
2146 LOGGING_STR FILTER_STR
2147 "Filter based on NS Entity\n"
2148 "Identify NSE by NSEI\n"
2149 "Numeric identifier\n")
2150{
2151 struct log_target *tgt;
2152 struct gprs_ns2_nse *nse;
Daniel Willmann89106522020-12-04 01:36:59 +01002153 uint16_t id = atoi(argv[0]);
Daniel Willmann751977b2020-12-02 18:59:44 +01002154
2155 log_tgt_mutex_lock();
2156 tgt = osmo_log_vty2tgt(vty);
2157 if (!tgt) {
2158 log_tgt_mutex_unlock();
2159 return CMD_WARNING;
2160 }
2161
2162 nse = gprs_ns2_nse_by_nsei(vty_nsi, id);
2163 if (!nse) {
2164 vty_out(vty, "No NSE by that identifier%s", VTY_NEWLINE);
2165 log_tgt_mutex_unlock();
2166 return CMD_WARNING;
2167 }
2168
2169 log_set_nse_filter(tgt, nse);
2170 log_tgt_mutex_unlock();
2171 return CMD_SUCCESS;
2172}
2173
Alexander Couzens6a161492020-07-12 13:45:50 +02002174/* TODO: add filter for single connection by description */
2175DEFUN(logging_fltr_nsvc,
2176 logging_fltr_nsvc_cmd,
2177 "logging filter nsvc nsvci <0-65535>",
2178 LOGGING_STR FILTER_STR
2179 "Filter based on NS Virtual Connection\n"
2180 "Identify NS-VC by NSVCI\n"
2181 "Numeric identifier\n")
2182{
2183 struct log_target *tgt;
2184 struct gprs_ns2_vc *nsvc;
Daniel Willmann89106522020-12-04 01:36:59 +01002185 uint16_t id = atoi(argv[0]);
Alexander Couzens6a161492020-07-12 13:45:50 +02002186
2187 log_tgt_mutex_lock();
2188 tgt = osmo_log_vty2tgt(vty);
2189 if (!tgt) {
2190 log_tgt_mutex_unlock();
2191 return CMD_WARNING;
2192 }
2193
2194 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, id);
2195 if (!nsvc) {
2196 vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE);
2197 log_tgt_mutex_unlock();
2198 return CMD_WARNING;
2199 }
2200
2201 log_set_nsvc_filter(tgt, nsvc);
2202 log_tgt_mutex_unlock();
2203 return CMD_SUCCESS;
2204}
2205
Alexander Couzense43b46e2021-01-27 21:52:08 +01002206/*! initialized a reduced vty interface which excludes the configuration nodes besides timeouts.
2207 * This can be used by the PCU which can be only configured by the BTS/BSC and not by the vty.
2208 * \param[in] nsi NS instance on which we operate
2209 * \return 0 on success.
2210 */
2211int gprs_ns2_vty_init_reduced(struct gprs_ns2_inst *nsi)
Alexander Couzens6a161492020-07-12 13:45:50 +02002212{
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01002213 vty_nsi = nsi;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002214 INIT_LLIST_HEAD(&binds);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002215 INIT_LLIST_HEAD(&nses);
Harald Welted164ef82021-03-04 22:29:17 +01002216 INIT_LLIST_HEAD(&ip_sns_default_binds);
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01002217
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002218 vty_fr_network = osmo_fr_network_alloc(nsi);
2219 if (!vty_fr_network)
2220 return -ENOMEM;
Alexander Couzens6a161492020-07-12 13:45:50 +02002221
Harald Welte25ee7552020-12-02 22:14:00 +01002222 install_lib_element_ve(&show_ns_cmd);
Harald Welte2fce19a2020-12-01 17:52:55 +01002223 install_lib_element_ve(&show_ns_binds_cmd);
2224 install_lib_element_ve(&show_ns_entities_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002225 install_lib_element_ve(&show_ns_pers_cmd);
2226 install_lib_element_ve(&show_nse_cmd);
Daniel Willmann751977b2020-12-02 18:59:44 +01002227 install_lib_element_ve(&logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002228 install_lib_element_ve(&logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002229
Daniel Willmanndbab7142020-11-18 14:19:56 +01002230 install_lib_element(ENABLE_NODE, &nsvc_force_unconf_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002231 install_lib_element(ENABLE_NODE, &nsvc_block_cmd);
Daniel Willmanndbab7142020-11-18 14:19:56 +01002232
Daniel Willmann751977b2020-12-02 18:59:44 +01002233 install_lib_element(CFG_LOG_NODE, &logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002234 install_lib_element(CFG_LOG_NODE, &logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002235
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002236 install_lib_element(CONFIG_NODE, &cfg_ns_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002237
Alexander Couzens6a161492020-07-12 13:45:50 +02002238 install_node(&ns_node, config_write_ns);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002239 /* TODO: convert into osmo timer */
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002240 install_lib_element(L_NS_NODE, &cfg_ns_timer_cmd);
Alexander Couzense43b46e2021-01-27 21:52:08 +01002241
2242 return 0;
2243}
2244
2245int gprs_ns2_vty_init(struct gprs_ns2_inst *nsi)
2246{
2247 int rc = gprs_ns2_vty_init_reduced(nsi);
2248 if (rc)
2249 return rc;
2250
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002251 install_lib_element(L_NS_NODE, &cfg_ns_nsei_cmd);
2252 install_lib_element(L_NS_NODE, &cfg_no_ns_nsei_cmd);
2253 install_lib_element(L_NS_NODE, &cfg_ns_bind_cmd);
2254 install_lib_element(L_NS_NODE, &cfg_no_ns_bind_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002255
Harald Welted164ef82021-03-04 22:29:17 +01002256 install_lib_element(L_NS_NODE, &cfg_ns_ip_sns_default_bind_cmd);
2257 install_lib_element(L_NS_NODE, &cfg_no_ns_ip_sns_default_bind_cmd);
2258
Alexander Couzens260cd522021-01-28 20:31:31 +01002259 install_node(&ns_bind_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002260 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_listen_cmd);
2261 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_listen_cmd);
2262 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_dscp_cmd);
2263 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_dscp_cmd);
Harald Welted99e4ee2021-04-28 19:57:12 +02002264 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_priority_cmd);
Alexander Couzensc4704762021-02-08 23:13:12 +01002265 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_ip_sns_weight_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002266 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_ipaccess_cmd);
2267 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_ipaccess_cmd);
2268 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_fr_cmd);
2269 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_fr_cmd);
Harald Welte42e36462021-03-03 18:12:09 +01002270 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_accept_sns_cmd);
2271 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_accept_sns_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002272
Alexander Couzens260cd522021-01-28 20:31:31 +01002273 install_node(&ns_nse_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002274 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_fr_cmd);
2275 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvci_cmd);
2276 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_fr_dlci_cmd);
2277 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_udp_cmd);
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01002278 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_udp_weights_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002279 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_udp_cmd);
2280 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_ipa_cmd);
2281 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_ipa_cmd);
Alexander Couzens5fa431c2021-02-08 23:21:54 +01002282 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_remote_cmd);
2283 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_remote_cmd);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002284 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_bind_cmd);
2285 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_bind_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002286
2287 return 0;
2288}