blob: 68a14c2582821332e6f6cbd92f8b51c83a442345 [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;
70 bool accept_ipaccess;
71 bool accept_sns;
Alexander Couzensc4704762021-02-08 23:13:12 +010072 uint8_t ip_sns_sig_weight;
73 uint8_t ip_sns_data_weight;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010074};
75
Alexander Couzens6b9d2322021-02-12 03:17:59 +010076struct vty_nse {
77 struct llist_head list;
78 uint16_t nsei;
79 /* list of binds which are valid for this nse. Only IP-SNS uses this
80 * to allow `no listen ..` in the bind context. So "half" created binds are valid for
81 * IP-SNS. This allows changing the bind ip without modifying all NSEs afterwards */
82 struct llist_head binds;
83};
84
85/* used by IP-SNS to connect multiple vty_nse_bind to a vty_nse */
86struct vty_nse_bind {
87 struct llist_head list;
88 struct vty_bind *vbind;
89};
90
Alexander Couzensda1bf8e2021-01-25 16:27:33 +010091/* TODO: this should into osmo timer */
Alexander Couzens6a161492020-07-12 13:45:50 +020092static const struct value_string gprs_ns_timer_strs[] = {
93 { 0, "tns-block" },
94 { 1, "tns-block-retries" },
95 { 2, "tns-reset" },
96 { 3, "tns-reset-retries" },
97 { 4, "tns-test" },
98 { 5, "tns-alive" },
99 { 6, "tns-alive-retries" },
100 { 7, "tsns-prov" },
Harald Welte33c3c062020-12-16 11:59:19 +0100101 { 8, "tsns-size-retries" },
102 { 9, "tsns-config-retries" },
Alexander Couzens6a161492020-07-12 13:45:50 +0200103 { 0, NULL }
104};
105
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100106const struct value_string vty_fr_role_names[] = {
107 { FR_ROLE_USER_EQUIPMENT, "fr" },
108 { FR_ROLE_NETWORK_EQUIPMENT, "frnet" },
109 { 0, NULL }
110};
111
112const struct value_string vty_ll_names[] = {
113 { GPRS_NS2_LL_FR, "fr" },
114 { GPRS_NS2_LL_FR_GRE, "frgre" },
115 { GPRS_NS2_LL_UDP, "udp" },
116 { 0, NULL }
117};
118
119static struct vty_bind *vty_bind_by_name(const char *name)
Daniel Willmann751977b2020-12-02 18:59:44 +0100120{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100121 struct vty_bind *vbind;
122 llist_for_each_entry(vbind, &binds, list) {
Alexander Couzensb7921732021-02-12 03:08:42 +0100123 if (!strcmp(vbind->name, name))
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100124 return vbind;
Daniel Willmann751977b2020-12-02 18:59:44 +0100125 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100126 return NULL;
Daniel Willmann751977b2020-12-02 18:59:44 +0100127}
128
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100129static struct vty_bind *vty_bind_alloc(const char *name)
Alexander Couzens6a161492020-07-12 13:45:50 +0200130{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100131 struct vty_bind *vbind = talloc_zero(vty_nsi, struct vty_bind);
132 if (!vbind)
133 return NULL;
134
135 vbind->name = talloc_strdup(vty_nsi, name);
136 if (!vbind->name) {
137 talloc_free(vbind);
138 return NULL;
Alexander Couzens6a161492020-07-12 13:45:50 +0200139 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100140
Alexander Couzensc4704762021-02-08 23:13:12 +0100141 vbind->ip_sns_sig_weight = 1;
142 vbind->ip_sns_data_weight = 1;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100143 llist_add(&vbind->list, &binds);
144 return vbind;
145}
146
147static void vty_bind_free(struct vty_bind *vbind)
148{
149 if (!vbind)
150 return;
151
152 llist_del(&vbind->list);
Alexander Couzens3e2e4a02021-02-09 16:15:06 +0100153 talloc_free(vbind);
Alexander Couzens6a161492020-07-12 13:45:50 +0200154}
155
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100156static struct vty_nse *vty_nse_by_nsei(uint16_t nsei)
157{
158 struct vty_nse *vnse;
159 llist_for_each_entry(vnse, &nses, list) {
160 if (vnse->nsei == nsei)
161 return vnse;
162 }
163 return NULL;
164}
165
166static struct vty_nse *vty_nse_alloc(uint16_t nsei)
167{
168 struct vty_nse *vnse = talloc_zero(vty_nsi, struct vty_nse);
169 if (!vnse)
170 return NULL;
171
172 vnse->nsei = nsei;
173 INIT_LLIST_HEAD(&vnse->binds);
174 llist_add(&vnse->list, &nses);
175 return vnse;
176}
177
178static void vty_nse_free(struct vty_nse *vnse)
179{
180 if (!vnse)
181 return;
182
183 llist_del(&vnse->list);
184 /* all vbind of the nse will be freed by talloc */
185 talloc_free(vnse);
186}
187
188static int vty_nse_add_vbind(struct vty_nse *vnse, struct vty_bind *vbind)
189{
190 struct vty_nse_bind *vnse_bind;
191
192 if (vbind->ll != GPRS_NS2_LL_UDP)
193 return -EINVAL;
194
195 llist_for_each_entry(vnse_bind, &vnse->binds, list) {
196 if (vnse_bind->vbind == vbind)
197 return -EALREADY;
198 }
199
200 vnse_bind = talloc(vnse, struct vty_nse_bind);
201 if (!vnse_bind)
202 return -ENOMEM;
203 vnse_bind->vbind = vbind;
204
205 llist_add_tail(&vnse_bind->list, &vnse->binds);
206 return 0;
207}
208
209static int vty_nse_remove_vbind(struct vty_nse *vnse, struct vty_bind *vbind)
210{
211 struct vty_nse_bind *vnse_bind, *tmp;
212 if (vbind->ll != GPRS_NS2_LL_UDP)
213 return -EINVAL;
214
215 llist_for_each_entry_safe(vnse_bind, tmp, &vnse->binds, list) {
216 if (vnse_bind->vbind == vbind) {
217 llist_del(&vnse_bind->list);
218 talloc_free(vnse_bind);
219 }
220 }
221
222 return -ENOENT;
223}
224
225/* check if the NSE still has SNS configuration */
226static bool vty_nse_check_sns(struct gprs_ns2_nse *nse) {
227 struct vty_nse *vnse = vty_nse_by_nsei(nse->nsei);
228
229 int count = gprs_ns2_sns_count(nse);
230 if (count > 0) {
231 /* there are other sns endpoints */
232 return true;
233 }
234
235 if (!vnse)
236 return false;
237
238 if (llist_empty(&vnse->binds))
239 return false;
240
241 return true;
242}
243
Alexander Couzens6a161492020-07-12 13:45:50 +0200244static struct cmd_node ns_node = {
245 L_NS_NODE,
246 "%s(config-ns)# ",
247 1,
248};
249
Alexander Couzens6a161492020-07-12 13:45:50 +0200250DEFUN(cfg_ns, cfg_ns_cmd,
251 "ns",
252 "Configure the GPRS Network Service")
253{
254 vty->node = L_NS_NODE;
255 return CMD_SUCCESS;
256}
257
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100258DEFUN(cfg_ns_timer, cfg_ns_timer_cmd,
259 "timer " NS_TIMERS " <0-65535>",
260 "Network Service Timer\n"
261 NS_TIMERS_HELP "Timer Value\n")
262{
263 int idx = get_string_value(gprs_ns_timer_strs, argv[0]);
264 int val = atoi(argv[1]);
265
266 if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout))
267 return CMD_WARNING;
268
269 vty_nsi->timeout[idx] = val;
270
271 return CMD_SUCCESS;
272}
273
274DEFUN(cfg_ns_nsei, cfg_ns_nsei_cmd,
Harald Welte579699b2021-03-05 10:22:23 +0100275 "nse <0-65535> [ip-sns-role-sgsn]",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100276 "Persistent NS Entity\n"
277 "NS Entity ID (NSEI)\n"
Harald Welte579699b2021-03-05 10:22:23 +0100278 "Create NSE in SGSN role (default: BSS)\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100279 )
280{
281 struct gprs_ns2_nse *nse;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100282 struct vty_nse *vnse;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100283 uint16_t nsei = atoi(argv[0]);
Harald Welte579699b2021-03-05 10:22:23 +0100284 bool sgsn_role = false;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100285 bool free_vnse = false;
Harald Welte579699b2021-03-05 10:22:23 +0100286 if (argc > 1 && !strcmp(argv[1], "ip-sns-role-sgsn"))
287 sgsn_role = true;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100288
289 vnse = vty_nse_by_nsei(nsei);
290 if (!vnse) {
291 vnse = vty_nse_alloc(nsei);
292 if (!vnse) {
293 vty_out(vty, "Failed to create vty NSE!%s", VTY_NEWLINE);
294 return CMD_ERR_INCOMPLETE;
295 }
296 free_vnse = true;
297 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100298
299 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
300 if (!nse) {
Harald Welte579699b2021-03-05 10:22:23 +0100301 nse = gprs_ns2_create_nse2(vty_nsi, nsei, GPRS_NS2_LL_UNDEF, GPRS_NS2_DIALECT_UNDEF,
302 sgsn_role);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100303 if (!nse) {
304 vty_out(vty, "Failed to create NSE!%s", VTY_NEWLINE);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100305 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100306 }
307 nse->persistent = true;
308 }
309
310 if (!nse->persistent) {
311 /* TODO: should the dynamic NSE removed? */
312 vty_out(vty, "A dynamic NSE with the specified NSEI already exists%s", VTY_NEWLINE);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100313 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100314 }
315
316 vty->node = L_NS_NSE_NODE;
317 vty->index = nse;
318
319 return CMD_SUCCESS;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100320
321err:
322 if (free_vnse)
323 talloc_free(vnse);
324
325 return CMD_ERR_INCOMPLETE;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100326}
327
328DEFUN(cfg_no_ns_nsei, cfg_no_ns_nsei_cmd,
329 "no nse <0-65535>",
330 NO_STR
331 "Delete a Persistent NS Entity\n"
332 "NS Entity ID (NSEI)\n"
333 )
334{
335 struct gprs_ns2_nse *nse;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100336 struct vty_nse *vnse;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100337 uint16_t nsei = atoi(argv[0]);
338
339 nse = gprs_ns2_nse_by_nsei(vty_nsi, nsei);
340 if (!nse) {
341 vty_out(vty, "Can not find NS Entity %s%s", argv[0], VTY_NEWLINE);
342 return CMD_ERR_NOTHING_TODO;
343 }
344
345 if (!nse->persistent) {
346 vty_out(vty, "Ignoring non-persistent NS Entity%s", VTY_NEWLINE);
347 return CMD_WARNING;
348 }
349
350 vty_out(vty, "Deleting NS Entity %u%s", nse->nsei, VTY_NEWLINE);
351 gprs_ns2_free_nse(nse);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100352
353 vnse = vty_nse_by_nsei(nsei);
354 vty_nse_free(vnse);
355
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100356 return CMD_SUCCESS;
357}
358
359/* TODO: add fr/gre */
360DEFUN(cfg_ns_bind, cfg_ns_bind_cmd,
361 "bind (fr|udp) ID",
Harald Welte2230a912021-03-04 20:09:50 +0100362 "Configure local Bind\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100363 "Frame Relay\n" "UDP/IP\n"
Harald Welte2230a912021-03-04 20:09:50 +0100364 "Unique identifier for this bind (to reference from NS-VCs, NSEs, ...)\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100365 )
366{
367 const char *nstype = argv[0];
368 const char *name = argv[1];
369 struct vty_bind *vbind;
370 enum gprs_ns2_ll ll;
371 int rc;
372
373 rc = get_string_value(vty_ll_names, nstype);
374 if (rc < 0)
375 return CMD_WARNING;
376 ll = (enum gprs_ns2_ll) rc;
377
378 if (!osmo_identifier_valid(name)) {
379 vty_out(vty, "Invalid ID. The ID should be only alphanumeric.%s", VTY_NEWLINE);
380 return CMD_WARNING;
381 }
382
383 vbind = vty_bind_by_name(name);
384 if (vbind) {
385 if (vbind->ll != ll) {
386 vty_out(vty, "A bind with the specified ID already exists with a different type (fr|frgre|udp)!%s",
387 VTY_NEWLINE);
388 return CMD_WARNING;
389 }
390 } else {
391 vbind = vty_bind_alloc(name);
392 if (!vbind) {
393 vty_out(vty, "Can not create bind - out of memory%s", VTY_NEWLINE);
394 return CMD_WARNING;
395 }
396 vbind->ll = ll;
397 }
398
399 vty->index = vbind;
400 vty->node = L_NS_BIND_NODE;
401
402 return CMD_SUCCESS;
403}
404
405DEFUN(cfg_no_ns_bind, cfg_no_ns_bind_cmd,
406 "no bind ID",
407 NO_STR
Harald Welte2230a912021-03-04 20:09:50 +0100408 "Delete a bind\n"
409 "Unique identifier for this bind\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100410 )
411{
412 struct vty_bind *vbind;
413 struct gprs_ns2_vc_bind *bind;
414 const char *name = argv[0];
415
416 vbind = vty_bind_by_name(name);
417 if (!vbind) {
418 vty_out(vty, "bind %s does not exist!%s", name, VTY_NEWLINE);
419 return CMD_WARNING;
420 }
421 vty_bind_free(vbind);
422 bind = gprs_ns2_bind_by_name(vty_nsi, name);
423 if (bind)
424 bind->driver->free_bind(bind);
425 return CMD_SUCCESS;
426}
427
428
429static void config_write_vbind(struct vty *vty, struct vty_bind *vbind)
430{
431 struct gprs_ns2_vc_bind *bind;
432 const struct osmo_sockaddr *addr;
433 struct osmo_sockaddr_str addr_str;
434 const char *netif, *frrole_str, *llstr;
435 enum osmo_fr_role frrole;
436
437 llstr = get_value_string_or_null(vty_ll_names, vbind->ll);
438 if (!llstr)
439 return;
440 vty_out(vty, " bind %s %s%s", llstr, vbind->name, VTY_NEWLINE);
441
442 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
443 switch (vbind->ll) {
444 case GPRS_NS2_LL_FR:
445 if (bind) {
446 netif = gprs_ns2_fr_bind_netif(bind);
447 if (!netif)
448 return;
449 frrole = gprs_ns2_fr_bind_role(bind);
450 if ((int) frrole == -1)
451 return;
452 frrole_str = get_value_string_or_null(vty_fr_role_names, frrole);
453 if (netif && frrole_str)
454 vty_out(vty, " fr %s %s%s", netif, frrole_str, VTY_NEWLINE);
455 }
456 break;
457 case GPRS_NS2_LL_UDP:
458 if (bind) {
459 addr = gprs_ns2_ip_bind_sockaddr(bind);
460 if (!osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas)) {
461 vty_out(vty, " listen %s %u%s", addr_str.ip, addr_str.port,
462 VTY_NEWLINE);
463 }
464 }
465 if (vbind->accept_ipaccess)
466 vty_out(vty, " accept-ipaccess%s", VTY_NEWLINE);
Harald Welte42e36462021-03-03 18:12:09 +0100467 if (vbind->accept_sns)
468 vty_out(vty, " accept-dynamic-ip-sns%s", VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100469 if (vbind->dscp)
470 vty_out(vty, " dscp %u%s", vbind->dscp, VTY_NEWLINE);
Daniel Willmann64db6362021-02-12 12:21:45 +0100471 vty_out(vty, " ip-sns signalling-weight %u data-weight %u%s",
Alexander Couzensc4704762021-02-08 23:13:12 +0100472 vbind->ip_sns_sig_weight, vbind->ip_sns_data_weight, VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100473 break;
474 default:
475 return;
476 }
477}
478
479static void config_write_nsvc(struct vty *vty, const struct gprs_ns2_vc *nsvc)
480{
481 const char *netif;
482 uint16_t dlci;
483 const struct osmo_sockaddr *addr;
484 struct osmo_sockaddr_str addr_str;
485
486 switch (nsvc->nse->ll) {
487 case GPRS_NS2_LL_UNDEF:
488 break;
489 case GPRS_NS2_LL_UDP:
490 switch (nsvc->nse->dialect) {
491 case GPRS_NS2_DIALECT_IPACCESS:
492 addr = gprs_ns2_ip_vc_remote(nsvc);
493 if (!addr)
494 break;
495 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas))
496 break;
497 vty_out(vty, " nsvc ipa %s %s %u nsvci %u%s",
498 nsvc->bind->name, addr_str.ip, addr_str.port,
499 nsvc->nsvci, VTY_NEWLINE);
500 break;
501 case GPRS_NS2_DIALECT_STATIC_ALIVE:
502 addr = gprs_ns2_ip_vc_remote(nsvc);
503 if (!addr)
504 break;
505 if (osmo_sockaddr_str_from_sockaddr(&addr_str, &addr->u.sas))
506 break;
507 vty_out(vty, " nsvc udp %s %s %u%s",
508 nsvc->bind->name, addr_str.ip, addr_str.port, VTY_NEWLINE);
509 break;
510 default:
511 break;
512 }
513 break;
514 case GPRS_NS2_LL_FR:
515 netif = gprs_ns2_fr_bind_netif(nsvc->bind);
516 if (!netif)
517 break;
518 dlci = gprs_ns2_fr_nsvc_dlci(nsvc);
519 if (!dlci)
520 break;
521 OSMO_ASSERT(nsvc->nsvci_is_valid);
522 vty_out(vty, " nsvc fr %s dlci %u nsvci %u%s",
523 netif, dlci, nsvc->nsvci, VTY_NEWLINE);
524 break;
525 case GPRS_NS2_LL_FR_GRE:
526 break;
527 }
528}
529
530static void _config_write_ns_nse(struct vty *vty, struct gprs_ns2_nse *nse)
531{
532 struct gprs_ns2_vc *nsvc;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100533 struct vty_nse *vnse = vty_nse_by_nsei(nse->nsei);
534 struct vty_nse_bind *vbind;
535
536 OSMO_ASSERT(vnse);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100537
Harald Welte579699b2021-03-05 10:22:23 +0100538 vty_out(vty, " nse %u%s%s", nse->nsei,
539 nse->ip_sns_role_sgsn ? " ip-sns-role-sgsn" : "", VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100540 switch (nse->dialect) {
541 case GPRS_NS2_DIALECT_SNS:
542 ns2_sns_write_vty(vty, nse);
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100543 llist_for_each_entry(vbind, &vnse->binds, list) {
544 vty_out(vty, " ip-sns-bind %s%s", vbind->vbind->name, VTY_NEWLINE);
545 }
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100546 break;
547 default:
548 llist_for_each_entry(nsvc, &nse->nsvc, list) {
549 config_write_nsvc(vty, nsvc);
550 }
551 break;
552 }
553}
554
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100555static int config_write_ns_nse(struct vty *vty)
556{
557 struct gprs_ns2_nse *nse;
558
559 llist_for_each_entry(nse, &vty_nsi->nse, list) {
560 if (!nse->persistent)
561 continue;
562
563 _config_write_ns_nse(vty, nse);
564 }
565
566 return 0;
567}
568
569static int config_write_ns_bind(struct vty *vty)
570{
571 struct vty_bind *vbind;
572
573 llist_for_each_entry(vbind, &binds, list) {
574 config_write_vbind(vty, vbind);
575 }
576
577 return 0;
578}
579
Alexander Couzens260cd522021-01-28 20:31:31 +0100580static int config_write_ns(struct vty *vty)
581{
Harald Welted164ef82021-03-04 22:29:17 +0100582 struct vty_nse_bind *vbind;
Alexander Couzens260cd522021-01-28 20:31:31 +0100583 unsigned int i;
584 int ret;
585
586 vty_out(vty, "ns%s", VTY_NEWLINE);
587
588 for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++)
589 vty_out(vty, " timer %s %u%s",
590 get_value_string(gprs_ns_timer_strs, i),
591 vty_nsi->timeout[i], VTY_NEWLINE);
592
593 ret = config_write_ns_bind(vty);
594 if (ret)
595 return ret;
596
Harald Welted164ef82021-03-04 22:29:17 +0100597 llist_for_each_entry(vbind, &ip_sns_default_binds, list) {
598 vty_out(vty, " ip-sns-default bind %s%s", vbind->vbind->name, VTY_NEWLINE);
599 }
600
Alexander Couzens260cd522021-01-28 20:31:31 +0100601 ret = config_write_ns_nse(vty);
602 if (ret)
603 return ret;
604
605 return 0;
606}
607
608
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100609static struct cmd_node ns_bind_node = {
610 L_NS_BIND_NODE,
611 "%s(config-ns-bind)# ",
612 1,
613};
614
615DEFUN(cfg_ns_bind_listen, cfg_ns_bind_listen_cmd,
616 "listen " VTY_IPV46_CMD " <1-65535>",
Harald Welte2230a912021-03-04 20:09:50 +0100617 "Configure local IP + Port of this bind\n"
618 "Local IPv4 Address\n" "Local IPv6 Address\n"
619 "Local UDP Port\n"
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100620 )
621{
622 struct vty_bind *vbind = vty->index;
623 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100624 int rc;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100625 const char *addr_str = argv[0];
626 unsigned int port = atoi(argv[1]);
627 struct osmo_sockaddr_str sockaddr_str;
628 struct osmo_sockaddr sockaddr;
629
630 if (vbind->ll != GPRS_NS2_LL_UDP) {
631 vty_out(vty, "listen can be only used with UDP bind%s",
632 VTY_NEWLINE);
633 return CMD_WARNING;
634 }
635
636 if (osmo_sockaddr_str_from_str(&sockaddr_str, addr_str, port)) {
637 vty_out(vty, "Can not parse the Address %s %s%s", argv[0], argv[1], VTY_NEWLINE);
638 return CMD_WARNING;
639 }
640 osmo_sockaddr_str_to_sockaddr(&sockaddr_str, &sockaddr.u.sas);
641 if (gprs_ns2_ip_bind_by_sockaddr(vty_nsi, &sockaddr)) {
642 vty_out(vty, "A bind with the specified address already exists!%s", VTY_NEWLINE);
643 return CMD_WARNING;
644 }
645
Alexander Couzens6b9d2322021-02-12 03:17:59 +0100646 rc = gprs_ns2_ip_bind(vty_nsi, vbind->name, &sockaddr, vbind->dscp, &bind);
647 if (rc != 0) {
648 vty_out(vty, "Failed to create the bind (rc %d)!%s", rc, VTY_NEWLINE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100649 return CMD_WARNING;
650 }
651
652 bind->accept_ipaccess = vbind->accept_ipaccess;
653 bind->accept_sns = vbind->accept_sns;
654
655 return CMD_SUCCESS;
656}
657
658DEFUN(cfg_no_ns_bind_listen, cfg_no_ns_bind_listen_cmd,
659 "no listen",
660 NO_STR
661 "Delete a IP/Port assignment\n"
662 )
663{
664 struct vty_bind *vbind = vty->index;
665 struct gprs_ns2_vc_bind *bind;
666
667 if (vbind->ll != GPRS_NS2_LL_UDP) {
668 vty_out(vty, "no listen can be only used with UDP bind%s", VTY_NEWLINE);
669 return CMD_WARNING;
670 }
671
672 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
673 if (!bind)
674 return CMD_ERR_NOTHING_TODO;
675
Daniel Willmann90432052021-01-26 16:09:18 +0100676 OSMO_ASSERT(bind->ll == GPRS_NS2_LL_UDP);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100677 bind->driver->free_bind(bind);
678 return CMD_SUCCESS;
679}
680
681DEFUN(cfg_ns_bind_dscp, cfg_ns_bind_dscp_cmd,
682 "dscp <0-255>",
683 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
684{
685 struct vty_bind *vbind = vty->index;
686 struct gprs_ns2_vc_bind *bind;
687 uint16_t dscp = atoi(argv[0]);
688
689 if (vbind->ll != GPRS_NS2_LL_UDP) {
690 vty_out(vty, "dscp can be only used with UDP bind%s",
691 VTY_NEWLINE);
692 return CMD_WARNING;
693 }
694
695 vbind->dscp = dscp;
696 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
697 if (bind)
698 gprs_ns2_ip_bind_set_dscp(bind, dscp);
699
700 return CMD_SUCCESS;
701}
702
703DEFUN(cfg_no_ns_bind_dscp, cfg_no_ns_bind_dscp_cmd,
704 "no dscp",
705 "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n")
706{
707 struct vty_bind *vbind = vty->index;
708 struct gprs_ns2_vc_bind *bind;
709 uint16_t dscp = 0;
710
711 if (vbind->ll != GPRS_NS2_LL_UDP) {
712 vty_out(vty, "dscp can be only used with UDP bind%s",
713 VTY_NEWLINE);
714 return CMD_WARNING;
715 }
716
717 vbind->dscp = dscp;
718 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
719 if (bind)
720 gprs_ns2_ip_bind_set_dscp(bind, dscp);
721
722 return CMD_SUCCESS;
723}
724
725DEFUN(cfg_ns_bind_ipaccess, cfg_ns_bind_ipaccess_cmd,
726 "accept-ipaccess",
727 "Allow to create dynamic NS Entity by NS Reset PDU on UDP (ip.access style)\n"
728 )
729{
730 struct vty_bind *vbind = vty->index;
731 struct gprs_ns2_vc_bind *bind;
732
733 if (vbind->ll != GPRS_NS2_LL_UDP) {
734 vty_out(vty, "accept-ipaccess can be only used with UDP bind%s",
735 VTY_NEWLINE);
736 return CMD_WARNING;
737 }
738
739 vbind->accept_ipaccess = true;
740 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
741 if (bind)
742 bind->accept_ipaccess = true;
743
744 return CMD_SUCCESS;
745}
746
747DEFUN(cfg_no_ns_bind_ipaccess, cfg_no_ns_bind_ipaccess_cmd,
748 "no accept-ipaccess",
749 NO_STR
750 "Reject NS Reset PDU on UDP (ip.access style)\n"
751 )
752{
753 struct vty_bind *vbind = vty->index;
754 struct gprs_ns2_vc_bind *bind;
755
756 if (vbind->ll != GPRS_NS2_LL_UDP) {
757 vty_out(vty, "no accept-ipaccess can be only used with UDP bind%s",
758 VTY_NEWLINE);
759 return CMD_WARNING;
760 }
761
762 vbind->accept_ipaccess = false;
763 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
764 if (bind)
765 bind->accept_ipaccess = false;
766
767 return CMD_SUCCESS;
768}
769
Harald Welte42e36462021-03-03 18:12:09 +0100770DEFUN(cfg_ns_bind_accept_sns, cfg_ns_bind_accept_sns_cmd,
771 "accept-dynamic-ip-sns",
772 "Allow to create dynamic NS Entities by IP-SNS PDUs\n"
773 )
774{
775 struct vty_bind *vbind = vty->index;
776 struct gprs_ns2_vc_bind *bind;
777
778 if (vbind->ll != GPRS_NS2_LL_UDP) {
779 vty_out(vty, "accept-dynamic-ip-sns can be only used with UDP bind%s",
780 VTY_NEWLINE);
781 return CMD_WARNING;
782 }
783
784 vbind->accept_sns = true;
785 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
786 if (bind)
787 bind->accept_sns = true;
788
789 return CMD_SUCCESS;
790}
791
792DEFUN(cfg_no_ns_bind_accept_sns, cfg_no_ns_bind_accept_sns_cmd,
793 "no accept-dynamic-ip-sns",
794 NO_STR
795 "Disable dynamic creation of NS Entities by IP-SNS PDUs\n"
796 )
797{
798 struct vty_bind *vbind = vty->index;
799 struct gprs_ns2_vc_bind *bind;
800
801 if (vbind->ll != GPRS_NS2_LL_UDP) {
802 vty_out(vty, "no accept-dynamic-ip-sns can be only used with UDP bind%s",
803 VTY_NEWLINE);
804 return CMD_WARNING;
805 }
806
807 vbind->accept_sns = false;
808 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
809 if (bind)
810 bind->accept_sns = false;
811
812 return CMD_SUCCESS;
813}
814
Alexander Couzensc4704762021-02-08 23:13:12 +0100815DEFUN(cfg_ns_bind_ip_sns_weight, cfg_ns_bind_ip_sns_weight_cmd,
816 "ip-sns signalling-weight <0-254> data-weight <0-254>",
817 "IP SNS\n"
818 "signalling weight used by IP-SNS dynamic configuration\n"
819 "signalling weight used by IP-SNS dynamic configuration\n"
820 "data weight used by IP-SNS dynamic configuration\n"
821 "data weight used by IP-SNS dynamic configuration\n")
822{
823 struct vty_bind *vbind = vty->index;
824 struct gprs_ns2_vc_bind *bind;
825
826 int signalling = atoi(argv[0]);
827 int data = atoi(argv[1]);
828
829 if (vbind->ll != GPRS_NS2_LL_UDP) {
830 vty_out(vty, "ip-sns signalling-weight <0-254> data-weight <0-254> can be only used with UDP bind%s",
831 VTY_NEWLINE);
832 return CMD_WARNING;
833 }
834
835 vbind->ip_sns_data_weight = data;
836 vbind->ip_sns_sig_weight = signalling;
837 bind = gprs_ns2_bind_by_name(vty_nsi, vbind->name);
838 if (bind)
839 gprs_ns2_ip_bind_set_sns_weight(bind, signalling, data);
840
841 return CMD_SUCCESS;
842}
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100843
844DEFUN(cfg_ns_bind_fr, cfg_ns_bind_fr_cmd,
845 "fr NETIF (fr|frnet)",
846 "frame relay\n"
847 IFNAME_STR
848 "fr (user) is used by BSS or SGSN attached to UNI of a FR network\n"
849 "frnet (network) is used by SGSN if BSS is directly attached\n"
850 )
851{
852 struct vty_bind *vbind = vty->index;
853 struct gprs_ns2_vc_bind *bind;
854 const char *netif = argv[0];
855 const char *role = argv[1];
856
857 int rc = 0;
858 enum osmo_fr_role frrole;
859
860 if (vbind->ll != GPRS_NS2_LL_FR) {
861 vty_out(vty, "fr can be only used with frame relay bind%s", VTY_NEWLINE);
862 return CMD_WARNING;
863 }
864
865 if (!strcmp(role, "fr"))
866 frrole = FR_ROLE_USER_EQUIPMENT;
867 else if (!strcmp(role, "frnet"))
868 frrole = FR_ROLE_NETWORK_EQUIPMENT;
869 else
870 return CMD_WARNING;
871
872 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
873 if (bind) {
874 vty_out(vty, "Interface %s already used.%s", netif, VTY_NEWLINE);
875 return CMD_WARNING;
876 }
877
878 rc = gprs_ns2_fr_bind(vty_nsi, vbind->name, netif, vty_fr_network, frrole, &bind);
879 if (rc < 0) {
880 LOGP(DLNS, LOGL_ERROR, "Failed to bind interface %s on fr. Err: %d\n", netif, rc);
881 return CMD_WARNING;
882 }
883
884 return CMD_SUCCESS;
885}
886
887DEFUN(cfg_no_ns_bind_fr, cfg_no_ns_bind_fr_cmd,
888 "no fr NETIF",
889 NO_STR
890 "Delete a frame relay link\n"
891 "Delete a frame relay link\n"
892 IFNAME_STR
893 )
894{
895 struct vty_bind *vbind = vty->index;
896 struct gprs_ns2_vc_bind *bind;
897 const char *netif = argv[0];
898
899 if (vbind->ll != GPRS_NS2_LL_FR) {
900 vty_out(vty, "fr can be only used with frame relay bind%s",
901 VTY_NEWLINE);
902 return CMD_WARNING;
903 }
904
905 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
906 if (!bind) {
907 vty_out(vty, "Interface not found.%s", VTY_NEWLINE);
908 return CMD_WARNING;
909 }
910
911 if (strcmp(bind->name, vbind->name)) {
912 vty_out(vty, "The specified interface is not bound to this bind.%s", VTY_NEWLINE);
913 return CMD_WARNING;
914 }
915
916 bind->driver->free_bind(bind);
917 return CMD_SUCCESS;
918}
919
920
921static struct cmd_node ns_nse_node = {
922 L_NS_NSE_NODE,
923 "%s(config-ns-nse)# ",
924 1,
925};
926
927DEFUN(cfg_ns_nse_nsvc_fr, cfg_ns_nse_nsvc_fr_cmd,
928 "nsvc fr NETIF dlci <16-1007> nsvci <0-65535>",
929 "NS Virtual Connection\n"
930 "frame relay\n"
931 "frame relay interface. Must be registered via fr vty\n"
932 NSVCI_STR
933 NSVCI_STR
934 DLCI_STR
935 DLCI_STR
936 )
937{
938 struct gprs_ns2_vc_bind *bind;
939 struct gprs_ns2_vc *nsvc;
940 struct gprs_ns2_nse *nse = vty->index;
941 const char *netif = argv[0];
942 uint16_t dlci = atoi(argv[1]);
943 uint16_t nsvci = atoi(argv[2]);
944 bool dialect_modified = false;
945 bool ll_modified = false;
946
947 if (nse->ll != GPRS_NS2_LL_FR && nse->ll != GPRS_NS2_LL_UNDEF) {
948 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
949 goto err;
950 }
951
952 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_RESETBLOCK && nse->dialect != GPRS_NS2_DIALECT_UNDEF) {
953 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
954 goto err;
955 }
956
957 if (nse->ll == GPRS_NS2_LL_UNDEF) {
958 nse->ll = GPRS_NS2_LL_FR;
959 ll_modified = true;
960 }
961
962 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +0100963 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_STATIC_RESETBLOCK);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100964 dialect_modified = true;
965 }
966
967
968 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
969 if (!bind) {
970 vty_out(vty, "Can not find fr interface \"%s\". Please configure it via fr vty.%s",
971 netif, VTY_NEWLINE);
972 goto err;
973 }
974
975 if (gprs_ns2_fr_nsvc_by_dlci(bind, dlci)) {
976 vty_out(vty, "A NS-VC with the specified DLCI already exist!%s", VTY_NEWLINE);
977 goto err;
978 }
979
980 if (gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci)) {
981 vty_out(vty, "A NS-VC with the specified NS-VCI already exist!%s", VTY_NEWLINE);
982 goto err;
983 }
984
985 nsvc = gprs_ns2_fr_connect(bind, nse, nsvci, dlci);
986 if (!nsvc) {
987 /* Could not create NS-VC, connect failed */
988 vty_out(vty, "Failed to create the NS-VC%s", VTY_NEWLINE);
989 goto err;
990 }
991 nsvc->persistent = true;
992 return CMD_SUCCESS;
993
994err:
995 if (ll_modified)
996 nse->ll = GPRS_NS2_LL_UNDEF;
997 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +0100998 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +0100999
1000 return CMD_WARNING;
1001}
1002
1003DEFUN(cfg_no_ns_nse_nsvc_fr_dlci, cfg_no_ns_nse_nsvc_fr_dlci_cmd,
1004 "no nsvc fr NETIF dlci <16-1007>",
1005 NO_STR
1006 "Delete frame relay NS-VC\n"
1007 "frame relay\n"
1008 "frame relay interface. Must be registered via fr vty\n"
1009 DLCI_STR
1010 DLCI_STR
1011 )
1012{
1013 struct gprs_ns2_vc_bind *bind;
1014 struct gprs_ns2_vc *nsvc;
1015 struct gprs_ns2_nse *nse = vty->index;
1016 const char *netif = argv[0];
1017 uint16_t dlci = atoi(argv[1]);
1018
1019 if (nse->ll != GPRS_NS2_LL_FR) {
1020 vty_out(vty, "This NSE doesn't support frame relay.%s", VTY_NEWLINE);
1021 return CMD_WARNING;
1022 }
1023
1024 bind = gprs_ns2_fr_bind_by_netif(vty_nsi, netif);
1025 if (!bind) {
1026 vty_out(vty, "Can not find fr interface \"%s\"%s",
1027 netif, VTY_NEWLINE);
1028 return CMD_ERR_NOTHING_TODO;
1029 }
1030
1031 nsvc = gprs_ns2_fr_nsvc_by_dlci(bind, dlci);
1032 if (!nsvc) {
1033 vty_out(vty, "Can not find a NS-VC on fr interface %s with dlci %u%s",
1034 netif, dlci, VTY_NEWLINE);
1035 return CMD_WARNING;
1036 }
1037
1038 if (nse != nsvc->nse) {
1039 vty_out(vty, "The specified NS-VC is not a part of the NSE %u!%s"
1040 "To remove this NS-VC go to the vty node 'nse %u'%s",
1041 nse->nsei, VTY_NEWLINE,
1042 nsvc->nse->nsei, VTY_NEWLINE);
1043 return CMD_WARNING;
1044 }
1045
1046 gprs_ns2_free_nsvc(nsvc);
1047 if (llist_empty(&nse->nsvc)) {
1048 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001049 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001050 }
1051
1052 return CMD_SUCCESS;
1053}
1054
1055DEFUN(cfg_no_ns_nse_nsvci, cfg_no_ns_nse_nsvci_cmd,
1056 "no nsvc nsvci <0-65535>",
1057 NO_STR
1058 "Delete NSVC\n"
1059 NSVCI_STR
1060 NSVCI_STR
1061 )
1062{
1063 struct gprs_ns2_vc *nsvc;
1064 struct gprs_ns2_nse *nse = vty->index;
1065 uint16_t nsvci = atoi(argv[0]);
1066
1067 switch (nse->dialect) {
1068 case GPRS_NS2_DIALECT_SNS:
1069 case GPRS_NS2_DIALECT_STATIC_ALIVE:
1070 vty_out(vty, "NSE doesn't support NSVCI.%s", VTY_NEWLINE);
1071 return CMD_WARNING;
1072 case GPRS_NS2_DIALECT_UNDEF:
1073 vty_out(vty, "No NSVCs configured%s", VTY_NEWLINE);
1074 return CMD_WARNING;
1075 case GPRS_NS2_DIALECT_IPACCESS:
1076 case GPRS_NS2_DIALECT_STATIC_RESETBLOCK:
1077 break;
1078 }
1079
1080 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, nsvci);
1081 if (!nsvc) {
1082 vty_out(vty, "Can not find NS-VC with NS-VCI %u%s", nsvci, VTY_NEWLINE);
1083 return CMD_WARNING;
1084 }
1085
1086 if (nse != nsvc->nse) {
1087 vty_out(vty, "NS-VC with NS-VCI %u is not part of this NSE!%s",
1088 nsvci, VTY_NEWLINE);
1089 return CMD_WARNING;
1090 }
1091
1092 gprs_ns2_free_nsvc(nsvc);
1093 if (llist_empty(&nse->nsvc)) {
1094 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001095 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001096 }
1097
1098 return CMD_SUCCESS;
1099}
1100
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001101static int ns_nse_nsvc_udp_cmds(struct vty *vty, const char *bind_name, const char *remote_char, uint16_t port,
1102 uint16_t sig_weight, uint16_t data_weight)
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001103{
1104 struct gprs_ns2_vc_bind *bind;
1105 struct gprs_ns2_vc *nsvc;
1106 struct gprs_ns2_nse *nse = vty->index;
1107 bool dialect_modified = false;
1108 bool ll_modified = false;
1109
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001110 struct osmo_sockaddr_str remote_str;
1111 struct osmo_sockaddr remote;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001112
1113 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1114 nse->ll = GPRS_NS2_LL_UDP;
1115 ll_modified = true;
1116 }
1117
1118 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001119 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_STATIC_ALIVE);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001120 dialect_modified = true;
1121 }
1122
1123 if (nse->ll != GPRS_NS2_LL_UDP) {
1124 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1125 goto err;
1126 }
1127
1128 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
1129 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1130 goto err;
1131 }
1132
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001133 if (osmo_sockaddr_str_from_str(&remote_str, remote_char, port)) {
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001134 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1135 goto err;
1136 }
1137
1138 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1139 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1140 goto err;
1141 }
1142
1143 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1144 if (!bind) {
1145 vty_out(vty, "Can not find bind with name %s%s",
1146 bind_name, VTY_NEWLINE);
1147 goto err;
1148 }
1149
1150 if (bind->ll != GPRS_NS2_LL_UDP) {
1151 vty_out(vty, "Bind %s is not an UDP bind.%s",
1152 bind_name, VTY_NEWLINE);
1153 goto err;
1154 }
1155
Alexander Couzens7bb39e32021-02-16 23:06:53 +01001156 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1157 if (nsvc) {
1158 if (nsvc->nse == nse)
1159 vty_out(vty, "Specified NSVC is already present in this NSE.%s", VTY_NEWLINE);
1160 else
1161 vty_out(vty, "Specified NSVC is already present in another NSE%05u.%s", nsvc->nse->nsei, VTY_NEWLINE);
1162 goto err;
1163 }
1164
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001165 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, 0);
1166 if (!nsvc) {
1167 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
1168 goto err;
1169 }
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001170 nsvc->sig_weight = sig_weight;
1171 nsvc->data_weight = data_weight;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001172 nsvc->persistent = true;
1173
1174 return CMD_SUCCESS;
1175
1176err:
1177 if (ll_modified)
1178 nse->ll = GPRS_NS2_LL_UNDEF;
1179 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001180 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001181 return CMD_WARNING;
1182}
1183
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01001184DEFUN(cfg_ns_nse_nsvc_udp, cfg_ns_nse_nsvc_udp_cmd,
1185 "nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
1186 "NS Virtual Connection\n"
1187 "NS over UDP\n"
1188 "A unique bind identifier created by ns bind\n"
1189 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1190 "Remote UDP Port\n")
1191{
1192 const char *bind_name = argv[0];
1193 const char *remote = argv[1];
1194 uint16_t port = atoi(argv[2]);
1195 uint16_t sig_weight = 1;
1196 uint16_t data_weight = 1;
1197
1198 return ns_nse_nsvc_udp_cmds(vty, bind_name, remote, port, sig_weight, data_weight);
1199}
1200
1201DEFUN(cfg_ns_nse_nsvc_udp_weights, cfg_ns_nse_nsvc_udp_weights_cmd,
1202 "nsvc udp BIND " VTY_IPV46_CMD " <1-65535> signalling-weight <0-254> data-weight <0-254>",
1203 "NS Virtual Connection\n"
1204 "NS over UDP\n"
1205 "A unique bind identifier created by ns bind\n"
1206 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1207 "Remote UDP Port\n"
1208 "Signalling weight of the NSVC (default = 1)\n"
1209 "Signalling weight of the NSVC (default = 1)\n"
1210 "Data weight of the NSVC (default = 1)\n"
1211 "Data weight of the NSVC (default = 1)\n"
1212 )
1213{
1214 const char *bind_name = argv[0];
1215 const char *remote = argv[1];
1216 uint16_t port = atoi(argv[2]);
1217 uint16_t sig_weight = atoi(argv[3]);
1218 uint16_t data_weight = atoi(argv[4]);
1219
1220 return ns_nse_nsvc_udp_cmds(vty, bind_name, remote, port, sig_weight, data_weight);
1221}
1222
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001223DEFUN(cfg_no_ns_nse_nsvc_udp, cfg_no_ns_nse_nsvc_udp_cmd,
1224 "no nsvc udp BIND " VTY_IPV46_CMD " <1-65535>",
1225 NO_STR
1226 "Delete a NS Virtual Connection\n"
1227 "NS over UDP\n"
1228 "A unique bind identifier created by ns bind\n"
1229 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1230 "Remote UDP Port\n"
1231 )
1232{
1233 struct gprs_ns2_vc_bind *bind;
1234 struct gprs_ns2_vc *nsvc;
1235 struct gprs_ns2_nse *nse = vty->index;
1236 const char *bind_name = argv[0];
1237 struct osmo_sockaddr_str remote_str;
1238 struct osmo_sockaddr remote;
1239 uint16_t port = atoi(argv[2]);
1240
1241 if (nse->ll != GPRS_NS2_LL_UDP) {
1242 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1243 return CMD_WARNING;
1244 }
1245
1246 if (nse->dialect != GPRS_NS2_DIALECT_STATIC_ALIVE) {
1247 vty_out(vty, "This NSE doesn't support UDP with dialect static alive.%s", VTY_NEWLINE);
1248 return CMD_WARNING;
1249 }
1250
1251 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1252 if (!bind) {
1253 vty_out(vty, "Can not find bind with name %s%s",
1254 bind_name, VTY_NEWLINE);
1255 return CMD_WARNING;
1256 }
1257
1258 if (bind->ll != GPRS_NS2_LL_UDP) {
1259 vty_out(vty, "Bind %s is not an UDP bind.%s",
1260 bind_name, VTY_NEWLINE);
1261 return CMD_WARNING;
1262 }
1263
1264 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1265 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1266 return CMD_WARNING;
1267 }
1268
1269 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1270 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1271 return CMD_WARNING;
1272 }
1273
1274 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1275 if (!nsvc) {
1276 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1277 remote_str.ip, remote_str.port, VTY_NEWLINE);
1278 return CMD_WARNING;
1279 }
1280
1281 if (!nsvc->persistent) {
1282 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1283 remote_str.ip, remote_str.port, VTY_NEWLINE);
1284 return CMD_WARNING;
1285 }
1286
1287 if (nsvc->nse != nse) {
1288 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1289 return CMD_WARNING;
1290 }
1291
1292 gprs_ns2_free_nsvc(nsvc);
1293 if (llist_empty(&nse->nsvc)) {
1294 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001295 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001296 }
1297
1298 return CMD_SUCCESS;
1299}
1300
1301DEFUN(cfg_ns_nse_nsvc_ipa, cfg_ns_nse_nsvc_ipa_cmd,
1302 "nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>" ,
1303 "NS Virtual Connection\n"
1304 "NS over UDP ip.access style (uses RESET/BLOCK)\n"
1305 "A unique bind identifier created by ns bind\n"
1306 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1307 "Remote UDP Port\n"
1308 NSVCI_STR
1309 NSVCI_STR
1310 )
1311{
1312 struct gprs_ns2_vc_bind *bind;
1313 struct gprs_ns2_vc *nsvc;
1314 struct gprs_ns2_nse *nse = vty->index;
1315 bool dialect_modified = false;
1316 bool ll_modified = false;
1317
1318 const char *bind_name = argv[0];
1319 struct osmo_sockaddr_str remote_str;
1320 struct osmo_sockaddr remote;
1321 uint16_t port = atoi(argv[2]);
1322 uint16_t nsvci = atoi(argv[3]);
1323
1324 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1325 nse->ll = GPRS_NS2_LL_UDP;
1326 ll_modified = true;
1327 }
1328
1329 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001330 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_IPACCESS);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001331 dialect_modified = true;
1332 }
1333
1334 if (nse->ll != GPRS_NS2_LL_UDP) {
1335 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1336 goto err;
1337 }
1338
1339 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1340 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1341 goto err;
1342 }
1343
1344 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1345 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1346 goto err;
1347 }
1348
1349 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1350 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1351 goto err;
1352 }
1353
1354 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1355 if (!bind) {
1356 vty_out(vty, "Can not find bind with name %s%s",
1357 bind_name, VTY_NEWLINE);
1358 goto err;
1359 }
1360
1361 if (bind->ll != GPRS_NS2_LL_UDP) {
1362 vty_out(vty, "Bind %s is not an UDP bind.%s",
1363 bind_name, VTY_NEWLINE);
1364 goto err;
1365 }
1366
1367 nsvc = gprs_ns2_ip_connect(bind, &remote, nse, nsvci);
1368 if (!nsvc) {
1369 vty_out(vty, "Can not create NS-VC.%s", VTY_NEWLINE);
1370 goto err;
1371 }
1372 nsvc->persistent = true;
1373
1374 return CMD_SUCCESS;
1375
1376err:
1377 if (ll_modified)
1378 nse->ll = GPRS_NS2_LL_UNDEF;
1379 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001380 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001381 return CMD_WARNING;
1382}
1383
1384DEFUN(cfg_no_ns_nse_nsvc_ipa, cfg_no_ns_nse_nsvc_ipa_cmd,
1385 "no nsvc ipa BIND " VTY_IPV46_CMD " <1-65535> nsvci <0-65535>",
1386 NO_STR
1387 "Delete a NS Virtual Connection\n"
1388 "NS over UDP\n"
1389 "A unique bind identifier created by ns bind\n"
1390 "Remote IPv4 Address\n" "Remote IPv6 Address\n"
1391 "Remote UDP Port\n"
1392 NSVCI_STR
1393 NSVCI_STR
1394 )
1395{
1396 struct gprs_ns2_vc_bind *bind;
1397 struct gprs_ns2_vc *nsvc;
1398 struct gprs_ns2_nse *nse = vty->index;
1399 const char *bind_name = argv[0];
1400 struct osmo_sockaddr_str remote_str;
1401 struct osmo_sockaddr remote;
1402 uint16_t port = atoi(argv[2]);
1403 uint16_t nsvci = atoi(argv[3]);
1404
1405 if (nse->ll != GPRS_NS2_LL_UDP) {
1406 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1407 return CMD_WARNING;
1408 }
1409
1410 if (nse->dialect != GPRS_NS2_DIALECT_IPACCESS) {
1411 vty_out(vty, "This NSE doesn't support UDP with dialect ipaccess.%s", VTY_NEWLINE);
1412 return CMD_WARNING;
1413 }
1414
1415 bind = gprs_ns2_bind_by_name(vty_nsi, bind_name);
1416 if (!bind) {
1417 vty_out(vty, "Can not find bind with name %s%s",
1418 bind_name, VTY_NEWLINE);
1419 return CMD_WARNING;
1420 }
1421
1422 if (bind->ll != GPRS_NS2_LL_UDP) {
1423 vty_out(vty, "Bind %s is not an UDP bind.%s",
1424 bind_name, VTY_NEWLINE);
1425 return CMD_WARNING;
1426 }
1427
1428 if (osmo_sockaddr_str_from_str(&remote_str, argv[1], port)) {
1429 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1430 return CMD_WARNING;
1431 }
1432
1433 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1434 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1435 return CMD_WARNING;
1436 }
1437
1438 nsvc = gprs_ns2_nsvc_by_sockaddr_bind(bind, &remote);
1439 if (!nsvc) {
1440 vty_out(vty, "Can not find NS-VC with remote %s:%u%s",
1441 remote_str.ip, remote_str.port, VTY_NEWLINE);
1442 return CMD_WARNING;
1443 }
1444
1445 if (!nsvc->persistent) {
1446 vty_out(vty, "NS-VC with remote %s:%u is a dynamic NS-VC. Not configured by vty.%s",
1447 remote_str.ip, remote_str.port, VTY_NEWLINE);
1448 return CMD_WARNING;
1449 }
1450
1451 if (nsvc->nse != nse) {
1452 vty_out(vty, "NS-VC is not part of this NSE!%s", VTY_NEWLINE);
1453 return CMD_WARNING;
1454 }
1455
1456 if (!nsvc->nsvci_is_valid) {
1457 vty_out(vty, "NS-VC doesn't have a nsvci!%s", VTY_NEWLINE);
1458 return CMD_WARNING;
1459 }
1460
1461 if (nsvc->nsvci != nsvci) {
1462 vty_out(vty, "NS-VC has a different nsvci (%u)!%s",
1463 nsvc->nsvci, VTY_NEWLINE);
1464 return CMD_WARNING;
1465 }
1466
1467 gprs_ns2_free_nsvc(nsvc);
1468 if (llist_empty(&nse->nsvc)) {
1469 nse->ll = GPRS_NS2_LL_UNDEF;
Harald Welte06d9bf92021-03-05 10:20:11 +01001470 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001471 }
1472
1473 return CMD_SUCCESS;
1474}
1475
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001476DEFUN(cfg_ns_nse_ip_sns_remote, cfg_ns_nse_ip_sns_remote_cmd,
1477 "ip-sns-remote " VTY_IPV46_CMD " <1-65535>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001478 "SNS Initial Endpoint\n"
1479 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1480 "SGSN UDP Port\n"
1481 )
1482{
1483 struct gprs_ns2_nse *nse = vty->index;
1484 bool dialect_modified = false;
1485 bool ll_modified = false;
1486 int rc;
1487
1488 /* argv[0] */
1489 struct osmo_sockaddr_str remote_str;
1490 struct osmo_sockaddr remote;
1491 uint16_t port = atoi(argv[1]);
1492
1493 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1494 nse->ll = GPRS_NS2_LL_UDP;
1495 ll_modified = true;
1496 }
1497
1498 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001499 if (ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_SNS) < 0)
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001500 goto err;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001501 dialect_modified = true;
1502 }
1503
1504 if (nse->ll != GPRS_NS2_LL_UDP) {
1505 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1506 goto err;
1507 }
1508
1509 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1510 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1511 goto err;
1512 }
1513
1514 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1515 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1516 goto err;
1517 }
1518
1519 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1520 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1521 goto err;
1522 }
1523
1524 rc = gprs_ns2_sns_add_endpoint(nse, &remote);
1525 switch (rc) {
1526 case 0:
1527 return CMD_SUCCESS;
1528 case -EADDRINUSE:
1529 vty_out(vty, "Specified SNS endpoint already part of the NSE.%s", VTY_NEWLINE);
1530 return CMD_WARNING;
1531 default:
1532 vty_out(vty, "Can not add specified SNS endpoint.%s", VTY_NEWLINE);
1533 return CMD_WARNING;
1534 }
1535
1536err:
1537 if (ll_modified)
1538 nse->ll = GPRS_NS2_LL_UNDEF;
1539 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001540 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001541 return CMD_WARNING;
1542}
1543
Alexander Couzens5fa431c2021-02-08 23:21:54 +01001544DEFUN(cfg_no_ns_nse_ip_sns_remote, cfg_no_ns_nse_ip_sns_remote_cmd,
1545 "no ip-sns-remote " VTY_IPV46_CMD " <1-65535>",
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001546 NO_STR
1547 "Delete a SNS Initial Endpoint\n"
1548 "SGSN IPv4 Address\n" "SGSN IPv6 Address\n"
1549 "SGSN UDP Port\n"
1550 )
1551{
1552 struct gprs_ns2_nse *nse = vty->index;
1553 struct osmo_sockaddr_str remote_str; /* argv[0] */
1554 struct osmo_sockaddr remote;
1555 uint16_t port = atoi(argv[1]);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001556
1557 if (nse->ll != GPRS_NS2_LL_UDP) {
1558 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1559 return CMD_WARNING;
1560 }
1561
1562 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1563 vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%s", VTY_NEWLINE);
1564 return CMD_WARNING;
1565 }
1566
1567 if (osmo_sockaddr_str_from_str(&remote_str, argv[0], port)) {
1568 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1569 return CMD_WARNING;
1570 }
1571
1572 if (osmo_sockaddr_str_to_sockaddr(&remote_str, &remote.u.sas)) {
1573 vty_out(vty, "Can not parse IPv4/IPv6 or port.%s", VTY_NEWLINE);
1574 return CMD_WARNING;
1575 }
1576
1577 if (gprs_ns2_sns_del_endpoint(nse, &remote)) {
1578 vty_out(vty, "Can not remove specified SNS endpoint.%s", VTY_NEWLINE);
1579 return CMD_WARNING;
1580 }
1581
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001582 if (vty_nse_check_sns(nse)) {
1583 /* there is still sns configuration valid */
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001584 return CMD_SUCCESS;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001585 } else {
1586 /* clean up nse to allow other nsvc commands */
Harald Welte06d9bf92021-03-05 10:20:11 +01001587 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001588 nse->ll = GPRS_NS2_LL_UNDEF;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001589 }
1590
1591 return CMD_SUCCESS;
1592}
1593
Harald Welted164ef82021-03-04 22:29:17 +01001594/* add all IP-SNS default binds to the given NSE */
1595int ns2_sns_add_sns_default_binds(struct gprs_ns2_nse *nse)
1596{
1597 struct vty_nse_bind *vnse_bind;
1598 int count = 0;
1599
1600 OSMO_ASSERT(nse->ll == GPRS_NS2_LL_UDP);
1601 OSMO_ASSERT(nse->dialect == GPRS_NS2_DIALECT_SNS);
1602
1603 llist_for_each_entry(vnse_bind, &ip_sns_default_binds, list) {
1604 struct gprs_ns2_vc_bind *bind = gprs_ns2_bind_by_name(vty_nsi, vnse_bind->vbind->name);
1605 /* the bind might not yet created because "listen" is missing. */
1606 if (!bind)
1607 continue;
1608 gprs_ns2_sns_add_bind(nse, bind);
1609 count++;
1610 }
1611 return count;
1612}
1613
1614DEFUN(cfg_ns_ip_sns_default_bind, cfg_ns_ip_sns_default_bind_cmd,
1615 "ip-sns-default bind ID",
1616 "Defaults for dynamically created NSEs created by IP-SNS in SGSN role\n"
1617 "IP SNS binds\n"
1618 "Name of NS udp bind whose IP endpoint will be used as IP-SNS local endpoint. Can be given multiple times.\n")
1619{
1620 struct vty_bind *vbind;
1621 struct vty_nse_bind *vnse_bind;
1622 const char *name = argv[0];
1623
1624 vbind = vty_bind_by_name(name);
1625 if (!vbind) {
1626 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1627 return CMD_WARNING;
1628 }
1629
1630 if (vbind->ll != GPRS_NS2_LL_UDP) {
1631 vty_out(vty, "ip-sns-default bind can only be used with UDP bind%s", VTY_NEWLINE);
1632 return CMD_WARNING;
1633 }
1634
1635 llist_for_each_entry(vnse_bind, &ip_sns_default_binds, list) {
1636 if (vnse_bind->vbind == vbind)
1637 return CMD_SUCCESS;
1638 }
1639
1640 vnse_bind = talloc(vty_nsi, struct vty_nse_bind);
1641 if (!vnse_bind)
1642 return CMD_WARNING;
1643 vnse_bind->vbind = vbind;
1644
1645 llist_add_tail(&vnse_bind->list, &ip_sns_default_binds);
1646
1647 return CMD_SUCCESS;
1648}
1649
1650DEFUN(cfg_no_ns_ip_sns_default_bind, cfg_no_ns_ip_sns_default_bind_cmd,
1651 "no ip-sns-default bind ID",
1652 NO_STR "Defaults for dynamically created NSEs created by IP-SNS in SGSN role\n"
1653 "IP SNS binds\n"
1654 "Name of NS udp bind whose IP endpoint will be removed as IP-SNS local endpoint.\n")
1655{
1656 struct vty_bind *vbind;
1657 struct vty_nse_bind *vnse_bind;
1658 const char *name = argv[0];
1659
1660 vbind = vty_bind_by_name(name);
1661 if (!vbind) {
1662 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1663 return CMD_WARNING;
1664 }
1665
1666 if (vbind->ll != GPRS_NS2_LL_UDP) {
1667 vty_out(vty, "ip-sns-default bind can only be used with UDP bind%s", VTY_NEWLINE);
1668 return CMD_WARNING;
1669 }
1670
1671 llist_for_each_entry(vnse_bind, &ip_sns_default_binds, list) {
1672 if (vnse_bind->vbind == vbind) {
1673 llist_del(&vnse_bind->list);
1674 talloc_free(vnse_bind);
1675 return CMD_SUCCESS;
1676 }
1677 }
1678
1679 vty_out(vty, "Bind '%s' was not an ip-sns-default bind%s", name, VTY_NEWLINE);
1680 return CMD_WARNING;
1681}
1682
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001683DEFUN(cfg_ns_nse_ip_sns_bind, cfg_ns_nse_ip_sns_bind_cmd,
1684 "ip-sns-bind BINDID",
1685 "IP SNS binds\n"
Harald Welte2230a912021-03-04 20:09:50 +01001686 "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 +01001687{
1688 struct gprs_ns2_nse *nse = vty->index;
1689 struct gprs_ns2_vc_bind *bind;
1690 struct vty_bind *vbind;
1691 struct vty_nse *vnse;
1692 const char *name = argv[0];
1693 bool ll_modified = false;
1694 bool dialect_modified = false;
1695 int rc;
1696
1697 if (nse->ll == GPRS_NS2_LL_UNDEF) {
1698 nse->ll = GPRS_NS2_LL_UDP;
1699 ll_modified = true;
1700 }
1701
1702 if (nse->dialect == GPRS_NS2_DIALECT_UNDEF) {
Harald Welte06d9bf92021-03-05 10:20:11 +01001703 if (ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_SNS) < 0)
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001704 goto err;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001705 dialect_modified = true;
1706 }
1707
1708 if (nse->ll != GPRS_NS2_LL_UDP) {
1709 vty_out(vty, "Can not mix NS-VC with different link layer%s", VTY_NEWLINE);
1710 goto err;
1711 }
1712
1713 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1714 vty_out(vty, "Can not mix NS-VC with different dialects%s", VTY_NEWLINE);
1715 goto err;
1716 }
1717
1718 vbind = vty_bind_by_name(name);
1719 if (!vbind) {
1720 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1721 goto err;
1722 }
1723
1724 if (vbind->ll != GPRS_NS2_LL_UDP) {
1725 vty_out(vty, "ip-sns-bind can only be used with UDP bind%s",
1726 VTY_NEWLINE);
1727 goto err;
1728 }
1729
1730 /* the vnse has been created together when creating the nse node. The parent node should check this already! */
1731 vnse = vty_nse_by_nsei(nse->nsei);
1732 OSMO_ASSERT(vnse);
1733
1734 rc = vty_nse_add_vbind(vnse, vbind);
1735 switch (rc) {
1736 case 0:
1737 break;
1738 case -EALREADY:
1739 vty_out(vty, "Failed to add ip-sns-bind %s already present%s", name, VTY_NEWLINE);
1740 goto err;
1741 case -ENOMEM:
1742 vty_out(vty, "Failed to add ip-sns-bind %s out of memory%s", name, VTY_NEWLINE);
1743 goto err;
1744 default:
1745 vty_out(vty, "Failed to add ip-sns-bind %s! %d%s", name, rc, VTY_NEWLINE);
1746 goto err;
1747 }
1748
1749 /* the bind might not yet created because "listen" is missing. */
1750 bind = gprs_ns2_bind_by_name(vty_nsi, name);
1751 if (!bind)
1752 return CMD_SUCCESS;
1753
1754 rc = gprs_ns2_sns_add_bind(nse, bind);
1755 switch (rc) {
1756 case 0:
1757 break;
1758 case -EALREADY:
1759 vty_out(vty, "Failed to add ip-sns-bind %s already present%s", name, VTY_NEWLINE);
1760 goto err;
1761 case -ENOMEM:
1762 vty_out(vty, "Failed to add ip-sns-bind %s out of memory%s", name, VTY_NEWLINE);
1763 goto err;
1764 default:
1765 vty_out(vty, "Failed to add ip-sns-bind %s! %d%s", name, rc, VTY_NEWLINE);
1766 goto err;
1767 }
1768
1769 return CMD_SUCCESS;
1770err:
1771 if (ll_modified)
1772 nse->ll = GPRS_NS2_LL_UNDEF;
1773 if (dialect_modified)
Harald Welte06d9bf92021-03-05 10:20:11 +01001774 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001775
1776 return CMD_WARNING;
1777}
1778
1779DEFUN(cfg_no_ns_nse_ip_sns_bind, cfg_no_ns_nse_ip_sns_bind_cmd,
1780 "no ip-sns-bind BINDID",
1781 NO_STR
1782 "IP SNS binds\n"
Harald Welte2230a912021-03-04 20:09:50 +01001783 "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 +01001784{
1785 struct gprs_ns2_nse *nse = vty->index;
1786 struct gprs_ns2_vc_bind *bind;
1787 struct vty_bind *vbind;
1788 struct vty_nse *vnse;
1789 const char *name = argv[0];
1790 int rc;
1791
1792 if (nse->ll != GPRS_NS2_LL_UDP) {
1793 vty_out(vty, "This NSE doesn't support UDP.%s", VTY_NEWLINE);
1794 return CMD_WARNING;
1795 }
1796
1797 if (nse->dialect != GPRS_NS2_DIALECT_SNS) {
1798 vty_out(vty, "This NSE doesn't support UDP with dialect ip-sns.%s", VTY_NEWLINE);
1799 return CMD_WARNING;
1800 }
1801
1802 vbind = vty_bind_by_name(name);
1803 if (!vbind) {
1804 vty_out(vty, "Can not find the given bind '%s'%s", name, VTY_NEWLINE);
1805 return CMD_WARNING;
1806 }
1807
1808 if (vbind->ll != GPRS_NS2_LL_UDP) {
1809 vty_out(vty, "no ip-sns-bind can only be used with UDP bind%s",
1810 VTY_NEWLINE);
1811 return CMD_WARNING;
1812 }
1813
1814 /* the vnse has been created together when creating the nse node. The parent node should check this already! */
1815 vnse = vty_nse_by_nsei(nse->nsei);
1816 OSMO_ASSERT(vnse);
1817
1818 rc = vty_nse_remove_vbind(vnse, vbind);
1819 switch(rc) {
1820 case 0:
1821 break;
1822 case -ENOENT:
1823 vty_out(vty, "Bind %s is not part of this NSE%s", name, VTY_NEWLINE);
1824 return CMD_WARNING;
1825 case -EINVAL:
1826 vty_out(vty, "no ip-sns-bind can only be used with UDP bind%s",
1827 VTY_NEWLINE);
1828 return CMD_WARNING;
1829 default:
1830 return CMD_WARNING;
1831 }
1832
1833 /* the bind might not exists yet */
1834 bind = gprs_ns2_bind_by_name(vty_nsi, name);
1835 if (bind)
1836 gprs_ns2_sns_del_bind(nse, bind);
1837
1838 if (!vty_nse_check_sns(nse)) {
1839 /* clean up nse to allow other nsvc commands */
Harald Welte06d9bf92021-03-05 10:20:11 +01001840 ns2_nse_set_dialect(nse, GPRS_NS2_DIALECT_UNDEF);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001841 nse->ll = GPRS_NS2_LL_UNDEF;
Alexander Couzens6b9d2322021-02-12 03:17:59 +01001842 }
1843
1844 return CMD_SUCCESS;
1845}
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01001846
1847/* non-config commands */
Alexander Couzens75b61882021-03-21 16:18:17 +01001848void ns2_vty_dump_nsvc(struct vty *vty, struct gprs_ns2_vc *nsvc, bool stats)
Alexander Couzens6a161492020-07-12 13:45:50 +02001849{
Harald Weltedc2d0802020-12-01 18:17:28 +01001850 char nsvci_str[32];
1851
1852 if (nsvc->nsvci_is_valid)
1853 snprintf(nsvci_str, sizeof(nsvci_str), "%05u", nsvc->nsvci);
1854 else
1855 snprintf(nsvci_str, sizeof(nsvci_str), "none");
1856
Alexander Couzens1dd9cbf2021-03-21 16:22:08 +01001857 vty_out(vty, " NSVCI %s: %s %s data_weight=%u sig_weight=%u %s%s", nsvci_str,
Harald Weltedc2d0802020-12-01 18:17:28 +01001858 osmo_fsm_inst_state_name(nsvc->fi),
1859 nsvc->persistent ? "PERSIST" : "DYNAMIC",
1860 nsvc->data_weight, nsvc->sig_weight,
1861 gprs_ns2_ll_str(nsvc), VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001862
1863 if (stats) {
Alexander Couzens1dd9cbf2021-03-21 16:22:08 +01001864 vty_out_rate_ctr_group(vty, " ", nsvc->ctrg);
1865 vty_out_stat_item_group(vty, " ", nsvc->statg);
Alexander Couzens6a161492020-07-12 13:45:50 +02001866 }
1867}
1868
1869static void dump_nse(struct vty *vty, const struct gprs_ns2_nse *nse, bool stats, bool persistent_only)
1870{
1871 struct gprs_ns2_vc *nsvc;
Alexander Couzens0ea4a4e2021-03-21 16:37:23 +01001872 unsigned int nsvcs = 0;
Alexander Couzens6a161492020-07-12 13:45:50 +02001873
Alexander Couzens3e539ed2021-03-21 16:25:18 +01001874 if (persistent_only && !nse->persistent)
1875 return;
1876
Harald Welte0ff12ad2020-12-01 17:51:07 +01001877 vty_out(vty, "NSEI %05u: %s, %s%s", nse->nsei, gprs_ns2_lltype_str(nse->ll),
1878 nse->alive ? "ALIVE" : "DEAD", VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001879
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001880 ns2_sns_dump_vty(vty, " ", nse, stats);
Alexander Couzens0ea4a4e2021-03-21 16:37:23 +01001881 llist_for_each_entry(nsvc, &nse->nsvc, list) {
1882 nsvcs++;
1883 }
1884 vty_out(vty, " %u NS-VC:%s", nsvcs, VTY_NEWLINE);
Alexander Couzens3e539ed2021-03-21 16:25:18 +01001885 llist_for_each_entry(nsvc, &nse->nsvc, list)
1886 ns2_vty_dump_nsvc(vty, nsvc, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001887}
1888
Alexander Couzens22f34712020-10-02 02:34:39 +02001889static void dump_bind(struct vty *vty, const struct gprs_ns2_vc_bind *bind, bool stats)
1890{
1891 if (bind->dump_vty)
1892 bind->dump_vty(bind, vty, stats);
Harald Welte76346072021-01-31 11:54:02 +01001893
1894 if (stats) {
1895 vty_out_stat_item_group(vty, " ", bind->statg);
1896 }
Alexander Couzens22f34712020-10-02 02:34:39 +02001897}
1898
Harald Welte2fce19a2020-12-01 17:52:55 +01001899static void dump_ns_bind(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats)
Alexander Couzens6a161492020-07-12 13:45:50 +02001900{
Alexander Couzens22f34712020-10-02 02:34:39 +02001901 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6a161492020-07-12 13:45:50 +02001902
Alexander Couzens22f34712020-10-02 02:34:39 +02001903 llist_for_each_entry(bind, &nsi->binding, list) {
1904 dump_bind(vty, bind, stats);
1905 }
Harald Welte2fce19a2020-12-01 17:52:55 +01001906}
1907
1908
1909static void dump_ns_entities(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats, bool persistent_only)
1910{
1911 struct gprs_ns2_nse *nse;
Alexander Couzens22f34712020-10-02 02:34:39 +02001912
Alexander Couzens6a161492020-07-12 13:45:50 +02001913 llist_for_each_entry(nse, &nsi->nse, list) {
1914 dump_nse(vty, nse, stats, persistent_only);
Alexander Couzens6a161492020-07-12 13:45:50 +02001915 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001916}
1917
Harald Welte25ee7552020-12-02 22:14:00 +01001918/* Backwards compatibility, among other things for the TestVTYGbproxy which expects
1919 * 'show ns' to output something about binds */
1920DEFUN_HIDDEN(show_ns, show_ns_cmd, "show ns",
1921 SHOW_STR SHOW_NS_STR)
1922{
1923 dump_ns_entities(vty, vty_nsi, false, false);
1924 dump_ns_bind(vty, vty_nsi, false);
1925 return CMD_SUCCESS;
1926}
1927
1928
Harald Welte2fce19a2020-12-01 17:52:55 +01001929DEFUN(show_ns_binds, show_ns_binds_cmd, "show ns binds [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001930 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01001931 "Display information about the NS protocol binds\n"
1932 "Include statistic\n")
Alexander Couzens6a161492020-07-12 13:45:50 +02001933{
Harald Welte2fce19a2020-12-01 17:52:55 +01001934 bool stats = false;
1935 if (argc > 0)
1936 stats = true;
1937
1938 dump_ns_bind(vty, vty_nsi, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001939 return CMD_SUCCESS;
1940}
1941
Harald Welte2fce19a2020-12-01 17:52:55 +01001942DEFUN(show_ns_entities, show_ns_entities_cmd, "show ns entities [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001943 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01001944 "Display information about the NS protocol entities (NSEs)\n"
Alexander Couzens6a161492020-07-12 13:45:50 +02001945 "Include statistics\n")
1946{
Harald Welte2fce19a2020-12-01 17:52:55 +01001947 bool stats = false;
1948 if (argc > 0)
1949 stats = true;
1950
1951 dump_ns_entities(vty, vty_nsi, stats, false);
Alexander Couzens6a161492020-07-12 13:45:50 +02001952 return CMD_SUCCESS;
1953}
1954
1955DEFUN(show_ns_pers, show_ns_pers_cmd, "show ns persistent",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001956 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02001957 "Show only persistent NS\n")
1958{
Harald Welte2fce19a2020-12-01 17:52:55 +01001959 dump_ns_entities(vty, vty_nsi, true, true);
Alexander Couzens6a161492020-07-12 13:45:50 +02001960 return CMD_SUCCESS;
1961}
1962
1963DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001964 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02001965 "Select one NSE by its NSE Identifier\n"
1966 "Select one NSE by its NS-VC Identifier\n"
1967 "The Identifier of selected type\n"
1968 "Include Statistics\n")
1969{
1970 struct gprs_ns2_inst *nsi = vty_nsi;
1971 struct gprs_ns2_nse *nse;
1972 struct gprs_ns2_vc *nsvc;
1973 uint16_t id = atoi(argv[1]);
1974 bool show_stats = false;
1975
1976 if (argc >= 3)
1977 show_stats = true;
1978
1979 if (!strcmp(argv[0], "nsei")) {
1980 nse = gprs_ns2_nse_by_nsei(nsi, id);
1981 if (!nse) {
1982 return CMD_WARNING;
1983 }
1984
1985 dump_nse(vty, nse, show_stats, false);
1986 } else {
1987 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
1988
1989 if (!nsvc) {
1990 vty_out(vty, "No such NS Entity%s", VTY_NEWLINE);
1991 return CMD_WARNING;
1992 }
1993
Alexander Couzens75b61882021-03-21 16:18:17 +01001994 ns2_vty_dump_nsvc(vty, nsvc, show_stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001995 }
1996
1997 return CMD_SUCCESS;
1998}
1999
Daniel Willmanndbab7142020-11-18 14:19:56 +01002000static int nsvc_force_unconf_cb(struct gprs_ns2_vc *nsvc, void *ctx)
2001{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01002002 ns2_vc_force_unconfigured(nsvc);
Harald Welte7fe8d712021-01-31 18:40:54 +01002003 ns2_vc_fsm_start(nsvc);
Daniel Willmanndbab7142020-11-18 14:19:56 +01002004 return 0;
2005}
2006
2007DEFUN_HIDDEN(nsvc_force_unconf, nsvc_force_unconf_cmd,
2008 "nsvc nsei <0-65535> force-unconfigured",
2009 "NS Virtual Connection\n"
2010 "The NSEI\n"
2011 "Reset the NSVCs back to initial state\n"
2012 )
2013{
2014 struct gprs_ns2_inst *nsi = vty_nsi;
2015 struct gprs_ns2_nse *nse;
2016
2017 uint16_t id = atoi(argv[0]);
2018
2019 nse = gprs_ns2_nse_by_nsei(nsi, id);
2020 if (!nse) {
2021 vty_out(vty, "Could not find NSE for NSEI %u%s", id, VTY_NEWLINE);
2022 return CMD_WARNING;
2023 }
2024
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002025 if (!nse->persistent) {
2026 gprs_ns2_free_nse(nse);
2027 } else if (nse->dialect == GPRS_NS2_DIALECT_SNS) {
Alexander Couzens280ed782020-12-21 18:25:41 +01002028 gprs_ns2_free_nsvcs(nse);
2029 } else {
2030 /* Perform the operation for all nsvc */
2031 gprs_ns2_nse_foreach_nsvc(nse, nsvc_force_unconf_cb, NULL);
2032 }
Daniel Willmanndbab7142020-11-18 14:19:56 +01002033
2034 return CMD_SUCCESS;
2035}
2036
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002037DEFUN(nsvc_block, nsvc_block_cmd,
2038 "nsvc <0-65535> (block|unblock)",
2039 "NS Virtual Connection\n"
2040 NSVCI_STR
2041 "Block a NSVC. As cause code O&M intervention will be used.\n"
2042 "Unblock a NSVC. As cause code O&M intervention will be used.\n")
Alexander Couzens841817e2020-11-19 00:41:29 +01002043{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002044 struct gprs_ns2_inst *nsi = vty_nsi;
2045 struct gprs_ns2_vc *nsvc;
Alexander Couzens841817e2020-11-19 00:41:29 +01002046
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002047 uint16_t id = atoi(argv[0]);
Alexander Couzens841817e2020-11-19 00:41:29 +01002048
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002049 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
2050 if (!nsvc) {
2051 vty_out(vty, "Could not find NSVCI %05u%s", id, VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +01002052 return CMD_WARNING;
2053 }
2054
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002055 if (!strcmp(argv[1], "block")) {
2056 ns2_vc_block(nsvc);
2057 } else {
2058 ns2_vc_unblock(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +02002059 }
2060
2061 return CMD_SUCCESS;
2062}
2063
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002064static void log_set_nse_filter(struct log_target *target,
2065 struct gprs_ns2_nse *nse)
Alexander Couzens6a161492020-07-12 13:45:50 +02002066{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002067 if (nse) {
2068 target->filter_map |= (1 << LOG_FLT_GB_NSE);
2069 target->filter_data[LOG_FLT_GB_NSE] = nse;
2070 } else if (target->filter_data[LOG_FLT_GB_NSE]) {
2071 target->filter_map = ~(1 << LOG_FLT_GB_NSE);
2072 target->filter_data[LOG_FLT_GB_NSE] = NULL;
2073 }
Alexander Couzens6a161492020-07-12 13:45:50 +02002074}
2075
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002076static void log_set_nsvc_filter(struct log_target *target,
2077 struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +02002078{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002079 if (nsvc) {
2080 target->filter_map |= (1 << LOG_FLT_GB_NSVC);
2081 target->filter_data[LOG_FLT_GB_NSVC] = nsvc;
2082 } else if (target->filter_data[LOG_FLT_GB_NSVC]) {
2083 target->filter_map = ~(1 << LOG_FLT_GB_NSVC);
2084 target->filter_data[LOG_FLT_GB_NSVC] = NULL;
2085 }
Alexander Couzens6a161492020-07-12 13:45:50 +02002086}
2087
Daniel Willmann751977b2020-12-02 18:59:44 +01002088DEFUN(logging_fltr_nse,
2089 logging_fltr_nse_cmd,
2090 "logging filter nse nsei <0-65535>",
2091 LOGGING_STR FILTER_STR
2092 "Filter based on NS Entity\n"
2093 "Identify NSE by NSEI\n"
2094 "Numeric identifier\n")
2095{
2096 struct log_target *tgt;
2097 struct gprs_ns2_nse *nse;
Daniel Willmann89106522020-12-04 01:36:59 +01002098 uint16_t id = atoi(argv[0]);
Daniel Willmann751977b2020-12-02 18:59:44 +01002099
2100 log_tgt_mutex_lock();
2101 tgt = osmo_log_vty2tgt(vty);
2102 if (!tgt) {
2103 log_tgt_mutex_unlock();
2104 return CMD_WARNING;
2105 }
2106
2107 nse = gprs_ns2_nse_by_nsei(vty_nsi, id);
2108 if (!nse) {
2109 vty_out(vty, "No NSE by that identifier%s", VTY_NEWLINE);
2110 log_tgt_mutex_unlock();
2111 return CMD_WARNING;
2112 }
2113
2114 log_set_nse_filter(tgt, nse);
2115 log_tgt_mutex_unlock();
2116 return CMD_SUCCESS;
2117}
2118
Alexander Couzens6a161492020-07-12 13:45:50 +02002119/* TODO: add filter for single connection by description */
2120DEFUN(logging_fltr_nsvc,
2121 logging_fltr_nsvc_cmd,
2122 "logging filter nsvc nsvci <0-65535>",
2123 LOGGING_STR FILTER_STR
2124 "Filter based on NS Virtual Connection\n"
2125 "Identify NS-VC by NSVCI\n"
2126 "Numeric identifier\n")
2127{
2128 struct log_target *tgt;
2129 struct gprs_ns2_vc *nsvc;
Daniel Willmann89106522020-12-04 01:36:59 +01002130 uint16_t id = atoi(argv[0]);
Alexander Couzens6a161492020-07-12 13:45:50 +02002131
2132 log_tgt_mutex_lock();
2133 tgt = osmo_log_vty2tgt(vty);
2134 if (!tgt) {
2135 log_tgt_mutex_unlock();
2136 return CMD_WARNING;
2137 }
2138
2139 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, id);
2140 if (!nsvc) {
2141 vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE);
2142 log_tgt_mutex_unlock();
2143 return CMD_WARNING;
2144 }
2145
2146 log_set_nsvc_filter(tgt, nsvc);
2147 log_tgt_mutex_unlock();
2148 return CMD_SUCCESS;
2149}
2150
Alexander Couzense43b46e2021-01-27 21:52:08 +01002151/*! initialized a reduced vty interface which excludes the configuration nodes besides timeouts.
2152 * This can be used by the PCU which can be only configured by the BTS/BSC and not by the vty.
2153 * \param[in] nsi NS instance on which we operate
2154 * \return 0 on success.
2155 */
2156int gprs_ns2_vty_init_reduced(struct gprs_ns2_inst *nsi)
Alexander Couzens6a161492020-07-12 13:45:50 +02002157{
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01002158 vty_nsi = nsi;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002159 INIT_LLIST_HEAD(&binds);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002160 INIT_LLIST_HEAD(&nses);
Harald Welted164ef82021-03-04 22:29:17 +01002161 INIT_LLIST_HEAD(&ip_sns_default_binds);
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01002162
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002163 vty_fr_network = osmo_fr_network_alloc(nsi);
2164 if (!vty_fr_network)
2165 return -ENOMEM;
Alexander Couzens6a161492020-07-12 13:45:50 +02002166
Harald Welte25ee7552020-12-02 22:14:00 +01002167 install_lib_element_ve(&show_ns_cmd);
Harald Welte2fce19a2020-12-01 17:52:55 +01002168 install_lib_element_ve(&show_ns_binds_cmd);
2169 install_lib_element_ve(&show_ns_entities_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002170 install_lib_element_ve(&show_ns_pers_cmd);
2171 install_lib_element_ve(&show_nse_cmd);
Daniel Willmann751977b2020-12-02 18:59:44 +01002172 install_lib_element_ve(&logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002173 install_lib_element_ve(&logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002174
Daniel Willmanndbab7142020-11-18 14:19:56 +01002175 install_lib_element(ENABLE_NODE, &nsvc_force_unconf_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002176 install_lib_element(ENABLE_NODE, &nsvc_block_cmd);
Daniel Willmanndbab7142020-11-18 14:19:56 +01002177
Daniel Willmann751977b2020-12-02 18:59:44 +01002178 install_lib_element(CFG_LOG_NODE, &logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002179 install_lib_element(CFG_LOG_NODE, &logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002180
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002181 install_lib_element(CONFIG_NODE, &cfg_ns_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002182
Alexander Couzens6a161492020-07-12 13:45:50 +02002183 install_node(&ns_node, config_write_ns);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002184 /* TODO: convert into osmo timer */
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002185 install_lib_element(L_NS_NODE, &cfg_ns_timer_cmd);
Alexander Couzense43b46e2021-01-27 21:52:08 +01002186
2187 return 0;
2188}
2189
2190int gprs_ns2_vty_init(struct gprs_ns2_inst *nsi)
2191{
2192 int rc = gprs_ns2_vty_init_reduced(nsi);
2193 if (rc)
2194 return rc;
2195
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002196 install_lib_element(L_NS_NODE, &cfg_ns_nsei_cmd);
2197 install_lib_element(L_NS_NODE, &cfg_no_ns_nsei_cmd);
2198 install_lib_element(L_NS_NODE, &cfg_ns_bind_cmd);
2199 install_lib_element(L_NS_NODE, &cfg_no_ns_bind_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002200
Harald Welted164ef82021-03-04 22:29:17 +01002201 install_lib_element(L_NS_NODE, &cfg_ns_ip_sns_default_bind_cmd);
2202 install_lib_element(L_NS_NODE, &cfg_no_ns_ip_sns_default_bind_cmd);
2203
Alexander Couzens260cd522021-01-28 20:31:31 +01002204 install_node(&ns_bind_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002205 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_listen_cmd);
2206 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_listen_cmd);
2207 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_dscp_cmd);
2208 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_dscp_cmd);
Alexander Couzensc4704762021-02-08 23:13:12 +01002209 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_ip_sns_weight_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002210 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_ipaccess_cmd);
2211 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_ipaccess_cmd);
2212 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_fr_cmd);
2213 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_fr_cmd);
Harald Welte42e36462021-03-03 18:12:09 +01002214 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_accept_sns_cmd);
2215 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_accept_sns_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002216
Alexander Couzens260cd522021-01-28 20:31:31 +01002217 install_node(&ns_nse_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002218 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_fr_cmd);
2219 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvci_cmd);
2220 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_fr_dlci_cmd);
2221 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_udp_cmd);
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01002222 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_udp_weights_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002223 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_udp_cmd);
2224 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_ipa_cmd);
2225 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_ipa_cmd);
Alexander Couzens5fa431c2021-02-08 23:21:54 +01002226 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_remote_cmd);
2227 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_remote_cmd);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002228 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_bind_cmd);
2229 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_bind_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002230
2231 return 0;
2232}