blob: 4bd7cdefb32dad1bb5b8cbfc800a6114875b862a [file] [log] [blame]
Alexander Couzens6a161492020-07-12 13:45:50 +02001/*! \file gprs_ns2_vty.c
2 * VTY interface for our GPRS Networks Service (NS) implementation. */
3
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01004/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
Alexander Couzens6a161492020-07-12 13:45:50 +02005 * Author: Alexander Couzens <lynxis@fe80.eu>
6 *
7 * All Rights Reserved
8 *
9 * SPDX-License-Identifier: GPL-2.0+
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 *
24 */
25
26#include <stdlib.h>
27#include <unistd.h>
28#include <errno.h>
29#include <stdint.h>
30
31#include <arpa/inet.h>
Alexander Couzens841817e2020-11-19 00:41:29 +010032#include <net/if.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020033
Alexander Couzens6a161492020-07-12 13:45:50 +020034#include <osmocom/core/byteswap.h>
Daniel Willmanndbab7142020-11-18 14:19:56 +010035#include <osmocom/core/fsm.h>
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010036#include <osmocom/core/linuxlist.h>
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010037#include <osmocom/core/msgb.h>
38#include <osmocom/core/rate_ctr.h>
39#include <osmocom/core/select.h>
40#include <osmocom/core/talloc.h>
41#include <osmocom/core/sockaddr_str.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020042#include <osmocom/core/socket.h>
Alexander Couzens841817e2020-11-19 00:41:29 +010043#include <osmocom/gprs/frame_relay.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020044#include <osmocom/gprs/gprs_ns2.h>
45#include <osmocom/gsm/tlv.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020046#include <osmocom/vty/command.h>
47#include <osmocom/vty/logging.h>
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010048#include <osmocom/vty/misc.h>
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010049#include <osmocom/vty/telnet_interface.h>
50#include <osmocom/vty/vty.h>
Alexander Couzens6a161492020-07-12 13:45:50 +020051
52#include "gprs_ns2_internal.h"
53
Daniel Willmanncb3e9b52020-12-02 15:50:22 +010054#define SHOW_NS_STR "Display information about the NS protocol\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010055#define NSVCI_STR "NS Virtual Connection ID (NS-VCI)\n"
56#define DLCI_STR "Data Link connection identifier\n"
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010057
58static struct gprs_ns2_inst *vty_nsi = NULL;
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010059static struct osmo_fr_network *vty_fr_network = NULL;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010060static struct llist_head binds;
Alexander Couzens6b9d2322021-02-12 03:17:59 +010061static struct llist_head nses;
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +010062
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010063struct vty_bind {
64 struct llist_head list;
65 const char *name;
66 enum gprs_ns2_ll ll;
67 int dscp;
68 bool accept_ipaccess;
69 bool accept_sns;
Alexander Couzensc4704762021-02-08 23:13:12 +010070 uint8_t ip_sns_sig_weight;
71 uint8_t ip_sns_data_weight;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010072};
73
Alexander Couzens6b9d2322021-02-12 03:17:59 +010074struct vty_nse {
75 struct llist_head list;
76 uint16_t nsei;
77 /* list of binds which are valid for this nse. Only IP-SNS uses this
78 * to allow `no listen ..` in the bind context. So "half" created binds are valid for
79 * IP-SNS. This allows changing the bind ip without modifying all NSEs afterwards */
80 struct llist_head binds;
81};
82
83/* used by IP-SNS to connect multiple vty_nse_bind to a vty_nse */
84struct vty_nse_bind {
85 struct llist_head list;
86 struct vty_bind *vbind;
87};
88
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010089/* TODO: this should into osmo timer */
Alexander Couzens6a161492020-07-12 13:45:50 +020090static const struct value_string gprs_ns_timer_strs[] = {
91 { 0, "tns-block" },
92 { 1, "tns-block-retries" },
93 { 2, "tns-reset" },
94 { 3, "tns-reset-retries" },
95 { 4, "tns-test" },
96 { 5, "tns-alive" },
97 { 6, "tns-alive-retries" },
98 { 7, "tsns-prov" },
Harald Welte33c3c062020-12-16 11:59:19 +010099 { 8, "tsns-size-retries" },
100 { 9, "tsns-config-retries" },
Alexander Couzens6a161492020-07-12 13:45:50 +0200101 { 0, NULL }
102};
103
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100104const struct value_string vty_fr_role_names[] = {
105 { FR_ROLE_USER_EQUIPMENT, "fr" },
106 { FR_ROLE_NETWORK_EQUIPMENT, "frnet" },
107 { 0, NULL }
108};
109
110const struct value_string vty_ll_names[] = {
111 { GPRS_NS2_LL_FR, "fr" },
112 { GPRS_NS2_LL_FR_GRE, "frgre" },
113 { GPRS_NS2_LL_UDP, "udp" },
114 { 0, NULL }
115};
116
117static struct vty_bind *vty_bind_by_name(const char *name)
Daniel Willmann751977b2020-12-02 18:59:44 +0100118{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100119 struct vty_bind *vbind;
120 llist_for_each_entry(vbind, &binds, list) {
Alexander Couzensb7921732021-02-12 03:08:42 +0100121 if (!strcmp(vbind->name, name))
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100122 return vbind;
Daniel Willmann751977b2020-12-02 18:59:44 +0100123 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100124 return NULL;
Daniel Willmann751977b2020-12-02 18:59:44 +0100125}
126
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100127static struct vty_bind *vty_bind_alloc(const char *name)
Alexander Couzens6a161492020-07-12 13:45:50 +0200128{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100129 struct vty_bind *vbind = talloc_zero(vty_nsi, struct vty_bind);
130 if (!vbind)
131 return NULL;
132
133 vbind->name = talloc_strdup(vty_nsi, name);
134 if (!vbind->name) {
135 talloc_free(vbind);
136 return NULL;
Alexander Couzens6a161492020-07-12 13:45:50 +0200137 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100138
Alexander Couzensc4704762021-02-08 23:13:12 +0100139 vbind->ip_sns_sig_weight = 1;
140 vbind->ip_sns_data_weight = 1;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100141 llist_add(&vbind->list, &binds);
142 return vbind;
143}
144
145static void vty_bind_free(struct vty_bind *vbind)
146{
147 if (!vbind)
148 return;
149
150 llist_del(&vbind->list);
Alexander Couzens3e2e4a02021-02-09 16:15:06 +0100151 talloc_free(vbind);
Alexander Couzens6a161492020-07-12 13:45:50 +0200152}
153
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100154static struct vty_nse *vty_nse_by_nsei(uint16_t nsei)
155{
156 struct vty_nse *vnse;
157 llist_for_each_entry(vnse, &nses, list) {
158 if (vnse->nsei == nsei)
159 return vnse;
160 }
161 return NULL;
162}
163
164static struct vty_nse *vty_nse_alloc(uint16_t nsei)
165{
166 struct vty_nse *vnse = talloc_zero(vty_nsi, struct vty_nse);
167 if (!vnse)
168 return NULL;
169
170 vnse->nsei = nsei;
171 INIT_LLIST_HEAD(&vnse->binds);
172 llist_add(&vnse->list, &nses);
173 return vnse;
174}
175
176static void vty_nse_free(struct vty_nse *vnse)
177{
178 if (!vnse)
179 return;
180
181 llist_del(&vnse->list);
182 /* all vbind of the nse will be freed by talloc */
183 talloc_free(vnse);
184}
185
186static int vty_nse_add_vbind(struct vty_nse *vnse, struct vty_bind *vbind)
187{
188 struct vty_nse_bind *vnse_bind;
189
190 if (vbind->ll != GPRS_NS2_LL_UDP)
191 return -EINVAL;
192
193 llist_for_each_entry(vnse_bind, &vnse->binds, list) {
194 if (vnse_bind->vbind == vbind)
195 return -EALREADY;
196 }
197
198 vnse_bind = talloc(vnse, struct vty_nse_bind);
199 if (!vnse_bind)
200 return -ENOMEM;
201 vnse_bind->vbind = vbind;
202
203 llist_add_tail(&vnse_bind->list, &vnse->binds);
204 return 0;
205}
206
207static int vty_nse_remove_vbind(struct vty_nse *vnse, struct vty_bind *vbind)
208{
209 struct vty_nse_bind *vnse_bind, *tmp;
210 if (vbind->ll != GPRS_NS2_LL_UDP)
211 return -EINVAL;
212
213 llist_for_each_entry_safe(vnse_bind, tmp, &vnse->binds, list) {
214 if (vnse_bind->vbind == vbind) {
215 llist_del(&vnse_bind->list);
216 talloc_free(vnse_bind);
217 }
218 }
219
220 return -ENOENT;
221}
222
223/* check if the NSE still has SNS configuration */
224static bool vty_nse_check_sns(struct gprs_ns2_nse *nse) {
225 struct vty_nse *vnse = vty_nse_by_nsei(nse->nsei);
226
227 int count = gprs_ns2_sns_count(nse);
228 if (count > 0) {
229 /* there are other sns endpoints */
230 return true;
231 }
232
233 if (!vnse)
234 return false;
235
236 if (llist_empty(&vnse->binds))
237 return false;
238
239 return true;
240}
241
Alexander Couzens6a161492020-07-12 13:45:50 +0200242static struct cmd_node ns_node = {
243 L_NS_NODE,
244 "%s(config-ns)# ",
245 1,
246};
247
Alexander Couzens6a161492020-07-12 13:45:50 +0200248DEFUN(cfg_ns, cfg_ns_cmd,
249 "ns",
250 "Configure the GPRS Network Service")
251{
252 vty->node = L_NS_NODE;
253 return CMD_SUCCESS;
254}
255
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100256DEFUN(cfg_ns_timer, cfg_ns_timer_cmd,
257 "timer " NS_TIMERS " <0-65535>",
258 "Network Service Timer\n"
259 NS_TIMERS_HELP "Timer Value\n")
260{
261 int idx = get_string_value(gprs_ns_timer_strs, argv[0]);
262 int val = atoi(argv[1]);
263
264 if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout))
265 return CMD_WARNING;
266
267 vty_nsi->timeout[idx] = val;
268
269 return CMD_SUCCESS;
270}
271
272DEFUN(cfg_ns_nsei, cfg_ns_nsei_cmd,
273 "nse <0-65535>",
274 "Persistent NS Entity\n"
275 "NS Entity ID (NSEI)\n"
276 )
277{
278 struct gprs_ns2_nse *nse;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100279 struct vty_nse *vnse;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100280 uint16_t nsei = atoi(argv[0]);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100281 bool free_vnse = false;
282
283 vnse = vty_nse_by_nsei(nsei);
284 if (!vnse) {
285 vnse = vty_nse_alloc(nsei);
286 if (!vnse) {
287 vty_out(vty, "Failed to create vty NSE!%s", VTY_NEWLINE);
288 return CMD_ERR_INCOMPLETE;
289 }
290 free_vnse = true;
291 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100292
293 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
294 if (!nse) {
295 nse = gprs_ns2_create_nse(vty_nsi, nsei, GPRS_NS2_LL_UNDEF, GPRS_NS2_DIALECT_UNDEF);
296 if (!nse) {
297 vty_out(vty, "Failed to create NSE!%s", VTY_NEWLINE);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100298 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100299 }
300 nse->persistent = true;
301 }
302
303 if (!nse->persistent) {
304 /* TODO: should the dynamic NSE removed? */
305 vty_out(vty, "A dynamic NSE with the specified NSEI already exists%s", VTY_NEWLINE);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100306 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100307 }
308
309 vty->node = L_NS_NSE_NODE;
310 vty->index = nse;
311
312 return CMD_SUCCESS;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100313
314err:
315 if (free_vnse)
316 talloc_free(vnse);
317
318 return CMD_ERR_INCOMPLETE;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100319}
320
321DEFUN(cfg_no_ns_nsei, cfg_no_ns_nsei_cmd,
322 "no nse <0-65535>",
323 NO_STR
324 "Delete a Persistent NS Entity\n"
325 "NS Entity ID (NSEI)\n"
326 )
327{
328 struct gprs_ns2_nse *nse;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100329 struct vty_nse *vnse;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100330 uint16_t nsei = atoi(argv[0]);
331
332 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
333 if (!nse) {
334 vty_out(vty, "Can not find NS Entity %s%s", argv[0], VTY_NEWLINE);
335 return CMD_ERR_NOTHING_TODO;
336 }
337
338 if (!nse->persistent) {
339 vty_out(vty, "Ignoring non-persistent NS Entity%s", VTY_NEWLINE);
340 return CMD_WARNING;
341 }
342
343 vty_out(vty, "Deleting NS Entity %u%s", nse->nsei, VTY_NEWLINE);
344 gprs_ns2_free_nse(nse);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100345
346 vnse = vty_nse_by_nsei(nsei);
347 vty_nse_free(vnse);
348
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100349 return CMD_SUCCESS;
350}
351
352/* TODO: add fr/gre */
353DEFUN(cfg_ns_bind, cfg_ns_bind_cmd,
354 "bind (fr|udp) ID",
355 "Binding\n"
356 "Frame Relay\n" "UDP/IP\n"
357 "a unique identifier for this bind to reference NS-VCs\n"
358 )
359{
360 const char *nstype = argv[0];
361 const char *name = argv[1];
362 struct vty_bind *vbind;
363 enum gprs_ns2_ll ll;
364 int rc;
365
366 rc = get_string_value(vty_ll_names, nstype);
367 if (rc < 0)
368 return CMD_WARNING;
369 ll = (enum gprs_ns2_ll) rc;
370
371 if (!osmo_identifier_valid(name)) {
372 vty_out(vty, "Invalid ID. The ID should be only alphanumeric.%s", VTY_NEWLINE);
373 return CMD_WARNING;
374 }
375
376 vbind = vty_bind_by_name(name);
377 if (vbind) {
378 if (vbind->ll != ll) {
379 vty_out(vty, "A bind with the specified ID already exists with a different type (fr|frgre|udp)!%s",
380 VTY_NEWLINE);
381 return CMD_WARNING;
382 }
383 } else {
384 vbind = vty_bind_alloc(name);
385 if (!vbind) {
386 vty_out(vty, "Can not create bind - out of memory%s", VTY_NEWLINE);
387 return CMD_WARNING;
388 }
389 vbind->ll = ll;
390 }
391
392 vty->index = vbind;
393 vty->node = L_NS_BIND_NODE;
394
395 return CMD_SUCCESS;
396}
397
398DEFUN(cfg_no_ns_bind, cfg_no_ns_bind_cmd,
399 "no bind ID",
400 NO_STR
401 "Delete a binding\n"
402 "a unique identifier for this bind to reference NS-VCs\n"
403 )
404{
405 struct vty_bind *vbind;
406 struct gprs_ns2_vc_bind *bind;
407 const char *name = argv[0];
408
409 vbind = vty_bind_by_name(name);
410 if (!vbind) {
411 vty_out(vty, "bind %s does not exist!%s", name, VTY_NEWLINE);
412 return CMD_WARNING;
413 }
414 vty_bind_free(vbind);
415 bind = gprs_ns2_bind_by_name(vty_nsi, name);
416 if (bind)
417 bind->driver->free_bind(bind);
418 return CMD_SUCCESS;
419}
420
421
422static void config_write_vbind(struct vty *vty, struct vty_bind *vbind)
423{
424 struct gprs_ns2_vc_bind *bind;
425 const struct osmo_sockaddr *addr;
426 struct osmo_sockaddr_str addr_str;
427 const char *netif, *frrole_str, *llstr;
428 enum osmo_fr_role frrole;
429
430 llstr = get_value_string_or_null(vty_ll_names, vbind->ll);
431 if (!llstr)
432 return;
433 vty_out(vty, " bind %s %s%s", llstr, vbind->name, VTY_NEWLINE);
434
435 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
436 switch (vbind->ll) {
437 case GPRS_NS2_LL_FR:
438 if (bind) {
439 netif = gprs_ns2_fr_bind_netif(bind);
440 if (!netif)
441 return;
442 frrole = gprs_ns2_fr_bind_role(bind);
443 if ((int) frrole == -1)
444 return;
445 frrole_str = get_value_string_or_null(vty_fr_role_names, frrole);
446 if (netif && frrole_str)
447 vty_out(vty, " fr %s %s%s", netif, frrole_str, VTY_NEWLINE);
448 }
449 break;
450 case GPRS_NS2_LL_UDP:
451 if (bind) {
452 addr = gprs_ns2_ip_bind_sockaddr(bind);
453 if (!osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas)) {
454 vty_out(vty, " listen %s %u%s", addr_str.ip, addr_str.port,
455 VTY_NEWLINE);
456 }
457 }
458 if (vbind->accept_ipaccess)
459 vty_out(vty, " accept-ipaccess%s", VTY_NEWLINE);
460 if (vbind->dscp)
461 vty_out(vty, " dscp %u%s", vbind->dscp, VTY_NEWLINE);
Daniel Willmann64db6362021-02-12 12:21:45 +0100462 vty_out(vty, " ip-sns signalling-weight %u data-weight %u%s",
Alexander Couzensc4704762021-02-08 23:13:12 +0100463 vbind->ip_sns_sig_weight, vbind->ip_sns_data_weight, VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100464 break;
465 default:
466 return;
467 }
468}
469
470static void config_write_nsvc(struct vty *vty, const struct gprs_ns2_vc *nsvc)
471{
472 const char *netif;
473 uint16_t dlci;
474 const struct osmo_sockaddr *addr;
475 struct osmo_sockaddr_str addr_str;
476
477 switch (nsvc->nse->ll) {
478 case GPRS_NS2_LL_UNDEF:
479 break;
480 case GPRS_NS2_LL_UDP:
481 switch (nsvc->nse->dialect) {
482 case GPRS_NS2_DIALECT_IPACCESS:
483 addr = gprs_ns2_ip_vc_remote(nsvc);
484 if (!addr)
485 break;
486 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas))
487 break;
488 vty_out(vty, " nsvc ipa %s %s %u nsvci %u%s",
489 nsvc->bind->name, addr_str.ip, addr_str.port,
490 nsvc->nsvci, VTY_NEWLINE);
491 break;
492 case GPRS_NS2_DIALECT_STATIC_ALIVE:
493 addr = gprs_ns2_ip_vc_remote(nsvc);
494 if (!addr)
495 break;
496 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas))
497 break;
498 vty_out(vty, " nsvc udp %s %s %u%s",
499 nsvc->bind->name, addr_str.ip, addr_str.port, VTY_NEWLINE);
500 break;
501 default:
502 break;
503 }
504 break;
505 case GPRS_NS2_LL_FR:
506 netif = gprs_ns2_fr_bind_netif(nsvc->bind);
507 if (!netif)
508 break;
509 dlci = gprs_ns2_fr_nsvc_dlci(nsvc);
510 if (!dlci)
511 break;
512 OSMO_ASSERT(nsvc->nsvci_is_valid);
513 vty_out(vty, " nsvc fr %s dlci %u nsvci %u%s",
514 netif, dlci, nsvc->nsvci, VTY_NEWLINE);
515 break;
516 case GPRS_NS2_LL_FR_GRE:
517 break;
518 }
519}
520
521static void _config_write_ns_nse(struct vty *vty, struct gprs_ns2_nse *nse)
522{
523 struct gprs_ns2_vc *nsvc;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100524 struct vty_nse *vnse = vty_nse_by_nsei(nse->nsei);
525 struct vty_nse_bind *vbind;
526
527 OSMO_ASSERT(vnse);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100528
529 vty_out(vty, " nse %u%s", nse->nsei, VTY_NEWLINE);
530 switch (nse->dialect) {
531 case GPRS_NS2_DIALECT_SNS:
532 ns2_sns_write_vty(vty, nse);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100533 llist_for_each_entry(vbind, &vnse->binds, list) {
534 vty_out(vty, " ip-sns-bind %s%s", vbind->vbind->name, VTY_NEWLINE);
535 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100536 break;
537 default:
538 llist_for_each_entry(nsvc, &nse->nsvc, list) {
539 config_write_nsvc(vty, nsvc);
540 }
541 break;
542 }
543}
544
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100545static int config_write_ns_nse(struct vty *vty)
546{
547 struct gprs_ns2_nse *nse;
548
549 llist_for_each_entry(nse, &vty_nsi->nse, list) {
550 if (!nse->persistent)
551 continue;
552
553 _config_write_ns_nse(vty, nse);
554 }
555
556 return 0;
557}
558
559static int config_write_ns_bind(struct vty *vty)
560{
561 struct vty_bind *vbind;
562
563 llist_for_each_entry(vbind, &binds, list) {
564 config_write_vbind(vty, vbind);
565 }
566
567 return 0;
568}
569
Alexander Couzens260cd522021-01-28 20:31:31 +0100570static int config_write_ns(struct vty *vty)
571{
572 unsigned int i;
573 int ret;
574
575 vty_out(vty, "ns%s", VTY_NEWLINE);
576
577 for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++)
578 vty_out(vty, " timer %s %u%s",
579 get_value_string(gprs_ns_timer_strs, i),
580 vty_nsi->timeout[i], VTY_NEWLINE);
581
582 ret = config_write_ns_bind(vty);
583 if (ret)
584 return ret;
585
586 ret = config_write_ns_nse(vty);
587 if (ret)
588 return ret;
589
590 return 0;
591}
592
593
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100594static struct cmd_node ns_bind_node = {
595 L_NS_BIND_NODE,
596 "%s(config-ns-bind)# ",
597 1,
598};
599
600DEFUN(cfg_ns_bind_listen, cfg_ns_bind_listen_cmd,
601 "listen " VTY_IPV46_CMD " <1-65535>",
602 "Binding\n"
603 "IPv4 Address\n" "IPv6 Address\n"
604 "Port\n"
605 )
606{
607 struct vty_bind *vbind = vty->index;
608 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100609 int rc;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100610 const char *addr_str = argv[0];
611 unsigned int port = atoi(argv[1]);
612 struct osmo_sockaddr_str sockaddr_str;
613 struct osmo_sockaddr sockaddr;
614
615 if (vbind->ll != GPRS_NS2_LL_UDP) {
616 vty_out(vty, "listen can be only used with UDP bind%s",
617 VTY_NEWLINE);
618 return CMD_WARNING;
619 }
620
621 if (osmo_sockaddr_str_from_str(&sockaddr_str, addr_str, port)) {
622 vty_out(vty, "Can not parse the Address %s %s%s", argv[0], argv[1], VTY_NEWLINE);
623 return CMD_WARNING;
624 }
625 osmo_sockaddr_str_to_sockaddr(&sockaddr_str, &sockaddr.u.sas);
626 if (gprs_ns2_ip_bind_by_sockaddr(vty_nsi, &sockaddr)) {
627 vty_out(vty, "A bind with the specified address already exists!%s", VTY_NEWLINE);
628 return CMD_WARNING;
629 }
630
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100631 rc = gprs_ns2_ip_bind(vty_nsi, vbind->name, &sockaddr, vbind->dscp, &bind);
632 if (rc != 0) {
633 vty_out(vty, "Failed to create the bind (rc %d)!%s", rc, VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100634 return CMD_WARNING;
635 }
636
637 bind->accept_ipaccess = vbind->accept_ipaccess;
638 bind->accept_sns = vbind->accept_sns;
639
640 return CMD_SUCCESS;
641}
642
643DEFUN(cfg_no_ns_bind_listen, cfg_no_ns_bind_listen_cmd,
644 "no listen",
645 NO_STR
646 "Delete a IP/Port assignment\n"
647 )
648{
649 struct vty_bind *vbind = vty->index;
650 struct gprs_ns2_vc_bind *bind;
651
652 if (vbind->ll != GPRS_NS2_LL_UDP) {
653 vty_out(vty, "no listen can be only used with UDP bind%s", VTY_NEWLINE);
654 return CMD_WARNING;
655 }
656
657 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
658 if (!bind)
659 return CMD_ERR_NOTHING_TODO;
660
Daniel Willmann90432052021-01-26 16:09:18 +0100661 OSMO_ASSERT(bind->ll == GPRS_NS2_LL_UDP);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100662 bind->driver->free_bind(bind);
663 return CMD_SUCCESS;
664}
665
666DEFUN(cfg_ns_bind_dscp, cfg_ns_bind_dscp_cmd,
667 "dscp <0-255>",
668 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
669{
670 struct vty_bind *vbind = vty->index;
671 struct gprs_ns2_vc_bind *bind;
672 uint16_t dscp = atoi(argv[0]);
673
674 if (vbind->ll != GPRS_NS2_LL_UDP) {
675 vty_out(vty, "dscp can be only used with UDP bind%s",
676 VTY_NEWLINE);
677 return CMD_WARNING;
678 }
679
680 vbind->dscp = dscp;
681 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
682 if (bind)
683 gprs_ns2_ip_bind_set_dscp(bind, dscp);
684
685 return CMD_SUCCESS;
686}
687
688DEFUN(cfg_no_ns_bind_dscp, cfg_no_ns_bind_dscp_cmd,
689 "no dscp",
690 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
691{
692 struct vty_bind *vbind = vty->index;
693 struct gprs_ns2_vc_bind *bind;
694 uint16_t dscp = 0;
695
696 if (vbind->ll != GPRS_NS2_LL_UDP) {
697 vty_out(vty, "dscp can be only used with UDP bind%s",
698 VTY_NEWLINE);
699 return CMD_WARNING;
700 }
701
702 vbind->dscp = dscp;
703 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
704 if (bind)
705 gprs_ns2_ip_bind_set_dscp(bind, dscp);
706
707 return CMD_SUCCESS;
708}
709
710DEFUN(cfg_ns_bind_ipaccess, cfg_ns_bind_ipaccess_cmd,
711 "accept-ipaccess",
712 "Allow to create dynamic NS Entity by NS Reset PDU on UDP (ip.access style)\n"
713 )
714{
715 struct vty_bind *vbind = vty->index;
716 struct gprs_ns2_vc_bind *bind;
717
718 if (vbind->ll != GPRS_NS2_LL_UDP) {
719 vty_out(vty, "accept-ipaccess can be only used with UDP bind%s",
720 VTY_NEWLINE);
721 return CMD_WARNING;
722 }
723
724 vbind->accept_ipaccess = true;
725 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
726 if (bind)
727 bind->accept_ipaccess = true;
728
729 return CMD_SUCCESS;
730}
731
732DEFUN(cfg_no_ns_bind_ipaccess, cfg_no_ns_bind_ipaccess_cmd,
733 "no accept-ipaccess",
734 NO_STR
735 "Reject NS Reset PDU on UDP (ip.access style)\n"
736 )
737{
738 struct vty_bind *vbind = vty->index;
739 struct gprs_ns2_vc_bind *bind;
740
741 if (vbind->ll != GPRS_NS2_LL_UDP) {
742 vty_out(vty, "no accept-ipaccess can be only used with UDP bind%s",
743 VTY_NEWLINE);
744 return CMD_WARNING;
745 }
746
747 vbind->accept_ipaccess = false;
748 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
749 if (bind)
750 bind->accept_ipaccess = false;
751
752 return CMD_SUCCESS;
753}
754
Alexander Couzensc4704762021-02-08 23:13:12 +0100755DEFUN(cfg_ns_bind_ip_sns_weight, cfg_ns_bind_ip_sns_weight_cmd,
756 "ip-sns signalling-weight <0-254> data-weight <0-254>",
757 "IP SNS\n"
758 "signalling weight used by IP-SNS dynamic configuration\n"
759 "signalling weight used by IP-SNS dynamic configuration\n"
760 "data weight used by IP-SNS dynamic configuration\n"
761 "data weight used by IP-SNS dynamic configuration\n")
762{
763 struct vty_bind *vbind = vty->index;
764 struct gprs_ns2_vc_bind *bind;
765
766 int signalling = atoi(argv[0]);
767 int data = atoi(argv[1]);
768
769 if (vbind->ll != GPRS_NS2_LL_UDP) {
770 vty_out(vty, "ip-sns signalling-weight <0-254> data-weight <0-254> can be only used with UDP bind%s",
771 VTY_NEWLINE);
772 return CMD_WARNING;
773 }
774
775 vbind->ip_sns_data_weight = data;
776 vbind->ip_sns_sig_weight = signalling;
777 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
778 if (bind)
779 gprs_ns2_ip_bind_set_sns_weight(bind, signalling, data);
780
781 return CMD_SUCCESS;
782}
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100783
784DEFUN(cfg_ns_bind_fr, cfg_ns_bind_fr_cmd,
785 "fr NETIF (fr|frnet)",
786 "frame relay\n"
787 IFNAME_STR
788 "fr (user) is used by BSS or SGSN attached to UNI of a FR network\n"
789 "frnet (network) is used by SGSN if BSS is directly attached\n"
790 )
791{
792 struct vty_bind *vbind = vty->index;
793 struct gprs_ns2_vc_bind *bind;
794 const char *netif = argv[0];
795 const char *role = argv[1];
796
797 int rc = 0;
798 enum osmo_fr_role frrole;
799
800 if (vbind->ll != GPRS_NS2_LL_FR) {
801 vty_out(vty, "fr can be only used with frame relay bind%s", VTY_NEWLINE);
802 return CMD_WARNING;
803 }
804
805 if (!strcmp(role, "fr"))
806 frrole = FR_ROLE_USER_EQUIPMENT;
807 else if (!strcmp(role, "frnet"))
808 frrole = FR_ROLE_NETWORK_EQUIPMENT;
809 else
810 return CMD_WARNING;
811
812 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
813 if (bind) {
814 vty_out(vty, "Interface %s already used.%s", netif, VTY_NEWLINE);
815 return CMD_WARNING;
816 }
817
818 rc = gprs_ns2_fr_bind(vty_nsi, vbind->name, netif, vty_fr_network, frrole, &bind);
819 if (rc < 0) {
820 LOGP(DLNS, LOGL_ERROR, "Failed to bind interface %s on fr. Err: %d\n", netif, rc);
821 return CMD_WARNING;
822 }
823
824 return CMD_SUCCESS;
825}
826
827DEFUN(cfg_no_ns_bind_fr, cfg_no_ns_bind_fr_cmd,
828 "no fr NETIF",
829 NO_STR
830 "Delete a frame relay link\n"
831 "Delete a frame relay link\n"
832 IFNAME_STR
833 )
834{
835 struct vty_bind *vbind = vty->index;
836 struct gprs_ns2_vc_bind *bind;
837 const char *netif = argv[0];
838
839 if (vbind->ll != GPRS_NS2_LL_FR) {
840 vty_out(vty, "fr can be only used with frame relay bind%s",
841 VTY_NEWLINE);
842 return CMD_WARNING;
843 }
844
845 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
846 if (!bind) {
847 vty_out(vty, "Interface not found.%s", VTY_NEWLINE);
848 return CMD_WARNING;
849 }
850
851 if (strcmp(bind->name, vbind->name)) {
852 vty_out(vty, "The specified interface is not bound to this bind.%s", VTY_NEWLINE);
853 return CMD_WARNING;
854 }
855
856 bind->driver->free_bind(bind);
857 return CMD_SUCCESS;
858}
859
860
861static struct cmd_node ns_nse_node = {
862 L_NS_NSE_NODE,
863 "%s(config-ns-nse)# ",
864 1,
865};
866
867DEFUN(cfg_ns_nse_nsvc_fr, cfg_ns_nse_nsvc_fr_cmd,
868 "nsvc fr NETIF dlci <16-1007> nsvci <0-65535>",
869 "NS Virtual Connection\n"
870 "frame relay\n"
871 "frame relay interface. Must be registered via fr vty\n"
872 NSVCI_STR
873 NSVCI_STR
874 DLCI_STR
875 DLCI_STR
876 )
877{
878 struct gprs_ns2_vc_bind *bind;
879 struct gprs_ns2_vc *nsvc;
880 struct gprs_ns2_nse *nse = vty->index;
881 const char *netif = argv[0];
882 uint16_t dlci = atoi(argv[1]);
883 uint16_t nsvci = atoi(argv[2]);
884 bool dialect_modified = false;
885 bool ll_modified = false;
886
887 if (nse->ll != GPRS_NS2_LL_FR && nse->ll != GPRS_NS2_LL_UNDEF) {
888 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
889 goto err;
890 }
891
892 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_RESETBLOCK && nse->dialect != GPRS_NS2_DIALECT_UNDEF) {
893 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
894 goto err;
895 }
896
897 if (nse->ll == GPRS_NS2_LL_UNDEF) {
898 nse->ll = GPRS_NS2_LL_FR;
899 ll_modified = true;
900 }
901
902 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
903 nse->dialect = GPRS_NS2_DIALECT_STATIC_RESETBLOCK;
904 dialect_modified = true;
905 }
906
907
908 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
909 if (!bind) {
910 vty_out(vty, "Can not find fr interface \"%s\". Please configure it via fr vty.%s",
911 netif, VTY_NEWLINE);
912 goto err;
913 }
914
915 if (gprs_ns2_fr_nsvc_by_dlci(bind, dlci)) {
916 vty_out(vty, "A NS-VC with the specified DLCI already exist!%s", VTY_NEWLINE);
917 goto err;
918 }
919
920 if (gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci)) {
921 vty_out(vty, "A NS-VC with the specified NS-VCI already exist!%s", VTY_NEWLINE);
922 goto err;
923 }
924
925 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
926 if (!nsvc) {
927 /* Could not create NS-VC, connect failed */
928 vty_out(vty, "Failed to create the NS-VC%s", VTY_NEWLINE);
929 goto err;
930 }
931 nsvc->persistent = true;
932 return CMD_SUCCESS;
933
934err:
935 if (ll_modified)
936 nse->ll = GPRS_NS2_LL_UNDEF;
937 if (dialect_modified)
938 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
939
940 return CMD_WARNING;
941}
942
943DEFUN(cfg_no_ns_nse_nsvc_fr_dlci, cfg_no_ns_nse_nsvc_fr_dlci_cmd,
944 "no nsvc fr NETIF dlci <16-1007>",
945 NO_STR
946 "Delete frame relay NS-VC\n"
947 "frame relay\n"
948 "frame relay interface. Must be registered via fr vty\n"
949 DLCI_STR
950 DLCI_STR
951 )
952{
953 struct gprs_ns2_vc_bind *bind;
954 struct gprs_ns2_vc *nsvc;
955 struct gprs_ns2_nse *nse = vty->index;
956 const char *netif = argv[0];
957 uint16_t dlci = atoi(argv[1]);
958
959 if (nse->ll != GPRS_NS2_LL_FR) {
960 vty_out(vty, "This NSE doesn't support frame relay.%s", VTY_NEWLINE);
961 return CMD_WARNING;
962 }
963
964 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
965 if (!bind) {
966 vty_out(vty, "Can not find fr interface \"%s\"%s",
967 netif, VTY_NEWLINE);
968 return CMD_ERR_NOTHING_TODO;
969 }
970
971 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
972 if (!nsvc) {
973 vty_out(vty, "Can not find a NS-VC on fr interface %s with dlci %u%s",
974 netif, dlci, VTY_NEWLINE);
975 return CMD_WARNING;
976 }
977
978 if (nse != nsvc->nse) {
979 vty_out(vty, "The specified NS-VC is not a part of the NSE %u!%s"
980 "To remove this NS-VC go to the vty node 'nse %u'%s",
981 nse->nsei, VTY_NEWLINE,
982 nsvc->nse->nsei, VTY_NEWLINE);
983 return CMD_WARNING;
984 }
985
986 gprs_ns2_free_nsvc(nsvc);
987 if (llist_empty(&nse->nsvc)) {
988 nse->ll = GPRS_NS2_LL_UNDEF;
989 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
990 }
991
992 return CMD_SUCCESS;
993}
994
995DEFUN(cfg_no_ns_nse_nsvci, cfg_no_ns_nse_nsvci_cmd,
996 "no nsvc nsvci <0-65535>",
997 NO_STR
998 "Delete NSVC\n"
999 NSVCI_STR
1000 NSVCI_STR
1001 )
1002{
1003 struct gprs_ns2_vc *nsvc;
1004 struct gprs_ns2_nse *nse = vty->index;
1005 uint16_t nsvci = atoi(argv[0]);
1006
1007 switch (nse->dialect) {
1008 case GPRS_NS2_DIALECT_SNS:
1009 case GPRS_NS2_DIALECT_STATIC_ALIVE:
1010 vty_out(vty, "NSE doesn't support NSVCI.%s", VTY_NEWLINE);
1011 return CMD_WARNING;
1012 case GPRS_NS2_DIALECT_UNDEF:
1013 vty_out(vty, "No NSVCs configured%s", VTY_NEWLINE);
1014 return CMD_WARNING;
1015 case GPRS_NS2_DIALECT_IPACCESS:
1016 case GPRS_NS2_DIALECT_STATIC_RESETBLOCK:
1017 break;
1018 }
1019
1020 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci);
1021 if (!nsvc) {
1022 vty_out(vty, "Can not find NS-VC with NS-VCI %u%s", nsvci, VTY_NEWLINE);
1023 return CMD_WARNING;
1024 }
1025
1026 if (nse != nsvc->nse) {
1027 vty_out(vty, "NS-VC with NS-VCI %u is not part of this NSE!%s",
1028 nsvci, VTY_NEWLINE);
1029 return CMD_WARNING;
1030 }
1031
1032 gprs_ns2_free_nsvc(nsvc);
1033 if (llist_empty(&nse->nsvc)) {
1034 nse->ll = GPRS_NS2_LL_UNDEF;
1035 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1036 }
1037
1038 return CMD_SUCCESS;
1039}
1040
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001041static int ns_nse_nsvc_udp_cmds(struct vty *vty, const char *bind_name, const char *remote_char, uint16_t port,
1042 uint16_t sig_weight, uint16_t data_weight)
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001043{
1044 struct gprs_ns2_vc_bind *bind;
1045 struct gprs_ns2_vc *nsvc;
1046 struct gprs_ns2_nse *nse = vty->index;
1047 bool dialect_modified = false;
1048 bool ll_modified = false;
1049
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001050 struct osmo_sockaddr_str remote_str;
1051 struct osmo_sockaddr remote;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001052
1053 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1054 nse->ll = GPRS_NS2_LL_UDP;
1055 ll_modified = true;
1056 }
1057
1058 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
1059 nse->dialect = GPRS_NS2_DIALECT_STATIC_ALIVE;
1060 dialect_modified = true;
1061 }
1062
1063 if (nse->ll != GPRS_NS2_LL_UDP) {
1064 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1065 goto err;
1066 }
1067
1068 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
1069 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1070 goto err;
1071 }
1072
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001073 if (osmo_sockaddr_str_from_str(&remote_str, remote_char, port)) {
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001074 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1075 goto err;
1076 }
1077
1078 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1079 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1080 goto err;
1081 }
1082
1083 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1084 if (!bind) {
1085 vty_out(vty, "Can not find bind with name %s%s",
1086 bind_name, VTY_NEWLINE);
1087 goto err;
1088 }
1089
1090 if (bind->ll != GPRS_NS2_LL_UDP) {
1091 vty_out(vty, "Bind %s is not an UDP bind.%s",
1092 bind_name, VTY_NEWLINE);
1093 goto err;
1094 }
1095
1096 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, 0);
1097 if (!nsvc) {
1098 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
1099 goto err;
1100 }
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001101 nsvc->sig_weight = sig_weight;
1102 nsvc->data_weight = data_weight;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001103 nsvc->persistent = true;
1104
1105 return CMD_SUCCESS;
1106
1107err:
1108 if (ll_modified)
1109 nse->ll = GPRS_NS2_LL_UNDEF;
1110 if (dialect_modified)
1111 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1112 return CMD_WARNING;
1113}
1114
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001115DEFUN(cfg_ns_nse_nsvc_udp, cfg_ns_nse_nsvc_udp_cmd,
1116 "nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
1117 "NS Virtual Connection\n"
1118 "NS over UDP\n"
1119 "A unique bind identifier created by ns bind\n"
1120 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1121 "Remote UDP Port\n")
1122{
1123 const char *bind_name = argv[0];
1124 const char *remote = argv[1];
1125 uint16_t port = atoi(argv[2]);
1126 uint16_t sig_weight = 1;
1127 uint16_t data_weight = 1;
1128
1129 return ns_nse_nsvc_udp_cmds(vty, bind_name, remote, port, sig_weight, data_weight);
1130}
1131
1132DEFUN(cfg_ns_nse_nsvc_udp_weights, cfg_ns_nse_nsvc_udp_weights_cmd,
1133 "nsvc udp BIND " VTY_IPV46_CMD " <1-65535> signalling-weight <0-254> data-weight <0-254>",
1134 "NS Virtual Connection\n"
1135 "NS over UDP\n"
1136 "A unique bind identifier created by ns bind\n"
1137 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1138 "Remote UDP Port\n"
1139 "Signalling weight of the NSVC (default = 1)\n"
1140 "Signalling weight of the NSVC (default = 1)\n"
1141 "Data weight of the NSVC (default = 1)\n"
1142 "Data weight of the NSVC (default = 1)\n"
1143 )
1144{
1145 const char *bind_name = argv[0];
1146 const char *remote = argv[1];
1147 uint16_t port = atoi(argv[2]);
1148 uint16_t sig_weight = atoi(argv[3]);
1149 uint16_t data_weight = atoi(argv[4]);
1150
1151 return ns_nse_nsvc_udp_cmds(vty, bind_name, remote, port, sig_weight, data_weight);
1152}
1153
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001154DEFUN(cfg_no_ns_nse_nsvc_udp, cfg_no_ns_nse_nsvc_udp_cmd,
1155 "no nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
1156 NO_STR
1157 "Delete a NS Virtual Connection\n"
1158 "NS over UDP\n"
1159 "A unique bind identifier created by ns bind\n"
1160 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1161 "Remote UDP Port\n"
1162 )
1163{
1164 struct gprs_ns2_vc_bind *bind;
1165 struct gprs_ns2_vc *nsvc;
1166 struct gprs_ns2_nse *nse = vty->index;
1167 const char *bind_name = argv[0];
1168 struct osmo_sockaddr_str remote_str;
1169 struct osmo_sockaddr remote;
1170 uint16_t port = atoi(argv[2]);
1171
1172 if (nse->ll != GPRS_NS2_LL_UDP) {
1173 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1174 return CMD_WARNING;
1175 }
1176
1177 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
1178 vty_out(vty, "This NSE doesn't support UDP with dialect static alive.%s", VTY_NEWLINE);
1179 return CMD_WARNING;
1180 }
1181
1182 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1183 if (!bind) {
1184 vty_out(vty, "Can not find bind with name %s%s",
1185 bind_name, VTY_NEWLINE);
1186 return CMD_WARNING;
1187 }
1188
1189 if (bind->ll != GPRS_NS2_LL_UDP) {
1190 vty_out(vty, "Bind %s is not an UDP bind.%s",
1191 bind_name, VTY_NEWLINE);
1192 return CMD_WARNING;
1193 }
1194
1195 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1196 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1197 return CMD_WARNING;
1198 }
1199
1200 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1201 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1202 return CMD_WARNING;
1203 }
1204
1205 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1206 if (!nsvc) {
1207 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1208 remote_str.ip, remote_str.port, VTY_NEWLINE);
1209 return CMD_WARNING;
1210 }
1211
1212 if (!nsvc->persistent) {
1213 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1214 remote_str.ip, remote_str.port, VTY_NEWLINE);
1215 return CMD_WARNING;
1216 }
1217
1218 if (nsvc->nse != nse) {
1219 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1220 return CMD_WARNING;
1221 }
1222
1223 gprs_ns2_free_nsvc(nsvc);
1224 if (llist_empty(&nse->nsvc)) {
1225 nse->ll = GPRS_NS2_LL_UNDEF;
1226 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1227 }
1228
1229 return CMD_SUCCESS;
1230}
1231
1232DEFUN(cfg_ns_nse_nsvc_ipa, cfg_ns_nse_nsvc_ipa_cmd,
1233 "nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>" ,
1234 "NS Virtual Connection\n"
1235 "NS over UDP ip.access style (uses RESET/BLOCK)\n"
1236 "A unique bind identifier created by ns bind\n"
1237 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1238 "Remote UDP Port\n"
1239 NSVCI_STR
1240 NSVCI_STR
1241 )
1242{
1243 struct gprs_ns2_vc_bind *bind;
1244 struct gprs_ns2_vc *nsvc;
1245 struct gprs_ns2_nse *nse = vty->index;
1246 bool dialect_modified = false;
1247 bool ll_modified = false;
1248
1249 const char *bind_name = argv[0];
1250 struct osmo_sockaddr_str remote_str;
1251 struct osmo_sockaddr remote;
1252 uint16_t port = atoi(argv[2]);
1253 uint16_t nsvci = atoi(argv[3]);
1254
1255 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1256 nse->ll = GPRS_NS2_LL_UDP;
1257 ll_modified = true;
1258 }
1259
1260 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
1261 nse->dialect = GPRS_NS2_DIALECT_IPACCESS;
1262 dialect_modified = true;
1263 }
1264
1265 if (nse->ll != GPRS_NS2_LL_UDP) {
1266 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1267 goto err;
1268 }
1269
1270 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1271 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1272 goto err;
1273 }
1274
1275 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1276 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1277 goto err;
1278 }
1279
1280 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1281 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1282 goto err;
1283 }
1284
1285 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1286 if (!bind) {
1287 vty_out(vty, "Can not find bind with name %s%s",
1288 bind_name, VTY_NEWLINE);
1289 goto err;
1290 }
1291
1292 if (bind->ll != GPRS_NS2_LL_UDP) {
1293 vty_out(vty, "Bind %s is not an UDP bind.%s",
1294 bind_name, VTY_NEWLINE);
1295 goto err;
1296 }
1297
1298 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, nsvci);
1299 if (!nsvc) {
1300 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
1301 goto err;
1302 }
1303 nsvc->persistent = true;
1304
1305 return CMD_SUCCESS;
1306
1307err:
1308 if (ll_modified)
1309 nse->ll = GPRS_NS2_LL_UNDEF;
1310 if (dialect_modified)
1311 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1312 return CMD_WARNING;
1313}
1314
1315DEFUN(cfg_no_ns_nse_nsvc_ipa, cfg_no_ns_nse_nsvc_ipa_cmd,
1316 "no nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>",
1317 NO_STR
1318 "Delete a NS Virtual Connection\n"
1319 "NS over UDP\n"
1320 "A unique bind identifier created by ns bind\n"
1321 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1322 "Remote UDP Port\n"
1323 NSVCI_STR
1324 NSVCI_STR
1325 )
1326{
1327 struct gprs_ns2_vc_bind *bind;
1328 struct gprs_ns2_vc *nsvc;
1329 struct gprs_ns2_nse *nse = vty->index;
1330 const char *bind_name = argv[0];
1331 struct osmo_sockaddr_str remote_str;
1332 struct osmo_sockaddr remote;
1333 uint16_t port = atoi(argv[2]);
1334 uint16_t nsvci = atoi(argv[3]);
1335
1336 if (nse->ll != GPRS_NS2_LL_UDP) {
1337 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1338 return CMD_WARNING;
1339 }
1340
1341 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1342 vty_out(vty, "This NSE doesn't support UDP with dialect ipaccess.%s", VTY_NEWLINE);
1343 return CMD_WARNING;
1344 }
1345
1346 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1347 if (!bind) {
1348 vty_out(vty, "Can not find bind with name %s%s",
1349 bind_name, VTY_NEWLINE);
1350 return CMD_WARNING;
1351 }
1352
1353 if (bind->ll != GPRS_NS2_LL_UDP) {
1354 vty_out(vty, "Bind %s is not an UDP bind.%s",
1355 bind_name, VTY_NEWLINE);
1356 return CMD_WARNING;
1357 }
1358
1359 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1360 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1361 return CMD_WARNING;
1362 }
1363
1364 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1365 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1366 return CMD_WARNING;
1367 }
1368
1369 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1370 if (!nsvc) {
1371 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1372 remote_str.ip, remote_str.port, VTY_NEWLINE);
1373 return CMD_WARNING;
1374 }
1375
1376 if (!nsvc->persistent) {
1377 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1378 remote_str.ip, remote_str.port, VTY_NEWLINE);
1379 return CMD_WARNING;
1380 }
1381
1382 if (nsvc->nse != nse) {
1383 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1384 return CMD_WARNING;
1385 }
1386
1387 if (!nsvc->nsvci_is_valid) {
1388 vty_out(vty, "NS-VC doesn't have a nsvci!%s", VTY_NEWLINE);
1389 return CMD_WARNING;
1390 }
1391
1392 if (nsvc->nsvci != nsvci) {
1393 vty_out(vty, "NS-VC has a different nsvci (%u)!%s",
1394 nsvc->nsvci, VTY_NEWLINE);
1395 return CMD_WARNING;
1396 }
1397
1398 gprs_ns2_free_nsvc(nsvc);
1399 if (llist_empty(&nse->nsvc)) {
1400 nse->ll = GPRS_NS2_LL_UNDEF;
1401 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1402 }
1403
1404 return CMD_SUCCESS;
1405}
1406
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001407DEFUN(cfg_ns_nse_ip_sns_remote, cfg_ns_nse_ip_sns_remote_cmd,
1408 "ip-sns-remote " VTY_IPV46_CMD " <1-65535>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001409 "SNS Initial Endpoint\n"
1410 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1411 "SGSN UDP Port\n"
1412 )
1413{
1414 struct gprs_ns2_nse *nse = vty->index;
1415 bool dialect_modified = false;
1416 bool ll_modified = false;
1417 int rc;
1418
1419 /* argv[0] */
1420 struct osmo_sockaddr_str remote_str;
1421 struct osmo_sockaddr remote;
1422 uint16_t port = atoi(argv[1]);
1423
1424 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1425 nse->ll = GPRS_NS2_LL_UDP;
1426 ll_modified = true;
1427 }
1428
1429 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
1430 char sns[16];
1431 snprintf(sns, sizeof(sns), "NSE%05u-SNS", nse->nsei);
1432 nse->bss_sns_fi = ns2_sns_bss_fsm_alloc(nse, sns);
1433 if (!nse->bss_sns_fi)
1434 goto err;
1435 nse->dialect = GPRS_NS2_DIALECT_SNS;
1436 dialect_modified = true;
1437 }
1438
1439 if (nse->ll != GPRS_NS2_LL_UDP) {
1440 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1441 goto err;
1442 }
1443
1444 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1445 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1446 goto err;
1447 }
1448
1449 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1450 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1451 goto err;
1452 }
1453
1454 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1455 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1456 goto err;
1457 }
1458
1459 rc = gprs_ns2_sns_add_endpoint(nse, &remote);
1460 switch (rc) {
1461 case 0:
1462 return CMD_SUCCESS;
1463 case -EADDRINUSE:
1464 vty_out(vty, "Specified SNS endpoint already part of the NSE.%s", VTY_NEWLINE);
1465 return CMD_WARNING;
1466 default:
1467 vty_out(vty, "Can not add specified SNS endpoint.%s", VTY_NEWLINE);
1468 return CMD_WARNING;
1469 }
1470
1471err:
1472 if (ll_modified)
1473 nse->ll = GPRS_NS2_LL_UNDEF;
1474 if (dialect_modified)
1475 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1476 return CMD_WARNING;
1477}
1478
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001479DEFUN(cfg_no_ns_nse_ip_sns_remote, cfg_no_ns_nse_ip_sns_remote_cmd,
1480 "no ip-sns-remote " VTY_IPV46_CMD " <1-65535>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001481 NO_STR
1482 "Delete a SNS Initial Endpoint\n"
1483 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1484 "SGSN UDP Port\n"
1485 )
1486{
1487 struct gprs_ns2_nse *nse = vty->index;
1488 struct osmo_sockaddr_str remote_str; /* argv[0] */
1489 struct osmo_sockaddr remote;
1490 uint16_t port = atoi(argv[1]);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001491
1492 if (nse->ll != GPRS_NS2_LL_UDP) {
1493 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1494 return CMD_WARNING;
1495 }
1496
1497 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1498 vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%s", VTY_NEWLINE);
1499 return CMD_WARNING;
1500 }
1501
1502 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1503 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1504 return CMD_WARNING;
1505 }
1506
1507 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1508 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1509 return CMD_WARNING;
1510 }
1511
1512 if (gprs_ns2_sns_del_endpoint(nse, &remote)) {
1513 vty_out(vty, "Can not remove specified SNS endpoint.%s", VTY_NEWLINE);
1514 return CMD_WARNING;
1515 }
1516
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001517 if (vty_nse_check_sns(nse)) {
1518 /* there is still sns configuration valid */
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001519 return CMD_SUCCESS;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001520 } else {
1521 /* clean up nse to allow other nsvc commands */
1522 osmo_fsm_inst_term(nse->bss_sns_fi, OSMO_FSM_TERM_REQUEST, NULL);
1523 nse->bss_sns_fi = NULL;
1524 nse->ll = GPRS_NS2_LL_UNDEF;
1525 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1526 }
1527
1528 return CMD_SUCCESS;
1529}
1530
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001531DEFUN(cfg_ns_nse_ip_sns_bind, cfg_ns_nse_ip_sns_bind_cmd,
1532 "ip-sns-bind BINDID",
1533 "IP SNS binds\n"
1534 "A udp bind which this SNS will be used. The bind must be already exists. Can be given multiple times.\n")
1535{
1536 struct gprs_ns2_nse *nse = vty->index;
1537 struct gprs_ns2_vc_bind *bind;
1538 struct vty_bind *vbind;
1539 struct vty_nse *vnse;
1540 const char *name = argv[0];
1541 bool ll_modified = false;
1542 bool dialect_modified = false;
1543 int rc;
1544
1545 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1546 nse->ll = GPRS_NS2_LL_UDP;
1547 ll_modified = true;
1548 }
1549
1550 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
1551 char sns[16];
1552 snprintf(sns, sizeof(sns), "NSE%05u-SNS", nse->nsei);
1553 nse->bss_sns_fi = ns2_sns_bss_fsm_alloc(nse, sns);
1554 if (!nse->bss_sns_fi)
1555 goto err;
1556 nse->dialect = GPRS_NS2_DIALECT_SNS;
1557 dialect_modified = true;
1558 }
1559
1560 if (nse->ll != GPRS_NS2_LL_UDP) {
1561 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1562 goto err;
1563 }
1564
1565 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1566 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1567 goto err;
1568 }
1569
1570 vbind = vty_bind_by_name(name);
1571 if (!vbind) {
1572 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1573 goto err;
1574 }
1575
1576 if (vbind->ll != GPRS_NS2_LL_UDP) {
1577 vty_out(vty, "ip-sns-bind can only be used with UDP bind%s",
1578 VTY_NEWLINE);
1579 goto err;
1580 }
1581
1582 /* the vnse has been created together when creating the nse node. The parent node should check this already! */
1583 vnse = vty_nse_by_nsei(nse->nsei);
1584 OSMO_ASSERT(vnse);
1585
1586 rc = vty_nse_add_vbind(vnse, vbind);
1587 switch (rc) {
1588 case 0:
1589 break;
1590 case -EALREADY:
1591 vty_out(vty, "Failed to add ip-sns-bind %s already present%s", name, VTY_NEWLINE);
1592 goto err;
1593 case -ENOMEM:
1594 vty_out(vty, "Failed to add ip-sns-bind %s out of memory%s", name, VTY_NEWLINE);
1595 goto err;
1596 default:
1597 vty_out(vty, "Failed to add ip-sns-bind %s! %d%s", name, rc, VTY_NEWLINE);
1598 goto err;
1599 }
1600
1601 /* the bind might not yet created because "listen" is missing. */
1602 bind = gprs_ns2_bind_by_name(vty_nsi, name);
1603 if (!bind)
1604 return CMD_SUCCESS;
1605
1606 rc = gprs_ns2_sns_add_bind(nse, bind);
1607 switch (rc) {
1608 case 0:
1609 break;
1610 case -EALREADY:
1611 vty_out(vty, "Failed to add ip-sns-bind %s already present%s", name, VTY_NEWLINE);
1612 goto err;
1613 case -ENOMEM:
1614 vty_out(vty, "Failed to add ip-sns-bind %s out of memory%s", name, VTY_NEWLINE);
1615 goto err;
1616 default:
1617 vty_out(vty, "Failed to add ip-sns-bind %s! %d%s", name, rc, VTY_NEWLINE);
1618 goto err;
1619 }
1620
1621 return CMD_SUCCESS;
1622err:
1623 if (ll_modified)
1624 nse->ll = GPRS_NS2_LL_UNDEF;
1625 if (dialect_modified)
1626 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1627
1628 return CMD_WARNING;
1629}
1630
1631DEFUN(cfg_no_ns_nse_ip_sns_bind, cfg_no_ns_nse_ip_sns_bind_cmd,
1632 "no ip-sns-bind BINDID",
1633 NO_STR
1634 "IP SNS binds\n"
1635 "A udp bind which this SNS will be used.\n")
1636{
1637 struct gprs_ns2_nse *nse = vty->index;
1638 struct gprs_ns2_vc_bind *bind;
1639 struct vty_bind *vbind;
1640 struct vty_nse *vnse;
1641 const char *name = argv[0];
1642 int rc;
1643
1644 if (nse->ll != GPRS_NS2_LL_UDP) {
1645 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1646 return CMD_WARNING;
1647 }
1648
1649 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1650 vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%s", VTY_NEWLINE);
1651 return CMD_WARNING;
1652 }
1653
1654 vbind = vty_bind_by_name(name);
1655 if (!vbind) {
1656 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1657 return CMD_WARNING;
1658 }
1659
1660 if (vbind->ll != GPRS_NS2_LL_UDP) {
1661 vty_out(vty, "no ip-sns-bind can only be used with UDP bind%s",
1662 VTY_NEWLINE);
1663 return CMD_WARNING;
1664 }
1665
1666 /* the vnse has been created together when creating the nse node. The parent node should check this already! */
1667 vnse = vty_nse_by_nsei(nse->nsei);
1668 OSMO_ASSERT(vnse);
1669
1670 rc = vty_nse_remove_vbind(vnse, vbind);
1671 switch(rc) {
1672 case 0:
1673 break;
1674 case -ENOENT:
1675 vty_out(vty, "Bind %s is not part of this NSE%s", name, VTY_NEWLINE);
1676 return CMD_WARNING;
1677 case -EINVAL:
1678 vty_out(vty, "no ip-sns-bind can only be used with UDP bind%s",
1679 VTY_NEWLINE);
1680 return CMD_WARNING;
1681 default:
1682 return CMD_WARNING;
1683 }
1684
1685 /* the bind might not exists yet */
1686 bind = gprs_ns2_bind_by_name(vty_nsi, name);
1687 if (bind)
1688 gprs_ns2_sns_del_bind(nse, bind);
1689
1690 if (!vty_nse_check_sns(nse)) {
1691 /* clean up nse to allow other nsvc commands */
1692 osmo_fsm_inst_term(nse->bss_sns_fi, OSMO_FSM_TERM_REQUEST, NULL);
1693 nse->bss_sns_fi = NULL;
1694 nse->ll = GPRS_NS2_LL_UNDEF;
1695 nse->dialect = GPRS_NS2_DIALECT_UNDEF;
1696 }
1697
1698 return CMD_SUCCESS;
1699}
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001700
1701/* non-config commands */
Alexander Couzens6a161492020-07-12 13:45:50 +02001702static void dump_nsvc(struct vty *vty, struct gprs_ns2_vc *nsvc, bool stats)
1703{
Harald Weltedc2d0802020-12-01 18:17:28 +01001704 char nsvci_str[32];
1705
1706 if (nsvc->nsvci_is_valid)
1707 snprintf(nsvci_str, sizeof(nsvci_str), "%05u", nsvc->nsvci);
1708 else
1709 snprintf(nsvci_str, sizeof(nsvci_str), "none");
1710
1711 vty_out(vty, " NSVCI %s: %s %s data_weight=%u sig_weight=%u %s%s", nsvci_str,
1712 osmo_fsm_inst_state_name(nsvc->fi),
1713 nsvc->persistent ? "PERSIST" : "DYNAMIC",
1714 nsvc->data_weight, nsvc->sig_weight,
1715 gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001716
1717 if (stats) {
Harald Welte7aa60992020-12-01 17:53:17 +01001718 vty_out_rate_ctr_group(vty, " ", nsvc->ctrg);
1719 vty_out_stat_item_group(vty, " ", nsvc->statg);
Alexander Couzens6a161492020-07-12 13:45:50 +02001720 }
1721}
1722
1723static void dump_nse(struct vty *vty, const struct gprs_ns2_nse *nse, bool stats, bool persistent_only)
1724{
1725 struct gprs_ns2_vc *nsvc;
1726
Harald Welte0ff12ad2020-12-01 17:51:07 +01001727 vty_out(vty, "NSEI %05u: %s, %s%s", nse->nsei, gprs_ns2_lltype_str(nse->ll),
1728 nse->alive ? "ALIVE" : "DEAD", VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001729
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001730 ns2_sns_dump_vty(vty, " ", nse, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001731 llist_for_each_entry(nsvc, &nse->nsvc, list) {
1732 if (persistent_only) {
1733 if (nsvc->persistent)
1734 dump_nsvc(vty, nsvc, stats);
1735 } else {
1736 dump_nsvc(vty, nsvc, stats);
1737 }
1738 }
1739}
1740
Alexander Couzens22f34712020-10-02 02:34:39 +02001741static void dump_bind(struct vty *vty, const struct gprs_ns2_vc_bind *bind, bool stats)
1742{
1743 if (bind->dump_vty)
1744 bind->dump_vty(bind, vty, stats);
Harald Welte76346072021-01-31 11:54:02 +01001745
1746 if (stats) {
1747 vty_out_stat_item_group(vty, " ", bind->statg);
1748 }
Alexander Couzens22f34712020-10-02 02:34:39 +02001749}
1750
Harald Welte2fce19a2020-12-01 17:52:55 +01001751static void dump_ns_bind(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats)
Alexander Couzens6a161492020-07-12 13:45:50 +02001752{
Alexander Couzens22f34712020-10-02 02:34:39 +02001753 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6a161492020-07-12 13:45:50 +02001754
Alexander Couzens22f34712020-10-02 02:34:39 +02001755 llist_for_each_entry(bind, &nsi->binding, list) {
1756 dump_bind(vty, bind, stats);
1757 }
Harald Welte2fce19a2020-12-01 17:52:55 +01001758}
1759
1760
1761static void dump_ns_entities(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats, bool persistent_only)
1762{
1763 struct gprs_ns2_nse *nse;
Alexander Couzens22f34712020-10-02 02:34:39 +02001764
Alexander Couzens6a161492020-07-12 13:45:50 +02001765 llist_for_each_entry(nse, &nsi->nse, list) {
1766 dump_nse(vty, nse, stats, persistent_only);
Alexander Couzens6a161492020-07-12 13:45:50 +02001767 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001768}
1769
Harald Welte25ee7552020-12-02 22:14:00 +01001770/* Backwards compatibility, among other things for the TestVTYGbproxy which expects
1771 * 'show ns' to output something about binds */
1772DEFUN_HIDDEN(show_ns, show_ns_cmd, "show ns",
1773 SHOW_STR SHOW_NS_STR)
1774{
1775 dump_ns_entities(vty, vty_nsi, false, false);
1776 dump_ns_bind(vty, vty_nsi, false);
1777 return CMD_SUCCESS;
1778}
1779
1780
Harald Welte2fce19a2020-12-01 17:52:55 +01001781DEFUN(show_ns_binds, show_ns_binds_cmd, "show ns binds [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001782 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01001783 "Display information about the NS protocol binds\n"
1784 "Include statistic\n")
Alexander Couzens6a161492020-07-12 13:45:50 +02001785{
Harald Welte2fce19a2020-12-01 17:52:55 +01001786 bool stats = false;
1787 if (argc > 0)
1788 stats = true;
1789
1790 dump_ns_bind(vty, vty_nsi, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001791 return CMD_SUCCESS;
1792}
1793
Harald Welte2fce19a2020-12-01 17:52:55 +01001794DEFUN(show_ns_entities, show_ns_entities_cmd, "show ns entities [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001795 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01001796 "Display information about the NS protocol entities (NSEs)\n"
Alexander Couzens6a161492020-07-12 13:45:50 +02001797 "Include statistics\n")
1798{
Harald Welte2fce19a2020-12-01 17:52:55 +01001799 bool stats = false;
1800 if (argc > 0)
1801 stats = true;
1802
1803 dump_ns_entities(vty, vty_nsi, stats, false);
Alexander Couzens6a161492020-07-12 13:45:50 +02001804 return CMD_SUCCESS;
1805}
1806
1807DEFUN(show_ns_pers, show_ns_pers_cmd, "show ns persistent",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001808 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02001809 "Show only persistent NS\n")
1810{
Harald Welte2fce19a2020-12-01 17:52:55 +01001811 dump_ns_entities(vty, vty_nsi, true, true);
Alexander Couzens6a161492020-07-12 13:45:50 +02001812 return CMD_SUCCESS;
1813}
1814
1815DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001816 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02001817 "Select one NSE by its NSE Identifier\n"
1818 "Select one NSE by its NS-VC Identifier\n"
1819 "The Identifier of selected type\n"
1820 "Include Statistics\n")
1821{
1822 struct gprs_ns2_inst *nsi = vty_nsi;
1823 struct gprs_ns2_nse *nse;
1824 struct gprs_ns2_vc *nsvc;
1825 uint16_t id = atoi(argv[1]);
1826 bool show_stats = false;
1827
1828 if (argc >= 3)
1829 show_stats = true;
1830
1831 if (!strcmp(argv[0], "nsei")) {
1832 nse = gprs_ns2_nse_by_nsei(nsi, id);
1833 if (!nse) {
1834 return CMD_WARNING;
1835 }
1836
1837 dump_nse(vty, nse, show_stats, false);
1838 } else {
1839 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
1840
1841 if (!nsvc) {
1842 vty_out(vty, "No such NS Entity%s", VTY_NEWLINE);
1843 return CMD_WARNING;
1844 }
1845
1846 dump_nsvc(vty, nsvc, show_stats);
1847 }
1848
1849 return CMD_SUCCESS;
1850}
1851
Daniel Willmanndbab7142020-11-18 14:19:56 +01001852static int nsvc_force_unconf_cb(struct gprs_ns2_vc *nsvc, void *ctx)
1853{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001854 ns2_vc_force_unconfigured(nsvc);
Harald Welte7fe8d712021-01-31 18:40:54 +01001855 ns2_vc_fsm_start(nsvc);
Daniel Willmanndbab7142020-11-18 14:19:56 +01001856 return 0;
1857}
1858
1859DEFUN_HIDDEN(nsvc_force_unconf, nsvc_force_unconf_cmd,
1860 "nsvc nsei <0-65535> force-unconfigured",
1861 "NS Virtual Connection\n"
1862 "The NSEI\n"
1863 "Reset the NSVCs back to initial state\n"
1864 )
1865{
1866 struct gprs_ns2_inst *nsi = vty_nsi;
1867 struct gprs_ns2_nse *nse;
1868
1869 uint16_t id = atoi(argv[0]);
1870
1871 nse = gprs_ns2_nse_by_nsei(nsi, id);
1872 if (!nse) {
1873 vty_out(vty, "Could not find NSE for NSEI %u%s", id, VTY_NEWLINE);
1874 return CMD_WARNING;
1875 }
1876
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001877 if (!nse->persistent) {
1878 gprs_ns2_free_nse(nse);
1879 } else if (nse->dialect == GPRS_NS2_DIALECT_SNS) {
Alexander Couzens280ed782020-12-21 18:25:41 +01001880 gprs_ns2_free_nsvcs(nse);
1881 } else {
1882 /* Perform the operation for all nsvc */
1883 gprs_ns2_nse_foreach_nsvc(nse, nsvc_force_unconf_cb, NULL);
1884 }
Daniel Willmanndbab7142020-11-18 14:19:56 +01001885
1886 return CMD_SUCCESS;
1887}
1888
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001889DEFUN(nsvc_block, nsvc_block_cmd,
1890 "nsvc <0-65535> (block|unblock)",
1891 "NS Virtual Connection\n"
1892 NSVCI_STR
1893 "Block a NSVC. As cause code O&M intervention will be used.\n"
1894 "Unblock a NSVC. As cause code O&M intervention will be used.\n")
Alexander Couzens841817e2020-11-19 00:41:29 +01001895{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001896 struct gprs_ns2_inst *nsi = vty_nsi;
1897 struct gprs_ns2_vc *nsvc;
Alexander Couzens841817e2020-11-19 00:41:29 +01001898
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001899 uint16_t id = atoi(argv[0]);
Alexander Couzens841817e2020-11-19 00:41:29 +01001900
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001901 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
1902 if (!nsvc) {
1903 vty_out(vty, "Could not find NSVCI %05u%s", id, VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +01001904 return CMD_WARNING;
1905 }
1906
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001907 if (!strcmp(argv[1], "block")) {
1908 ns2_vc_block(nsvc);
1909 } else {
1910 ns2_vc_unblock(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +02001911 }
1912
1913 return CMD_SUCCESS;
1914}
1915
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001916static void log_set_nse_filter(struct log_target *target,
1917 struct gprs_ns2_nse *nse)
Alexander Couzens6a161492020-07-12 13:45:50 +02001918{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001919 if (nse) {
1920 target->filter_map |= (1 << LOG_FLT_GB_NSE);
1921 target->filter_data[LOG_FLT_GB_NSE] = nse;
1922 } else if (target->filter_data[LOG_FLT_GB_NSE]) {
1923 target->filter_map = ~(1 << LOG_FLT_GB_NSE);
1924 target->filter_data[LOG_FLT_GB_NSE] = NULL;
1925 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001926}
1927
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001928static void log_set_nsvc_filter(struct log_target *target,
1929 struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +02001930{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001931 if (nsvc) {
1932 target->filter_map |= (1 << LOG_FLT_GB_NSVC);
1933 target->filter_data[LOG_FLT_GB_NSVC] = nsvc;
1934 } else if (target->filter_data[LOG_FLT_GB_NSVC]) {
1935 target->filter_map = ~(1 << LOG_FLT_GB_NSVC);
1936 target->filter_data[LOG_FLT_GB_NSVC] = NULL;
1937 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001938}
1939
Daniel Willmann751977b2020-12-02 18:59:44 +01001940DEFUN(logging_fltr_nse,
1941 logging_fltr_nse_cmd,
1942 "logging filter nse nsei <0-65535>",
1943 LOGGING_STR FILTER_STR
1944 "Filter based on NS Entity\n"
1945 "Identify NSE by NSEI\n"
1946 "Numeric identifier\n")
1947{
1948 struct log_target *tgt;
1949 struct gprs_ns2_nse *nse;
Daniel Willmann89106522020-12-04 01:36:59 +01001950 uint16_t id = atoi(argv[0]);
Daniel Willmann751977b2020-12-02 18:59:44 +01001951
1952 log_tgt_mutex_lock();
1953 tgt = osmo_log_vty2tgt(vty);
1954 if (!tgt) {
1955 log_tgt_mutex_unlock();
1956 return CMD_WARNING;
1957 }
1958
1959 nse = gprs_ns2_nse_by_nsei(vty_nsi, id);
1960 if (!nse) {
1961 vty_out(vty, "No NSE by that identifier%s", VTY_NEWLINE);
1962 log_tgt_mutex_unlock();
1963 return CMD_WARNING;
1964 }
1965
1966 log_set_nse_filter(tgt, nse);
1967 log_tgt_mutex_unlock();
1968 return CMD_SUCCESS;
1969}
1970
Alexander Couzens6a161492020-07-12 13:45:50 +02001971/* TODO: add filter for single connection by description */
1972DEFUN(logging_fltr_nsvc,
1973 logging_fltr_nsvc_cmd,
1974 "logging filter nsvc nsvci <0-65535>",
1975 LOGGING_STR FILTER_STR
1976 "Filter based on NS Virtual Connection\n"
1977 "Identify NS-VC by NSVCI\n"
1978 "Numeric identifier\n")
1979{
1980 struct log_target *tgt;
1981 struct gprs_ns2_vc *nsvc;
Daniel Willmann89106522020-12-04 01:36:59 +01001982 uint16_t id = atoi(argv[0]);
Alexander Couzens6a161492020-07-12 13:45:50 +02001983
1984 log_tgt_mutex_lock();
1985 tgt = osmo_log_vty2tgt(vty);
1986 if (!tgt) {
1987 log_tgt_mutex_unlock();
1988 return CMD_WARNING;
1989 }
1990
1991 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, id);
1992 if (!nsvc) {
1993 vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE);
1994 log_tgt_mutex_unlock();
1995 return CMD_WARNING;
1996 }
1997
1998 log_set_nsvc_filter(tgt, nsvc);
1999 log_tgt_mutex_unlock();
2000 return CMD_SUCCESS;
2001}
2002
Alexander Couzense43b46e2021-01-27 21:52:08 +01002003/*! initialized a reduced vty interface which excludes the configuration nodes besides timeouts.
2004 * This can be used by the PCU which can be only configured by the BTS/BSC and not by the vty.
2005 * \param[in] nsi NS instance on which we operate
2006 * \return 0 on success.
2007 */
2008int gprs_ns2_vty_init_reduced(struct gprs_ns2_inst *nsi)
Alexander Couzens6a161492020-07-12 13:45:50 +02002009{
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01002010 vty_nsi = nsi;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002011 INIT_LLIST_HEAD(&binds);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002012 INIT_LLIST_HEAD(&nses);
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01002013
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002014 vty_fr_network = osmo_fr_network_alloc(nsi);
2015 if (!vty_fr_network)
2016 return -ENOMEM;
Alexander Couzens6a161492020-07-12 13:45:50 +02002017
Harald Welte25ee7552020-12-02 22:14:00 +01002018 install_lib_element_ve(&show_ns_cmd);
Harald Welte2fce19a2020-12-01 17:52:55 +01002019 install_lib_element_ve(&show_ns_binds_cmd);
2020 install_lib_element_ve(&show_ns_entities_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002021 install_lib_element_ve(&show_ns_pers_cmd);
2022 install_lib_element_ve(&show_nse_cmd);
Daniel Willmann751977b2020-12-02 18:59:44 +01002023 install_lib_element_ve(&logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002024 install_lib_element_ve(&logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002025
Daniel Willmanndbab7142020-11-18 14:19:56 +01002026 install_lib_element(ENABLE_NODE, &nsvc_force_unconf_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002027 install_lib_element(ENABLE_NODE, &nsvc_block_cmd);
Daniel Willmanndbab7142020-11-18 14:19:56 +01002028
Daniel Willmann751977b2020-12-02 18:59:44 +01002029 install_lib_element(CFG_LOG_NODE, &logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002030 install_lib_element(CFG_LOG_NODE, &logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002031
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002032 install_lib_element(CONFIG_NODE, &cfg_ns_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002033
Alexander Couzens6a161492020-07-12 13:45:50 +02002034 install_node(&ns_node, config_write_ns);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002035 /* TODO: convert into osmo timer */
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002036 install_lib_element(L_NS_NODE, &cfg_ns_timer_cmd);
Alexander Couzense43b46e2021-01-27 21:52:08 +01002037
2038 return 0;
2039}
2040
2041int gprs_ns2_vty_init(struct gprs_ns2_inst *nsi)
2042{
2043 int rc = gprs_ns2_vty_init_reduced(nsi);
2044 if (rc)
2045 return rc;
2046
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002047 install_lib_element(L_NS_NODE, &cfg_ns_nsei_cmd);
2048 install_lib_element(L_NS_NODE, &cfg_no_ns_nsei_cmd);
2049 install_lib_element(L_NS_NODE, &cfg_ns_bind_cmd);
2050 install_lib_element(L_NS_NODE, &cfg_no_ns_bind_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002051
Alexander Couzens260cd522021-01-28 20:31:31 +01002052 install_node(&ns_bind_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002053 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_listen_cmd);
2054 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_listen_cmd);
2055 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_dscp_cmd);
2056 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_dscp_cmd);
Alexander Couzensc4704762021-02-08 23:13:12 +01002057 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_ip_sns_weight_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002058 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_ipaccess_cmd);
2059 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_ipaccess_cmd);
2060 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_fr_cmd);
2061 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_fr_cmd);
2062 /* TODO: accept-ip-sns when SGSN SNS has been implemented */
Alexander Couzens6a161492020-07-12 13:45:50 +02002063
Alexander Couzens260cd522021-01-28 20:31:31 +01002064 install_node(&ns_nse_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002065 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_fr_cmd);
2066 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvci_cmd);
2067 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_fr_dlci_cmd);
2068 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_udp_cmd);
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01002069 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_udp_weights_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002070 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_udp_cmd);
2071 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_ipa_cmd);
2072 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_ipa_cmd);
Alexander Couzens5fa431c2021-02-08 23:21:54 +01002073 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_remote_cmd);
2074 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_remote_cmd);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002075 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_bind_cmd);
2076 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_bind_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002077
2078 return 0;
2079}