blob: 2f540c2144c17372fa218cf2890b7f7ec40e7497 [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 Couzensd5cd8c62021-06-15 20:59:03 +0200144 llist_add_tail(&vbind->list, &binds);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100145 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);
Alexander Couzensd5cd8c62021-06-15 20:59:03 +0200175 llist_add_tail(&vnse->list, &nses);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100176 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);
Alexander Couzens15596892021-04-19 03:31:05 +0200220 return 0;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100221 }
222 }
223
224 return -ENOENT;
225}
226
227/* check if the NSE still has SNS configuration */
228static bool vty_nse_check_sns(struct gprs_ns2_nse *nse) {
229 struct vty_nse *vnse = vty_nse_by_nsei(nse->nsei);
230
231 int count = gprs_ns2_sns_count(nse);
232 if (count > 0) {
233 /* there are other sns endpoints */
234 return true;
235 }
236
237 if (!vnse)
238 return false;
239
240 if (llist_empty(&vnse->binds))
241 return false;
242
243 return true;
244}
245
Alexander Couzens6a161492020-07-12 13:45:50 +0200246static struct cmd_node ns_node = {
247 L_NS_NODE,
248 "%s(config-ns)# ",
249 1,
250};
251
Alexander Couzens6a161492020-07-12 13:45:50 +0200252DEFUN(cfg_ns, cfg_ns_cmd,
253 "ns",
254 "Configure the GPRS Network Service")
255{
256 vty->node = L_NS_NODE;
257 return CMD_SUCCESS;
258}
259
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100260DEFUN(cfg_ns_timer, cfg_ns_timer_cmd,
261 "timer " NS_TIMERS " <0-65535>",
262 "Network Service Timer\n"
263 NS_TIMERS_HELP "Timer Value\n")
264{
265 int idx = get_string_value(gprs_ns_timer_strs, argv[0]);
266 int val = atoi(argv[1]);
267
268 if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout))
269 return CMD_WARNING;
270
271 vty_nsi->timeout[idx] = val;
272
273 return CMD_SUCCESS;
274}
275
276DEFUN(cfg_ns_nsei, cfg_ns_nsei_cmd,
Harald Welte579699b2021-03-05 10:22:23 +0100277 "nse <0-65535> [ip-sns-role-sgsn]",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100278 "Persistent NS Entity\n"
279 "NS Entity ID (NSEI)\n"
Harald Welte579699b2021-03-05 10:22:23 +0100280 "Create NSE in SGSN role (default: BSS)\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100281 )
282{
283 struct gprs_ns2_nse *nse;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100284 struct vty_nse *vnse;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100285 uint16_t nsei = atoi(argv[0]);
Harald Welte579699b2021-03-05 10:22:23 +0100286 bool sgsn_role = false;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100287 bool free_vnse = false;
Harald Welte579699b2021-03-05 10:22:23 +0100288 if (argc > 1 && !strcmp(argv[1], "ip-sns-role-sgsn"))
289 sgsn_role = true;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100290
291 vnse = vty_nse_by_nsei(nsei);
292 if (!vnse) {
293 vnse = vty_nse_alloc(nsei);
294 if (!vnse) {
295 vty_out(vty, "Failed to create vty NSE!%s", VTY_NEWLINE);
296 return CMD_ERR_INCOMPLETE;
297 }
298 free_vnse = true;
299 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100300
301 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
302 if (!nse) {
Harald Welte579699b2021-03-05 10:22:23 +0100303 nse = gprs_ns2_create_nse2(vty_nsi, nsei, GPRS_NS2_LL_UNDEF, GPRS_NS2_DIALECT_UNDEF,
304 sgsn_role);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100305 if (!nse) {
306 vty_out(vty, "Failed to create NSE!%s", VTY_NEWLINE);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100307 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100308 }
309 nse->persistent = true;
310 }
311
312 if (!nse->persistent) {
313 /* TODO: should the dynamic NSE removed? */
314 vty_out(vty, "A dynamic NSE with the specified NSEI already exists%s", VTY_NEWLINE);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100315 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100316 }
317
318 vty->node = L_NS_NSE_NODE;
319 vty->index = nse;
320
321 return CMD_SUCCESS;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100322
323err:
324 if (free_vnse)
325 talloc_free(vnse);
326
327 return CMD_ERR_INCOMPLETE;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100328}
329
330DEFUN(cfg_no_ns_nsei, cfg_no_ns_nsei_cmd,
331 "no nse <0-65535>",
332 NO_STR
333 "Delete a Persistent NS Entity\n"
334 "NS Entity ID (NSEI)\n"
335 )
336{
337 struct gprs_ns2_nse *nse;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100338 struct vty_nse *vnse;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100339 uint16_t nsei = atoi(argv[0]);
340
341 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
342 if (!nse) {
343 vty_out(vty, "Can not find NS Entity %s%s", argv[0], VTY_NEWLINE);
344 return CMD_ERR_NOTHING_TODO;
345 }
346
347 if (!nse->persistent) {
348 vty_out(vty, "Ignoring non-persistent NS Entity%s", VTY_NEWLINE);
349 return CMD_WARNING;
350 }
351
352 vty_out(vty, "Deleting NS Entity %u%s", nse->nsei, VTY_NEWLINE);
353 gprs_ns2_free_nse(nse);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100354
355 vnse = vty_nse_by_nsei(nsei);
356 vty_nse_free(vnse);
357
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100358 return CMD_SUCCESS;
359}
360
361/* TODO: add fr/gre */
362DEFUN(cfg_ns_bind, cfg_ns_bind_cmd,
363 "bind (fr|udp) ID",
Harald Welte2230a912021-03-04 20:09:50 +0100364 "Configure local Bind\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100365 "Frame Relay\n" "UDP/IP\n"
Harald Welte2230a912021-03-04 20:09:50 +0100366 "Unique identifier for this bind (to reference from NS-VCs, NSEs, ...)\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100367 )
368{
369 const char *nstype = argv[0];
370 const char *name = argv[1];
371 struct vty_bind *vbind;
372 enum gprs_ns2_ll ll;
373 int rc;
374
375 rc = get_string_value(vty_ll_names, nstype);
376 if (rc < 0)
377 return CMD_WARNING;
378 ll = (enum gprs_ns2_ll) rc;
379
380 if (!osmo_identifier_valid(name)) {
381 vty_out(vty, "Invalid ID. The ID should be only alphanumeric.%s", VTY_NEWLINE);
382 return CMD_WARNING;
383 }
384
385 vbind = vty_bind_by_name(name);
386 if (vbind) {
387 if (vbind->ll != ll) {
388 vty_out(vty, "A bind with the specified ID already exists with a different type (fr|frgre|udp)!%s",
389 VTY_NEWLINE);
390 return CMD_WARNING;
391 }
392 } else {
393 vbind = vty_bind_alloc(name);
394 if (!vbind) {
395 vty_out(vty, "Can not create bind - out of memory%s", VTY_NEWLINE);
396 return CMD_WARNING;
397 }
398 vbind->ll = ll;
399 }
400
401 vty->index = vbind;
402 vty->node = L_NS_BIND_NODE;
403
404 return CMD_SUCCESS;
405}
406
407DEFUN(cfg_no_ns_bind, cfg_no_ns_bind_cmd,
408 "no bind ID",
409 NO_STR
Harald Welte2230a912021-03-04 20:09:50 +0100410 "Delete a bind\n"
411 "Unique identifier for this bind\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100412 )
413{
414 struct vty_bind *vbind;
415 struct gprs_ns2_vc_bind *bind;
416 const char *name = argv[0];
417
418 vbind = vty_bind_by_name(name);
419 if (!vbind) {
420 vty_out(vty, "bind %s does not exist!%s", name, VTY_NEWLINE);
421 return CMD_WARNING;
422 }
423 vty_bind_free(vbind);
424 bind = gprs_ns2_bind_by_name(vty_nsi, name);
425 if (bind)
Alexander Couzens56287d22021-07-06 10:56:55 +0200426 gprs_ns2_free_bind(bind);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100427 return CMD_SUCCESS;
428}
429
430
431static void config_write_vbind(struct vty *vty, struct vty_bind *vbind)
432{
433 struct gprs_ns2_vc_bind *bind;
434 const struct osmo_sockaddr *addr;
435 struct osmo_sockaddr_str addr_str;
436 const char *netif, *frrole_str, *llstr;
437 enum osmo_fr_role frrole;
438
439 llstr = get_value_string_or_null(vty_ll_names, vbind->ll);
440 if (!llstr)
441 return;
442 vty_out(vty, " bind %s %s%s", llstr, vbind->name, VTY_NEWLINE);
443
444 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
445 switch (vbind->ll) {
446 case GPRS_NS2_LL_FR:
447 if (bind) {
448 netif = gprs_ns2_fr_bind_netif(bind);
449 if (!netif)
450 return;
451 frrole = gprs_ns2_fr_bind_role(bind);
452 if ((int) frrole == -1)
453 return;
454 frrole_str = get_value_string_or_null(vty_fr_role_names, frrole);
455 if (netif && frrole_str)
456 vty_out(vty, " fr %s %s%s", netif, frrole_str, VTY_NEWLINE);
457 }
458 break;
459 case GPRS_NS2_LL_UDP:
460 if (bind) {
461 addr = gprs_ns2_ip_bind_sockaddr(bind);
462 if (!osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas)) {
463 vty_out(vty, " listen %s %u%s", addr_str.ip, addr_str.port,
464 VTY_NEWLINE);
465 }
466 }
467 if (vbind->accept_ipaccess)
468 vty_out(vty, " accept-ipaccess%s", VTY_NEWLINE);
Harald Welte42e36462021-03-03 18:12:09 +0100469 if (vbind->accept_sns)
470 vty_out(vty, " accept-dynamic-ip-sns%s", VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100471 if (vbind->dscp)
472 vty_out(vty, " dscp %u%s", vbind->dscp, VTY_NEWLINE);
Harald Welted99e4ee2021-04-28 19:57:12 +0200473 if (vbind->priority)
Harald Welte5782fec2021-04-29 21:28:53 +0200474 vty_out(vty, " socket-priority %u%s", vbind->priority, VTY_NEWLINE);
Daniel Willmann64db6362021-02-12 12:21:45 +0100475 vty_out(vty, " ip-sns signalling-weight %u data-weight %u%s",
Alexander Couzensc4704762021-02-08 23:13:12 +0100476 vbind->ip_sns_sig_weight, vbind->ip_sns_data_weight, VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100477 break;
478 default:
479 return;
480 }
481}
482
483static void config_write_nsvc(struct vty *vty, const struct gprs_ns2_vc *nsvc)
484{
485 const char *netif;
486 uint16_t dlci;
487 const struct osmo_sockaddr *addr;
488 struct osmo_sockaddr_str addr_str;
489
490 switch (nsvc->nse->ll) {
491 case GPRS_NS2_LL_UNDEF:
492 break;
493 case GPRS_NS2_LL_UDP:
494 switch (nsvc->nse->dialect) {
495 case GPRS_NS2_DIALECT_IPACCESS:
496 addr = gprs_ns2_ip_vc_remote(nsvc);
497 if (!addr)
498 break;
499 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas))
500 break;
501 vty_out(vty, " nsvc ipa %s %s %u nsvci %u%s",
502 nsvc->bind->name, addr_str.ip, addr_str.port,
503 nsvc->nsvci, VTY_NEWLINE);
504 break;
505 case GPRS_NS2_DIALECT_STATIC_ALIVE:
506 addr = gprs_ns2_ip_vc_remote(nsvc);
507 if (!addr)
508 break;
509 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas))
510 break;
511 vty_out(vty, " nsvc udp %s %s %u%s",
512 nsvc->bind->name, addr_str.ip, addr_str.port, VTY_NEWLINE);
513 break;
514 default:
515 break;
516 }
517 break;
518 case GPRS_NS2_LL_FR:
519 netif = gprs_ns2_fr_bind_netif(nsvc->bind);
520 if (!netif)
521 break;
522 dlci = gprs_ns2_fr_nsvc_dlci(nsvc);
523 if (!dlci)
524 break;
525 OSMO_ASSERT(nsvc->nsvci_is_valid);
526 vty_out(vty, " nsvc fr %s dlci %u nsvci %u%s",
527 netif, dlci, nsvc->nsvci, VTY_NEWLINE);
528 break;
529 case GPRS_NS2_LL_FR_GRE:
530 break;
531 }
532}
533
534static void _config_write_ns_nse(struct vty *vty, struct gprs_ns2_nse *nse)
535{
536 struct gprs_ns2_vc *nsvc;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100537 struct vty_nse *vnse = vty_nse_by_nsei(nse->nsei);
538 struct vty_nse_bind *vbind;
539
540 OSMO_ASSERT(vnse);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100541
Harald Welte579699b2021-03-05 10:22:23 +0100542 vty_out(vty, " nse %u%s%s", nse->nsei,
543 nse->ip_sns_role_sgsn ? " ip-sns-role-sgsn" : "", VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100544 switch (nse->dialect) {
545 case GPRS_NS2_DIALECT_SNS:
546 ns2_sns_write_vty(vty, nse);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100547 llist_for_each_entry(vbind, &vnse->binds, list) {
548 vty_out(vty, " ip-sns-bind %s%s", vbind->vbind->name, VTY_NEWLINE);
549 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100550 break;
551 default:
552 llist_for_each_entry(nsvc, &nse->nsvc, list) {
553 config_write_nsvc(vty, nsvc);
554 }
555 break;
556 }
557}
558
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100559static int config_write_ns_nse(struct vty *vty)
560{
561 struct gprs_ns2_nse *nse;
562
563 llist_for_each_entry(nse, &vty_nsi->nse, list) {
564 if (!nse->persistent)
565 continue;
566
567 _config_write_ns_nse(vty, nse);
568 }
569
570 return 0;
571}
572
573static int config_write_ns_bind(struct vty *vty)
574{
575 struct vty_bind *vbind;
576
577 llist_for_each_entry(vbind, &binds, list) {
578 config_write_vbind(vty, vbind);
579 }
580
581 return 0;
582}
583
Alexander Couzens260cd522021-01-28 20:31:31 +0100584static int config_write_ns(struct vty *vty)
585{
Harald Welted164ef82021-03-04 22:29:17 +0100586 struct vty_nse_bind *vbind;
Alexander Couzens260cd522021-01-28 20:31:31 +0100587 unsigned int i;
588 int ret;
589
590 vty_out(vty, "ns%s", VTY_NEWLINE);
591
592 for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++)
593 vty_out(vty, " timer %s %u%s",
594 get_value_string(gprs_ns_timer_strs, i),
595 vty_nsi->timeout[i], VTY_NEWLINE);
596
597 ret = config_write_ns_bind(vty);
598 if (ret)
599 return ret;
600
Harald Welted164ef82021-03-04 22:29:17 +0100601 llist_for_each_entry(vbind, &ip_sns_default_binds, list) {
602 vty_out(vty, " ip-sns-default bind %s%s", vbind->vbind->name, VTY_NEWLINE);
603 }
604
Alexander Couzens260cd522021-01-28 20:31:31 +0100605 ret = config_write_ns_nse(vty);
606 if (ret)
607 return ret;
608
609 return 0;
610}
611
612
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100613static struct cmd_node ns_bind_node = {
614 L_NS_BIND_NODE,
615 "%s(config-ns-bind)# ",
616 1,
617};
618
619DEFUN(cfg_ns_bind_listen, cfg_ns_bind_listen_cmd,
620 "listen " VTY_IPV46_CMD " <1-65535>",
Harald Welte2230a912021-03-04 20:09:50 +0100621 "Configure local IP + Port of this bind\n"
622 "Local IPv4 Address\n" "Local IPv6 Address\n"
623 "Local UDP Port\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100624 )
625{
626 struct vty_bind *vbind = vty->index;
627 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100628 int rc;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100629 const char *addr_str = argv[0];
630 unsigned int port = atoi(argv[1]);
631 struct osmo_sockaddr_str sockaddr_str;
632 struct osmo_sockaddr sockaddr;
633
634 if (vbind->ll != GPRS_NS2_LL_UDP) {
635 vty_out(vty, "listen can be only used with UDP bind%s",
636 VTY_NEWLINE);
637 return CMD_WARNING;
638 }
639
640 if (osmo_sockaddr_str_from_str(&sockaddr_str, addr_str, port)) {
641 vty_out(vty, "Can not parse the Address %s %s%s", argv[0], argv[1], VTY_NEWLINE);
642 return CMD_WARNING;
643 }
644 osmo_sockaddr_str_to_sockaddr(&sockaddr_str, &sockaddr.u.sas);
645 if (gprs_ns2_ip_bind_by_sockaddr(vty_nsi, &sockaddr)) {
646 vty_out(vty, "A bind with the specified address already exists!%s", VTY_NEWLINE);
647 return CMD_WARNING;
648 }
649
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100650 rc = gprs_ns2_ip_bind(vty_nsi, vbind->name, &sockaddr, vbind->dscp, &bind);
651 if (rc != 0) {
652 vty_out(vty, "Failed to create the bind (rc %d)!%s", rc, VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100653 return CMD_WARNING;
654 }
655
656 bind->accept_ipaccess = vbind->accept_ipaccess;
657 bind->accept_sns = vbind->accept_sns;
658
659 return CMD_SUCCESS;
660}
661
662DEFUN(cfg_no_ns_bind_listen, cfg_no_ns_bind_listen_cmd,
663 "no listen",
664 NO_STR
665 "Delete a IP/Port assignment\n"
666 )
667{
668 struct vty_bind *vbind = vty->index;
669 struct gprs_ns2_vc_bind *bind;
670
671 if (vbind->ll != GPRS_NS2_LL_UDP) {
672 vty_out(vty, "no listen can be only used with UDP bind%s", VTY_NEWLINE);
673 return CMD_WARNING;
674 }
675
676 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
677 if (!bind)
678 return CMD_ERR_NOTHING_TODO;
679
Daniel Willmann90432052021-01-26 16:09:18 +0100680 OSMO_ASSERT(bind->ll == GPRS_NS2_LL_UDP);
Alexander Couzens56287d22021-07-06 10:56:55 +0200681 gprs_ns2_free_bind(bind);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100682 return CMD_SUCCESS;
683}
684
685DEFUN(cfg_ns_bind_dscp, cfg_ns_bind_dscp_cmd,
Harald Weltec96d7162021-04-27 21:56:25 +0200686 "dscp <0-63>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100687 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
688{
689 struct vty_bind *vbind = vty->index;
690 struct gprs_ns2_vc_bind *bind;
691 uint16_t dscp = atoi(argv[0]);
692
693 if (vbind->ll != GPRS_NS2_LL_UDP) {
694 vty_out(vty, "dscp can be only used with UDP bind%s",
695 VTY_NEWLINE);
696 return CMD_WARNING;
697 }
698
699 vbind->dscp = dscp;
700 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
701 if (bind)
702 gprs_ns2_ip_bind_set_dscp(bind, dscp);
703
704 return CMD_SUCCESS;
705}
706
707DEFUN(cfg_no_ns_bind_dscp, cfg_no_ns_bind_dscp_cmd,
708 "no dscp",
709 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
710{
711 struct vty_bind *vbind = vty->index;
712 struct gprs_ns2_vc_bind *bind;
713 uint16_t dscp = 0;
714
715 if (vbind->ll != GPRS_NS2_LL_UDP) {
716 vty_out(vty, "dscp can be only used with UDP bind%s",
717 VTY_NEWLINE);
718 return CMD_WARNING;
719 }
720
721 vbind->dscp = dscp;
722 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
723 if (bind)
724 gprs_ns2_ip_bind_set_dscp(bind, dscp);
725
726 return CMD_SUCCESS;
727}
728
Harald Welted99e4ee2021-04-28 19:57:12 +0200729DEFUN(cfg_ns_bind_priority, cfg_ns_bind_priority_cmd,
Harald Welte5782fec2021-04-29 21:28:53 +0200730 "socket-priority <0-255>",
Harald Welted99e4ee2021-04-28 19:57:12 +0200731 "Set socket priority on the UDP socket\n" "Priority Value (>6 requires CAP_NET_ADMIN)\n")
732{
733 struct vty_bind *vbind = vty->index;
734 struct gprs_ns2_vc_bind *bind;
735 uint8_t prio = atoi(argv[0]);
736
737 if (vbind->ll != GPRS_NS2_LL_UDP) {
738 vty_out(vty, "dscp can be only used with UDP bind%s",
739 VTY_NEWLINE);
740 return CMD_WARNING;
741 }
742
743 vbind->priority = prio;
744 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
745 if (bind)
746 gprs_ns2_ip_bind_set_priority(bind, prio);
747
748 return CMD_SUCCESS;
749}
750
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100751DEFUN(cfg_ns_bind_ipaccess, cfg_ns_bind_ipaccess_cmd,
752 "accept-ipaccess",
753 "Allow to create dynamic NS Entity by NS Reset PDU on UDP (ip.access style)\n"
754 )
755{
756 struct vty_bind *vbind = vty->index;
757 struct gprs_ns2_vc_bind *bind;
758
759 if (vbind->ll != GPRS_NS2_LL_UDP) {
760 vty_out(vty, "accept-ipaccess can be only used with UDP bind%s",
761 VTY_NEWLINE);
762 return CMD_WARNING;
763 }
764
765 vbind->accept_ipaccess = true;
766 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
767 if (bind)
768 bind->accept_ipaccess = true;
769
770 return CMD_SUCCESS;
771}
772
773DEFUN(cfg_no_ns_bind_ipaccess, cfg_no_ns_bind_ipaccess_cmd,
774 "no accept-ipaccess",
775 NO_STR
776 "Reject NS Reset PDU on UDP (ip.access style)\n"
777 )
778{
779 struct vty_bind *vbind = vty->index;
780 struct gprs_ns2_vc_bind *bind;
781
782 if (vbind->ll != GPRS_NS2_LL_UDP) {
783 vty_out(vty, "no accept-ipaccess can be only used with UDP bind%s",
784 VTY_NEWLINE);
785 return CMD_WARNING;
786 }
787
788 vbind->accept_ipaccess = false;
789 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
790 if (bind)
791 bind->accept_ipaccess = false;
792
793 return CMD_SUCCESS;
794}
795
Harald Welte42e36462021-03-03 18:12:09 +0100796DEFUN(cfg_ns_bind_accept_sns, cfg_ns_bind_accept_sns_cmd,
797 "accept-dynamic-ip-sns",
798 "Allow to create dynamic NS Entities by IP-SNS PDUs\n"
799 )
800{
801 struct vty_bind *vbind = vty->index;
802 struct gprs_ns2_vc_bind *bind;
803
804 if (vbind->ll != GPRS_NS2_LL_UDP) {
805 vty_out(vty, "accept-dynamic-ip-sns can be only used with UDP bind%s",
806 VTY_NEWLINE);
807 return CMD_WARNING;
808 }
809
810 vbind->accept_sns = true;
811 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
812 if (bind)
813 bind->accept_sns = true;
814
815 return CMD_SUCCESS;
816}
817
818DEFUN(cfg_no_ns_bind_accept_sns, cfg_no_ns_bind_accept_sns_cmd,
819 "no accept-dynamic-ip-sns",
820 NO_STR
821 "Disable dynamic creation of NS Entities by IP-SNS PDUs\n"
822 )
823{
824 struct vty_bind *vbind = vty->index;
825 struct gprs_ns2_vc_bind *bind;
826
827 if (vbind->ll != GPRS_NS2_LL_UDP) {
828 vty_out(vty, "no accept-dynamic-ip-sns can be only used with UDP bind%s",
829 VTY_NEWLINE);
830 return CMD_WARNING;
831 }
832
833 vbind->accept_sns = false;
834 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
835 if (bind)
836 bind->accept_sns = false;
837
838 return CMD_SUCCESS;
839}
840
Alexander Couzensc4704762021-02-08 23:13:12 +0100841DEFUN(cfg_ns_bind_ip_sns_weight, cfg_ns_bind_ip_sns_weight_cmd,
842 "ip-sns signalling-weight <0-254> data-weight <0-254>",
843 "IP SNS\n"
844 "signalling weight used by IP-SNS dynamic configuration\n"
845 "signalling weight used by IP-SNS dynamic configuration\n"
846 "data weight used by IP-SNS dynamic configuration\n"
847 "data weight used by IP-SNS dynamic configuration\n")
848{
849 struct vty_bind *vbind = vty->index;
850 struct gprs_ns2_vc_bind *bind;
851
852 int signalling = atoi(argv[0]);
853 int data = atoi(argv[1]);
854
855 if (vbind->ll != GPRS_NS2_LL_UDP) {
856 vty_out(vty, "ip-sns signalling-weight <0-254> data-weight <0-254> can be only used with UDP bind%s",
857 VTY_NEWLINE);
858 return CMD_WARNING;
859 }
860
861 vbind->ip_sns_data_weight = data;
862 vbind->ip_sns_sig_weight = signalling;
863 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
864 if (bind)
865 gprs_ns2_ip_bind_set_sns_weight(bind, signalling, data);
866
867 return CMD_SUCCESS;
868}
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100869
870DEFUN(cfg_ns_bind_fr, cfg_ns_bind_fr_cmd,
871 "fr NETIF (fr|frnet)",
872 "frame relay\n"
873 IFNAME_STR
874 "fr (user) is used by BSS or SGSN attached to UNI of a FR network\n"
875 "frnet (network) is used by SGSN if BSS is directly attached\n"
876 )
877{
878 struct vty_bind *vbind = vty->index;
879 struct gprs_ns2_vc_bind *bind;
880 const char *netif = argv[0];
881 const char *role = argv[1];
882
883 int rc = 0;
884 enum osmo_fr_role frrole;
885
886 if (vbind->ll != GPRS_NS2_LL_FR) {
887 vty_out(vty, "fr can be only used with frame relay bind%s", VTY_NEWLINE);
888 return CMD_WARNING;
889 }
890
891 if (!strcmp(role, "fr"))
892 frrole = FR_ROLE_USER_EQUIPMENT;
893 else if (!strcmp(role, "frnet"))
894 frrole = FR_ROLE_NETWORK_EQUIPMENT;
895 else
896 return CMD_WARNING;
897
898 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
899 if (bind) {
900 vty_out(vty, "Interface %s already used.%s", netif, VTY_NEWLINE);
901 return CMD_WARNING;
902 }
903
904 rc = gprs_ns2_fr_bind(vty_nsi, vbind->name, netif, vty_fr_network, frrole, &bind);
905 if (rc < 0) {
906 LOGP(DLNS, LOGL_ERROR, "Failed to bind interface %s on fr. Err: %d\n", netif, rc);
907 return CMD_WARNING;
908 }
909
910 return CMD_SUCCESS;
911}
912
913DEFUN(cfg_no_ns_bind_fr, cfg_no_ns_bind_fr_cmd,
914 "no fr NETIF",
915 NO_STR
916 "Delete a frame relay link\n"
917 "Delete a frame relay link\n"
918 IFNAME_STR
919 )
920{
921 struct vty_bind *vbind = vty->index;
922 struct gprs_ns2_vc_bind *bind;
923 const char *netif = argv[0];
924
925 if (vbind->ll != GPRS_NS2_LL_FR) {
926 vty_out(vty, "fr can be only used with frame relay bind%s",
927 VTY_NEWLINE);
928 return CMD_WARNING;
929 }
930
931 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
932 if (!bind) {
933 vty_out(vty, "Interface not found.%s", VTY_NEWLINE);
934 return CMD_WARNING;
935 }
936
937 if (strcmp(bind->name, vbind->name)) {
938 vty_out(vty, "The specified interface is not bound to this bind.%s", VTY_NEWLINE);
939 return CMD_WARNING;
940 }
941
Alexander Couzens56287d22021-07-06 10:56:55 +0200942 gprs_ns2_free_bind(bind);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100943 return CMD_SUCCESS;
944}
945
946
947static struct cmd_node ns_nse_node = {
948 L_NS_NSE_NODE,
949 "%s(config-ns-nse)# ",
950 1,
951};
952
953DEFUN(cfg_ns_nse_nsvc_fr, cfg_ns_nse_nsvc_fr_cmd,
954 "nsvc fr NETIF dlci <16-1007> nsvci <0-65535>",
955 "NS Virtual Connection\n"
956 "frame relay\n"
957 "frame relay interface. Must be registered via fr vty\n"
958 NSVCI_STR
959 NSVCI_STR
960 DLCI_STR
961 DLCI_STR
962 )
963{
964 struct gprs_ns2_vc_bind *bind;
965 struct gprs_ns2_vc *nsvc;
966 struct gprs_ns2_nse *nse = vty->index;
967 const char *netif = argv[0];
968 uint16_t dlci = atoi(argv[1]);
969 uint16_t nsvci = atoi(argv[2]);
970 bool dialect_modified = false;
971 bool ll_modified = false;
972
973 if (nse->ll != GPRS_NS2_LL_FR && nse->ll != GPRS_NS2_LL_UNDEF) {
974 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
975 goto err;
976 }
977
978 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_RESETBLOCK && nse->dialect != GPRS_NS2_DIALECT_UNDEF) {
979 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
980 goto err;
981 }
982
983 if (nse->ll == GPRS_NS2_LL_UNDEF) {
984 nse->ll = GPRS_NS2_LL_FR;
985 ll_modified = true;
986 }
987
988 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +0100989 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_STATIC_RESETBLOCK);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100990 dialect_modified = true;
991 }
992
993
994 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
995 if (!bind) {
996 vty_out(vty, "Can not find fr interface \"%s\". Please configure it via fr vty.%s",
997 netif, VTY_NEWLINE);
998 goto err;
999 }
1000
1001 if (gprs_ns2_fr_nsvc_by_dlci(bind, dlci)) {
1002 vty_out(vty, "A NS-VC with the specified DLCI already exist!%s", VTY_NEWLINE);
1003 goto err;
1004 }
1005
1006 if (gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci)) {
1007 vty_out(vty, "A NS-VC with the specified NS-VCI already exist!%s", VTY_NEWLINE);
1008 goto err;
1009 }
1010
1011 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
1012 if (!nsvc) {
1013 /* Could not create NS-VC, connect failed */
1014 vty_out(vty, "Failed to create the NS-VC%s", VTY_NEWLINE);
1015 goto err;
1016 }
1017 nsvc->persistent = true;
1018 return CMD_SUCCESS;
1019
1020err:
1021 if (ll_modified)
1022 nse->ll = GPRS_NS2_LL_UNDEF;
1023 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001024 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001025
1026 return CMD_WARNING;
1027}
1028
1029DEFUN(cfg_no_ns_nse_nsvc_fr_dlci, cfg_no_ns_nse_nsvc_fr_dlci_cmd,
1030 "no nsvc fr NETIF dlci <16-1007>",
1031 NO_STR
1032 "Delete frame relay NS-VC\n"
1033 "frame relay\n"
1034 "frame relay interface. Must be registered via fr vty\n"
1035 DLCI_STR
1036 DLCI_STR
1037 )
1038{
1039 struct gprs_ns2_vc_bind *bind;
1040 struct gprs_ns2_vc *nsvc;
1041 struct gprs_ns2_nse *nse = vty->index;
1042 const char *netif = argv[0];
1043 uint16_t dlci = atoi(argv[1]);
1044
1045 if (nse->ll != GPRS_NS2_LL_FR) {
1046 vty_out(vty, "This NSE doesn't support frame relay.%s", VTY_NEWLINE);
1047 return CMD_WARNING;
1048 }
1049
1050 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
1051 if (!bind) {
1052 vty_out(vty, "Can not find fr interface \"%s\"%s",
1053 netif, VTY_NEWLINE);
1054 return CMD_ERR_NOTHING_TODO;
1055 }
1056
1057 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
1058 if (!nsvc) {
1059 vty_out(vty, "Can not find a NS-VC on fr interface %s with dlci %u%s",
1060 netif, dlci, VTY_NEWLINE);
1061 return CMD_WARNING;
1062 }
1063
1064 if (nse != nsvc->nse) {
1065 vty_out(vty, "The specified NS-VC is not a part of the NSE %u!%s"
1066 "To remove this NS-VC go to the vty node 'nse %u'%s",
1067 nse->nsei, VTY_NEWLINE,
1068 nsvc->nse->nsei, VTY_NEWLINE);
1069 return CMD_WARNING;
1070 }
1071
1072 gprs_ns2_free_nsvc(nsvc);
1073 if (llist_empty(&nse->nsvc)) {
1074 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001075 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001076 }
1077
1078 return CMD_SUCCESS;
1079}
1080
1081DEFUN(cfg_no_ns_nse_nsvci, cfg_no_ns_nse_nsvci_cmd,
1082 "no nsvc nsvci <0-65535>",
1083 NO_STR
1084 "Delete NSVC\n"
1085 NSVCI_STR
1086 NSVCI_STR
1087 )
1088{
1089 struct gprs_ns2_vc *nsvc;
1090 struct gprs_ns2_nse *nse = vty->index;
1091 uint16_t nsvci = atoi(argv[0]);
1092
1093 switch (nse->dialect) {
1094 case GPRS_NS2_DIALECT_SNS:
1095 case GPRS_NS2_DIALECT_STATIC_ALIVE:
1096 vty_out(vty, "NSE doesn't support NSVCI.%s", VTY_NEWLINE);
1097 return CMD_WARNING;
1098 case GPRS_NS2_DIALECT_UNDEF:
1099 vty_out(vty, "No NSVCs configured%s", VTY_NEWLINE);
1100 return CMD_WARNING;
1101 case GPRS_NS2_DIALECT_IPACCESS:
1102 case GPRS_NS2_DIALECT_STATIC_RESETBLOCK:
1103 break;
1104 }
1105
1106 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci);
1107 if (!nsvc) {
1108 vty_out(vty, "Can not find NS-VC with NS-VCI %u%s", nsvci, VTY_NEWLINE);
1109 return CMD_WARNING;
1110 }
1111
1112 if (nse != nsvc->nse) {
1113 vty_out(vty, "NS-VC with NS-VCI %u is not part of this NSE!%s",
1114 nsvci, VTY_NEWLINE);
1115 return CMD_WARNING;
1116 }
1117
1118 gprs_ns2_free_nsvc(nsvc);
1119 if (llist_empty(&nse->nsvc)) {
1120 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001121 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001122 }
1123
1124 return CMD_SUCCESS;
1125}
1126
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001127static int ns_nse_nsvc_udp_cmds(struct vty *vty, const char *bind_name, const char *remote_char, uint16_t port,
1128 uint16_t sig_weight, uint16_t data_weight)
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001129{
1130 struct gprs_ns2_vc_bind *bind;
1131 struct gprs_ns2_vc *nsvc;
1132 struct gprs_ns2_nse *nse = vty->index;
1133 bool dialect_modified = false;
1134 bool ll_modified = false;
1135
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001136 struct osmo_sockaddr_str remote_str;
1137 struct osmo_sockaddr remote;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001138
1139 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1140 nse->ll = GPRS_NS2_LL_UDP;
1141 ll_modified = true;
1142 }
1143
1144 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001145 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_STATIC_ALIVE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001146 dialect_modified = true;
1147 }
1148
1149 if (nse->ll != GPRS_NS2_LL_UDP) {
1150 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1151 goto err;
1152 }
1153
1154 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
1155 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1156 goto err;
1157 }
1158
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001159 if (osmo_sockaddr_str_from_str(&remote_str, remote_char, port)) {
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001160 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1161 goto err;
1162 }
1163
1164 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1165 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1166 goto err;
1167 }
1168
1169 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1170 if (!bind) {
1171 vty_out(vty, "Can not find bind with name %s%s",
1172 bind_name, VTY_NEWLINE);
1173 goto err;
1174 }
1175
1176 if (bind->ll != GPRS_NS2_LL_UDP) {
1177 vty_out(vty, "Bind %s is not an UDP bind.%s",
1178 bind_name, VTY_NEWLINE);
1179 goto err;
1180 }
1181
Alexander Couzens7bb39e32021-02-16 23:06:53 +01001182 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1183 if (nsvc) {
1184 if (nsvc->nse == nse)
1185 vty_out(vty, "Specified NSVC is already present in this NSE.%s", VTY_NEWLINE);
1186 else
1187 vty_out(vty, "Specified NSVC is already present in another NSE%05u.%s", nsvc->nse->nsei, VTY_NEWLINE);
1188 goto err;
1189 }
1190
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001191 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, 0);
1192 if (!nsvc) {
1193 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
1194 goto err;
1195 }
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001196 nsvc->sig_weight = sig_weight;
1197 nsvc->data_weight = data_weight;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001198 nsvc->persistent = true;
1199
1200 return CMD_SUCCESS;
1201
1202err:
1203 if (ll_modified)
1204 nse->ll = GPRS_NS2_LL_UNDEF;
1205 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001206 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001207 return CMD_WARNING;
1208}
1209
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001210DEFUN(cfg_ns_nse_nsvc_udp, cfg_ns_nse_nsvc_udp_cmd,
1211 "nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
1212 "NS Virtual Connection\n"
1213 "NS over UDP\n"
1214 "A unique bind identifier created by ns bind\n"
1215 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1216 "Remote UDP Port\n")
1217{
1218 const char *bind_name = argv[0];
1219 const char *remote = argv[1];
1220 uint16_t port = atoi(argv[2]);
1221 uint16_t sig_weight = 1;
1222 uint16_t data_weight = 1;
1223
1224 return ns_nse_nsvc_udp_cmds(vty, bind_name, remote, port, sig_weight, data_weight);
1225}
1226
1227DEFUN(cfg_ns_nse_nsvc_udp_weights, cfg_ns_nse_nsvc_udp_weights_cmd,
1228 "nsvc udp BIND " VTY_IPV46_CMD " <1-65535> signalling-weight <0-254> data-weight <0-254>",
1229 "NS Virtual Connection\n"
1230 "NS over UDP\n"
1231 "A unique bind identifier created by ns bind\n"
1232 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1233 "Remote UDP Port\n"
1234 "Signalling weight of the NSVC (default = 1)\n"
1235 "Signalling weight of the NSVC (default = 1)\n"
1236 "Data weight of the NSVC (default = 1)\n"
1237 "Data weight of the NSVC (default = 1)\n"
1238 )
1239{
1240 const char *bind_name = argv[0];
1241 const char *remote = argv[1];
1242 uint16_t port = atoi(argv[2]);
1243 uint16_t sig_weight = atoi(argv[3]);
1244 uint16_t data_weight = atoi(argv[4]);
1245
1246 return ns_nse_nsvc_udp_cmds(vty, bind_name, remote, port, sig_weight, data_weight);
1247}
1248
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001249DEFUN(cfg_no_ns_nse_nsvc_udp, cfg_no_ns_nse_nsvc_udp_cmd,
1250 "no nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
1251 NO_STR
1252 "Delete a NS Virtual Connection\n"
1253 "NS over UDP\n"
1254 "A unique bind identifier created by ns bind\n"
1255 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1256 "Remote UDP Port\n"
1257 )
1258{
1259 struct gprs_ns2_vc_bind *bind;
1260 struct gprs_ns2_vc *nsvc;
1261 struct gprs_ns2_nse *nse = vty->index;
1262 const char *bind_name = argv[0];
1263 struct osmo_sockaddr_str remote_str;
1264 struct osmo_sockaddr remote;
1265 uint16_t port = atoi(argv[2]);
1266
1267 if (nse->ll != GPRS_NS2_LL_UDP) {
1268 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1269 return CMD_WARNING;
1270 }
1271
1272 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
1273 vty_out(vty, "This NSE doesn't support UDP with dialect static alive.%s", VTY_NEWLINE);
1274 return CMD_WARNING;
1275 }
1276
1277 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1278 if (!bind) {
1279 vty_out(vty, "Can not find bind with name %s%s",
1280 bind_name, VTY_NEWLINE);
1281 return CMD_WARNING;
1282 }
1283
1284 if (bind->ll != GPRS_NS2_LL_UDP) {
1285 vty_out(vty, "Bind %s is not an UDP bind.%s",
1286 bind_name, VTY_NEWLINE);
1287 return CMD_WARNING;
1288 }
1289
1290 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1291 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1292 return CMD_WARNING;
1293 }
1294
1295 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1296 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1297 return CMD_WARNING;
1298 }
1299
1300 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1301 if (!nsvc) {
1302 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1303 remote_str.ip, remote_str.port, VTY_NEWLINE);
1304 return CMD_WARNING;
1305 }
1306
1307 if (!nsvc->persistent) {
1308 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1309 remote_str.ip, remote_str.port, VTY_NEWLINE);
1310 return CMD_WARNING;
1311 }
1312
1313 if (nsvc->nse != nse) {
1314 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1315 return CMD_WARNING;
1316 }
1317
1318 gprs_ns2_free_nsvc(nsvc);
1319 if (llist_empty(&nse->nsvc)) {
1320 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001321 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001322 }
1323
1324 return CMD_SUCCESS;
1325}
1326
1327DEFUN(cfg_ns_nse_nsvc_ipa, cfg_ns_nse_nsvc_ipa_cmd,
1328 "nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>" ,
1329 "NS Virtual Connection\n"
1330 "NS over UDP ip.access style (uses RESET/BLOCK)\n"
1331 "A unique bind identifier created by ns bind\n"
1332 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1333 "Remote UDP Port\n"
1334 NSVCI_STR
1335 NSVCI_STR
1336 )
1337{
1338 struct gprs_ns2_vc_bind *bind;
1339 struct gprs_ns2_vc *nsvc;
1340 struct gprs_ns2_nse *nse = vty->index;
1341 bool dialect_modified = false;
1342 bool ll_modified = false;
1343
1344 const char *bind_name = argv[0];
1345 struct osmo_sockaddr_str remote_str;
1346 struct osmo_sockaddr remote;
1347 uint16_t port = atoi(argv[2]);
1348 uint16_t nsvci = atoi(argv[3]);
1349
1350 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1351 nse->ll = GPRS_NS2_LL_UDP;
1352 ll_modified = true;
1353 }
1354
1355 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001356 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_IPACCESS);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001357 dialect_modified = true;
1358 }
1359
1360 if (nse->ll != GPRS_NS2_LL_UDP) {
1361 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1362 goto err;
1363 }
1364
1365 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1366 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1367 goto err;
1368 }
1369
1370 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1371 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1372 goto err;
1373 }
1374
1375 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1376 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1377 goto err;
1378 }
1379
1380 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1381 if (!bind) {
1382 vty_out(vty, "Can not find bind with name %s%s",
1383 bind_name, VTY_NEWLINE);
1384 goto err;
1385 }
1386
1387 if (bind->ll != GPRS_NS2_LL_UDP) {
1388 vty_out(vty, "Bind %s is not an UDP bind.%s",
1389 bind_name, VTY_NEWLINE);
1390 goto err;
1391 }
1392
1393 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, nsvci);
1394 if (!nsvc) {
1395 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
1396 goto err;
1397 }
1398 nsvc->persistent = true;
1399
1400 return CMD_SUCCESS;
1401
1402err:
1403 if (ll_modified)
1404 nse->ll = GPRS_NS2_LL_UNDEF;
1405 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001406 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001407 return CMD_WARNING;
1408}
1409
1410DEFUN(cfg_no_ns_nse_nsvc_ipa, cfg_no_ns_nse_nsvc_ipa_cmd,
1411 "no nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>",
1412 NO_STR
1413 "Delete a NS Virtual Connection\n"
1414 "NS over UDP\n"
1415 "A unique bind identifier created by ns bind\n"
1416 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1417 "Remote UDP Port\n"
1418 NSVCI_STR
1419 NSVCI_STR
1420 )
1421{
1422 struct gprs_ns2_vc_bind *bind;
1423 struct gprs_ns2_vc *nsvc;
1424 struct gprs_ns2_nse *nse = vty->index;
1425 const char *bind_name = argv[0];
1426 struct osmo_sockaddr_str remote_str;
1427 struct osmo_sockaddr remote;
1428 uint16_t port = atoi(argv[2]);
1429 uint16_t nsvci = atoi(argv[3]);
1430
1431 if (nse->ll != GPRS_NS2_LL_UDP) {
1432 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1433 return CMD_WARNING;
1434 }
1435
1436 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1437 vty_out(vty, "This NSE doesn't support UDP with dialect ipaccess.%s", VTY_NEWLINE);
1438 return CMD_WARNING;
1439 }
1440
1441 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1442 if (!bind) {
1443 vty_out(vty, "Can not find bind with name %s%s",
1444 bind_name, VTY_NEWLINE);
1445 return CMD_WARNING;
1446 }
1447
1448 if (bind->ll != GPRS_NS2_LL_UDP) {
1449 vty_out(vty, "Bind %s is not an UDP bind.%s",
1450 bind_name, VTY_NEWLINE);
1451 return CMD_WARNING;
1452 }
1453
1454 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1455 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1456 return CMD_WARNING;
1457 }
1458
1459 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1460 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1461 return CMD_WARNING;
1462 }
1463
1464 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1465 if (!nsvc) {
1466 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1467 remote_str.ip, remote_str.port, VTY_NEWLINE);
1468 return CMD_WARNING;
1469 }
1470
1471 if (!nsvc->persistent) {
1472 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1473 remote_str.ip, remote_str.port, VTY_NEWLINE);
1474 return CMD_WARNING;
1475 }
1476
1477 if (nsvc->nse != nse) {
1478 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1479 return CMD_WARNING;
1480 }
1481
1482 if (!nsvc->nsvci_is_valid) {
1483 vty_out(vty, "NS-VC doesn't have a nsvci!%s", VTY_NEWLINE);
1484 return CMD_WARNING;
1485 }
1486
1487 if (nsvc->nsvci != nsvci) {
1488 vty_out(vty, "NS-VC has a different nsvci (%u)!%s",
1489 nsvc->nsvci, VTY_NEWLINE);
1490 return CMD_WARNING;
1491 }
1492
1493 gprs_ns2_free_nsvc(nsvc);
1494 if (llist_empty(&nse->nsvc)) {
1495 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001496 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001497 }
1498
1499 return CMD_SUCCESS;
1500}
1501
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001502DEFUN(cfg_ns_nse_ip_sns_remote, cfg_ns_nse_ip_sns_remote_cmd,
1503 "ip-sns-remote " VTY_IPV46_CMD " <1-65535>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001504 "SNS Initial Endpoint\n"
1505 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1506 "SGSN UDP Port\n"
1507 )
1508{
1509 struct gprs_ns2_nse *nse = vty->index;
1510 bool dialect_modified = false;
1511 bool ll_modified = false;
1512 int rc;
1513
1514 /* argv[0] */
1515 struct osmo_sockaddr_str remote_str;
1516 struct osmo_sockaddr remote;
1517 uint16_t port = atoi(argv[1]);
1518
1519 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1520 nse->ll = GPRS_NS2_LL_UDP;
1521 ll_modified = true;
1522 }
1523
1524 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001525 if (ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_SNS) < 0)
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001526 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001527 dialect_modified = true;
1528 }
1529
1530 if (nse->ll != GPRS_NS2_LL_UDP) {
1531 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1532 goto err;
1533 }
1534
1535 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1536 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1537 goto err;
1538 }
1539
1540 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1541 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1542 goto err;
1543 }
1544
1545 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1546 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1547 goto err;
1548 }
1549
1550 rc = gprs_ns2_sns_add_endpoint(nse, &remote);
1551 switch (rc) {
1552 case 0:
1553 return CMD_SUCCESS;
1554 case -EADDRINUSE:
1555 vty_out(vty, "Specified SNS endpoint already part of the NSE.%s", VTY_NEWLINE);
1556 return CMD_WARNING;
1557 default:
1558 vty_out(vty, "Can not add specified SNS endpoint.%s", VTY_NEWLINE);
1559 return CMD_WARNING;
1560 }
1561
1562err:
1563 if (ll_modified)
1564 nse->ll = GPRS_NS2_LL_UNDEF;
1565 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001566 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001567 return CMD_WARNING;
1568}
1569
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001570DEFUN(cfg_no_ns_nse_ip_sns_remote, cfg_no_ns_nse_ip_sns_remote_cmd,
1571 "no ip-sns-remote " VTY_IPV46_CMD " <1-65535>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001572 NO_STR
1573 "Delete a SNS Initial Endpoint\n"
1574 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1575 "SGSN UDP Port\n"
1576 )
1577{
1578 struct gprs_ns2_nse *nse = vty->index;
1579 struct osmo_sockaddr_str remote_str; /* argv[0] */
1580 struct osmo_sockaddr remote;
1581 uint16_t port = atoi(argv[1]);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001582
1583 if (nse->ll != GPRS_NS2_LL_UDP) {
1584 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1585 return CMD_WARNING;
1586 }
1587
1588 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1589 vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%s", VTY_NEWLINE);
1590 return CMD_WARNING;
1591 }
1592
1593 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1594 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1595 return CMD_WARNING;
1596 }
1597
1598 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1599 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1600 return CMD_WARNING;
1601 }
1602
1603 if (gprs_ns2_sns_del_endpoint(nse, &remote)) {
1604 vty_out(vty, "Can not remove specified SNS endpoint.%s", VTY_NEWLINE);
1605 return CMD_WARNING;
1606 }
1607
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001608 if (vty_nse_check_sns(nse)) {
1609 /* there is still sns configuration valid */
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001610 return CMD_SUCCESS;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001611 } else {
1612 /* clean up nse to allow other nsvc commands */
Harald Welte06d9bf92021-03-05 10:20:11 +01001613 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001614 nse->ll = GPRS_NS2_LL_UNDEF;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001615 }
1616
1617 return CMD_SUCCESS;
1618}
1619
Harald Welted164ef82021-03-04 22:29:17 +01001620/* add all IP-SNS default binds to the given NSE */
1621int ns2_sns_add_sns_default_binds(struct gprs_ns2_nse *nse)
1622{
1623 struct vty_nse_bind *vnse_bind;
1624 int count = 0;
1625
1626 OSMO_ASSERT(nse->ll == GPRS_NS2_LL_UDP);
1627 OSMO_ASSERT(nse->dialect == GPRS_NS2_DIALECT_SNS);
1628
1629 llist_for_each_entry(vnse_bind, &ip_sns_default_binds, list) {
1630 struct gprs_ns2_vc_bind *bind = gprs_ns2_bind_by_name(vty_nsi, vnse_bind->vbind->name);
1631 /* the bind might not yet created because "listen" is missing. */
1632 if (!bind)
1633 continue;
1634 gprs_ns2_sns_add_bind(nse, bind);
1635 count++;
1636 }
1637 return count;
1638}
1639
1640DEFUN(cfg_ns_ip_sns_default_bind, cfg_ns_ip_sns_default_bind_cmd,
1641 "ip-sns-default bind ID",
1642 "Defaults for dynamically created NSEs created by IP-SNS in SGSN role\n"
1643 "IP SNS binds\n"
1644 "Name of NS udp bind whose IP endpoint will be used as IP-SNS local endpoint. Can be given multiple times.\n")
1645{
1646 struct vty_bind *vbind;
1647 struct vty_nse_bind *vnse_bind;
1648 const char *name = argv[0];
1649
1650 vbind = vty_bind_by_name(name);
1651 if (!vbind) {
1652 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1653 return CMD_WARNING;
1654 }
1655
1656 if (vbind->ll != GPRS_NS2_LL_UDP) {
1657 vty_out(vty, "ip-sns-default bind can only be used with UDP bind%s", VTY_NEWLINE);
1658 return CMD_WARNING;
1659 }
1660
1661 llist_for_each_entry(vnse_bind, &ip_sns_default_binds, list) {
1662 if (vnse_bind->vbind == vbind)
1663 return CMD_SUCCESS;
1664 }
1665
1666 vnse_bind = talloc(vty_nsi, struct vty_nse_bind);
1667 if (!vnse_bind)
1668 return CMD_WARNING;
1669 vnse_bind->vbind = vbind;
1670
1671 llist_add_tail(&vnse_bind->list, &ip_sns_default_binds);
1672
1673 return CMD_SUCCESS;
1674}
1675
1676DEFUN(cfg_no_ns_ip_sns_default_bind, cfg_no_ns_ip_sns_default_bind_cmd,
1677 "no ip-sns-default bind ID",
1678 NO_STR "Defaults for dynamically created NSEs created by IP-SNS in SGSN role\n"
1679 "IP SNS binds\n"
1680 "Name of NS udp bind whose IP endpoint will be removed as IP-SNS local endpoint.\n")
1681{
1682 struct vty_bind *vbind;
1683 struct vty_nse_bind *vnse_bind;
1684 const char *name = argv[0];
1685
1686 vbind = vty_bind_by_name(name);
1687 if (!vbind) {
1688 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1689 return CMD_WARNING;
1690 }
1691
1692 if (vbind->ll != GPRS_NS2_LL_UDP) {
1693 vty_out(vty, "ip-sns-default bind can only be used with UDP bind%s", VTY_NEWLINE);
1694 return CMD_WARNING;
1695 }
1696
1697 llist_for_each_entry(vnse_bind, &ip_sns_default_binds, list) {
1698 if (vnse_bind->vbind == vbind) {
1699 llist_del(&vnse_bind->list);
1700 talloc_free(vnse_bind);
1701 return CMD_SUCCESS;
1702 }
1703 }
1704
1705 vty_out(vty, "Bind '%s' was not an ip-sns-default bind%s", name, VTY_NEWLINE);
1706 return CMD_WARNING;
1707}
1708
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001709DEFUN(cfg_ns_nse_ip_sns_bind, cfg_ns_nse_ip_sns_bind_cmd,
1710 "ip-sns-bind BINDID",
1711 "IP SNS binds\n"
Harald Welte2230a912021-03-04 20:09:50 +01001712 "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 +01001713{
1714 struct gprs_ns2_nse *nse = vty->index;
1715 struct gprs_ns2_vc_bind *bind;
1716 struct vty_bind *vbind;
1717 struct vty_nse *vnse;
1718 const char *name = argv[0];
1719 bool ll_modified = false;
1720 bool dialect_modified = false;
1721 int rc;
1722
1723 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1724 nse->ll = GPRS_NS2_LL_UDP;
1725 ll_modified = true;
1726 }
1727
1728 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001729 if (ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_SNS) < 0)
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001730 goto err;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001731 dialect_modified = true;
1732 }
1733
1734 if (nse->ll != GPRS_NS2_LL_UDP) {
1735 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1736 goto err;
1737 }
1738
1739 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1740 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1741 goto err;
1742 }
1743
1744 vbind = vty_bind_by_name(name);
1745 if (!vbind) {
1746 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1747 goto err;
1748 }
1749
1750 if (vbind->ll != GPRS_NS2_LL_UDP) {
1751 vty_out(vty, "ip-sns-bind can only be used with UDP bind%s",
1752 VTY_NEWLINE);
1753 goto err;
1754 }
1755
1756 /* the vnse has been created together when creating the nse node. The parent node should check this already! */
1757 vnse = vty_nse_by_nsei(nse->nsei);
1758 OSMO_ASSERT(vnse);
1759
1760 rc = vty_nse_add_vbind(vnse, vbind);
1761 switch (rc) {
1762 case 0:
1763 break;
1764 case -EALREADY:
1765 vty_out(vty, "Failed to add ip-sns-bind %s already present%s", name, VTY_NEWLINE);
1766 goto err;
1767 case -ENOMEM:
1768 vty_out(vty, "Failed to add ip-sns-bind %s out of memory%s", name, VTY_NEWLINE);
1769 goto err;
1770 default:
1771 vty_out(vty, "Failed to add ip-sns-bind %s! %d%s", name, rc, VTY_NEWLINE);
1772 goto err;
1773 }
1774
1775 /* the bind might not yet created because "listen" is missing. */
1776 bind = gprs_ns2_bind_by_name(vty_nsi, name);
1777 if (!bind)
1778 return CMD_SUCCESS;
1779
1780 rc = gprs_ns2_sns_add_bind(nse, bind);
1781 switch (rc) {
1782 case 0:
1783 break;
1784 case -EALREADY:
1785 vty_out(vty, "Failed to add ip-sns-bind %s already present%s", name, VTY_NEWLINE);
1786 goto err;
1787 case -ENOMEM:
1788 vty_out(vty, "Failed to add ip-sns-bind %s out of memory%s", name, VTY_NEWLINE);
1789 goto err;
1790 default:
1791 vty_out(vty, "Failed to add ip-sns-bind %s! %d%s", name, rc, VTY_NEWLINE);
1792 goto err;
1793 }
1794
1795 return CMD_SUCCESS;
1796err:
1797 if (ll_modified)
1798 nse->ll = GPRS_NS2_LL_UNDEF;
1799 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001800 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001801
1802 return CMD_WARNING;
1803}
1804
1805DEFUN(cfg_no_ns_nse_ip_sns_bind, cfg_no_ns_nse_ip_sns_bind_cmd,
1806 "no ip-sns-bind BINDID",
1807 NO_STR
1808 "IP SNS binds\n"
Harald Welte2230a912021-03-04 20:09:50 +01001809 "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 +01001810{
1811 struct gprs_ns2_nse *nse = vty->index;
1812 struct gprs_ns2_vc_bind *bind;
1813 struct vty_bind *vbind;
1814 struct vty_nse *vnse;
1815 const char *name = argv[0];
1816 int rc;
1817
1818 if (nse->ll != GPRS_NS2_LL_UDP) {
1819 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1820 return CMD_WARNING;
1821 }
1822
1823 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1824 vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%s", VTY_NEWLINE);
1825 return CMD_WARNING;
1826 }
1827
1828 vbind = vty_bind_by_name(name);
1829 if (!vbind) {
1830 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1831 return CMD_WARNING;
1832 }
1833
1834 if (vbind->ll != GPRS_NS2_LL_UDP) {
1835 vty_out(vty, "no ip-sns-bind can only be used with UDP bind%s",
1836 VTY_NEWLINE);
1837 return CMD_WARNING;
1838 }
1839
1840 /* the vnse has been created together when creating the nse node. The parent node should check this already! */
1841 vnse = vty_nse_by_nsei(nse->nsei);
1842 OSMO_ASSERT(vnse);
1843
1844 rc = vty_nse_remove_vbind(vnse, vbind);
1845 switch(rc) {
1846 case 0:
1847 break;
1848 case -ENOENT:
1849 vty_out(vty, "Bind %s is not part of this NSE%s", name, VTY_NEWLINE);
1850 return CMD_WARNING;
1851 case -EINVAL:
1852 vty_out(vty, "no ip-sns-bind can only be used with UDP bind%s",
1853 VTY_NEWLINE);
1854 return CMD_WARNING;
1855 default:
1856 return CMD_WARNING;
1857 }
1858
1859 /* the bind might not exists yet */
1860 bind = gprs_ns2_bind_by_name(vty_nsi, name);
1861 if (bind)
1862 gprs_ns2_sns_del_bind(nse, bind);
1863
1864 if (!vty_nse_check_sns(nse)) {
1865 /* clean up nse to allow other nsvc commands */
Harald Welte06d9bf92021-03-05 10:20:11 +01001866 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001867 nse->ll = GPRS_NS2_LL_UNDEF;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001868 }
1869
1870 return CMD_SUCCESS;
1871}
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001872
1873/* non-config commands */
Alexander Couzens75b61882021-03-21 16:18:17 +01001874void ns2_vty_dump_nsvc(struct vty *vty, struct gprs_ns2_vc *nsvc, bool stats)
Alexander Couzens6a161492020-07-12 13:45:50 +02001875{
Harald Weltedc2d0802020-12-01 18:17:28 +01001876 char nsvci_str[32];
1877
1878 if (nsvc->nsvci_is_valid)
1879 snprintf(nsvci_str, sizeof(nsvci_str), "%05u", nsvc->nsvci);
1880 else
1881 snprintf(nsvci_str, sizeof(nsvci_str), "none");
1882
Alexander Couzens1dd9cbf2021-03-21 16:22:08 +01001883 vty_out(vty, " NSVCI %s: %s %s data_weight=%u sig_weight=%u %s%s", nsvci_str,
Harald Weltedc2d0802020-12-01 18:17:28 +01001884 osmo_fsm_inst_state_name(nsvc->fi),
1885 nsvc->persistent ? "PERSIST" : "DYNAMIC",
1886 nsvc->data_weight, nsvc->sig_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}