blob: 7cb9ed948f38c6a4e94c90710034160c4a715412 [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
1857 vty_out(vty, " NSVCI %s: %s %s data_weight=%u sig_weight=%u %s%s", nsvci_str,
1858 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) {
Harald Welte7aa60992020-12-01 17:53:17 +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;
1872
Harald Welte0ff12ad2020-12-01 17:51:07 +01001873 vty_out(vty, "NSEI %05u: %s, %s%s", nse->nsei, gprs_ns2_lltype_str(nse->ll),
1874 nse->alive ? "ALIVE" : "DEAD", VTY_NEWLINE);
Alexander Couzens6a161492020-07-12 13:45:50 +02001875
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01001876 ns2_sns_dump_vty(vty, " ", nse, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001877 llist_for_each_entry(nsvc, &nse->nsvc, list) {
1878 if (persistent_only) {
1879 if (nsvc->persistent)
Alexander Couzens75b61882021-03-21 16:18:17 +01001880 ns2_vty_dump_nsvc(vty, nsvc, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001881 } else {
Alexander Couzens75b61882021-03-21 16:18:17 +01001882 ns2_vty_dump_nsvc(vty, nsvc, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001883 }
1884 }
1885}
1886
Alexander Couzens22f34712020-10-02 02:34:39 +02001887static void dump_bind(struct vty *vty, const struct gprs_ns2_vc_bind *bind, bool stats)
1888{
1889 if (bind->dump_vty)
1890 bind->dump_vty(bind, vty, stats);
Harald Welte76346072021-01-31 11:54:02 +01001891
1892 if (stats) {
1893 vty_out_stat_item_group(vty, " ", bind->statg);
1894 }
Alexander Couzens22f34712020-10-02 02:34:39 +02001895}
1896
Harald Welte2fce19a2020-12-01 17:52:55 +01001897static void dump_ns_bind(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats)
Alexander Couzens6a161492020-07-12 13:45:50 +02001898{
Alexander Couzens22f34712020-10-02 02:34:39 +02001899 struct gprs_ns2_vc_bind *bind;
Alexander Couzens6a161492020-07-12 13:45:50 +02001900
Alexander Couzens22f34712020-10-02 02:34:39 +02001901 llist_for_each_entry(bind, &nsi->binding, list) {
1902 dump_bind(vty, bind, stats);
1903 }
Harald Welte2fce19a2020-12-01 17:52:55 +01001904}
1905
1906
1907static void dump_ns_entities(struct vty *vty, const struct gprs_ns2_inst *nsi, bool stats, bool persistent_only)
1908{
1909 struct gprs_ns2_nse *nse;
Alexander Couzens22f34712020-10-02 02:34:39 +02001910
Alexander Couzens6a161492020-07-12 13:45:50 +02001911 llist_for_each_entry(nse, &nsi->nse, list) {
1912 dump_nse(vty, nse, stats, persistent_only);
Alexander Couzens6a161492020-07-12 13:45:50 +02001913 }
Alexander Couzens6a161492020-07-12 13:45:50 +02001914}
1915
Harald Welte25ee7552020-12-02 22:14:00 +01001916/* Backwards compatibility, among other things for the TestVTYGbproxy which expects
1917 * 'show ns' to output something about binds */
1918DEFUN_HIDDEN(show_ns, show_ns_cmd, "show ns",
1919 SHOW_STR SHOW_NS_STR)
1920{
1921 dump_ns_entities(vty, vty_nsi, false, false);
1922 dump_ns_bind(vty, vty_nsi, false);
1923 return CMD_SUCCESS;
1924}
1925
1926
Harald Welte2fce19a2020-12-01 17:52:55 +01001927DEFUN(show_ns_binds, show_ns_binds_cmd, "show ns binds [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001928 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01001929 "Display information about the NS protocol binds\n"
1930 "Include statistic\n")
Alexander Couzens6a161492020-07-12 13:45:50 +02001931{
Harald Welte2fce19a2020-12-01 17:52:55 +01001932 bool stats = false;
1933 if (argc > 0)
1934 stats = true;
1935
1936 dump_ns_bind(vty, vty_nsi, stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001937 return CMD_SUCCESS;
1938}
1939
Harald Welte2fce19a2020-12-01 17:52:55 +01001940DEFUN(show_ns_entities, show_ns_entities_cmd, "show ns entities [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001941 SHOW_STR SHOW_NS_STR
Harald Welte2fce19a2020-12-01 17:52:55 +01001942 "Display information about the NS protocol entities (NSEs)\n"
Alexander Couzens6a161492020-07-12 13:45:50 +02001943 "Include statistics\n")
1944{
Harald Welte2fce19a2020-12-01 17:52:55 +01001945 bool stats = false;
1946 if (argc > 0)
1947 stats = true;
1948
1949 dump_ns_entities(vty, vty_nsi, stats, false);
Alexander Couzens6a161492020-07-12 13:45:50 +02001950 return CMD_SUCCESS;
1951}
1952
1953DEFUN(show_ns_pers, show_ns_pers_cmd, "show ns persistent",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001954 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02001955 "Show only persistent NS\n")
1956{
Harald Welte2fce19a2020-12-01 17:52:55 +01001957 dump_ns_entities(vty, vty_nsi, true, true);
Alexander Couzens6a161492020-07-12 13:45:50 +02001958 return CMD_SUCCESS;
1959}
1960
1961DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]",
Daniel Willmanncb3e9b52020-12-02 15:50:22 +01001962 SHOW_STR SHOW_NS_STR
Alexander Couzens6a161492020-07-12 13:45:50 +02001963 "Select one NSE by its NSE Identifier\n"
1964 "Select one NSE by its NS-VC Identifier\n"
1965 "The Identifier of selected type\n"
1966 "Include Statistics\n")
1967{
1968 struct gprs_ns2_inst *nsi = vty_nsi;
1969 struct gprs_ns2_nse *nse;
1970 struct gprs_ns2_vc *nsvc;
1971 uint16_t id = atoi(argv[1]);
1972 bool show_stats = false;
1973
1974 if (argc >= 3)
1975 show_stats = true;
1976
1977 if (!strcmp(argv[0], "nsei")) {
1978 nse = gprs_ns2_nse_by_nsei(nsi, id);
1979 if (!nse) {
1980 return CMD_WARNING;
1981 }
1982
1983 dump_nse(vty, nse, show_stats, false);
1984 } else {
1985 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
1986
1987 if (!nsvc) {
1988 vty_out(vty, "No such NS Entity%s", VTY_NEWLINE);
1989 return CMD_WARNING;
1990 }
1991
Alexander Couzens75b61882021-03-21 16:18:17 +01001992 ns2_vty_dump_nsvc(vty, nsvc, show_stats);
Alexander Couzens6a161492020-07-12 13:45:50 +02001993 }
1994
1995 return CMD_SUCCESS;
1996}
1997
Daniel Willmanndbab7142020-11-18 14:19:56 +01001998static int nsvc_force_unconf_cb(struct gprs_ns2_vc *nsvc, void *ctx)
1999{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +01002000 ns2_vc_force_unconfigured(nsvc);
Harald Welte7fe8d712021-01-31 18:40:54 +01002001 ns2_vc_fsm_start(nsvc);
Daniel Willmanndbab7142020-11-18 14:19:56 +01002002 return 0;
2003}
2004
2005DEFUN_HIDDEN(nsvc_force_unconf, nsvc_force_unconf_cmd,
2006 "nsvc nsei <0-65535> force-unconfigured",
2007 "NS Virtual Connection\n"
2008 "The NSEI\n"
2009 "Reset the NSVCs back to initial state\n"
2010 )
2011{
2012 struct gprs_ns2_inst *nsi = vty_nsi;
2013 struct gprs_ns2_nse *nse;
2014
2015 uint16_t id = atoi(argv[0]);
2016
2017 nse = gprs_ns2_nse_by_nsei(nsi, id);
2018 if (!nse) {
2019 vty_out(vty, "Could not find NSE for NSEI %u%s", id, VTY_NEWLINE);
2020 return CMD_WARNING;
2021 }
2022
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002023 if (!nse->persistent) {
2024 gprs_ns2_free_nse(nse);
2025 } else if (nse->dialect == GPRS_NS2_DIALECT_SNS) {
Alexander Couzens280ed782020-12-21 18:25:41 +01002026 gprs_ns2_free_nsvcs(nse);
2027 } else {
2028 /* Perform the operation for all nsvc */
2029 gprs_ns2_nse_foreach_nsvc(nse, nsvc_force_unconf_cb, NULL);
2030 }
Daniel Willmanndbab7142020-11-18 14:19:56 +01002031
2032 return CMD_SUCCESS;
2033}
2034
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002035DEFUN(nsvc_block, nsvc_block_cmd,
2036 "nsvc <0-65535> (block|unblock)",
2037 "NS Virtual Connection\n"
2038 NSVCI_STR
2039 "Block a NSVC. As cause code O&M intervention will be used.\n"
2040 "Unblock a NSVC. As cause code O&M intervention will be used.\n")
Alexander Couzens841817e2020-11-19 00:41:29 +01002041{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002042 struct gprs_ns2_inst *nsi = vty_nsi;
2043 struct gprs_ns2_vc *nsvc;
Alexander Couzens841817e2020-11-19 00:41:29 +01002044
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002045 uint16_t id = atoi(argv[0]);
Alexander Couzens841817e2020-11-19 00:41:29 +01002046
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002047 nsvc = gprs_ns2_nsvc_by_nsvci(nsi, id);
2048 if (!nsvc) {
2049 vty_out(vty, "Could not find NSVCI %05u%s", id, VTY_NEWLINE);
Alexander Couzens841817e2020-11-19 00:41:29 +01002050 return CMD_WARNING;
2051 }
2052
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002053 if (!strcmp(argv[1], "block")) {
2054 ns2_vc_block(nsvc);
2055 } else {
2056 ns2_vc_unblock(nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +02002057 }
2058
2059 return CMD_SUCCESS;
2060}
2061
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002062static void log_set_nse_filter(struct log_target *target,
2063 struct gprs_ns2_nse *nse)
Alexander Couzens6a161492020-07-12 13:45:50 +02002064{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002065 if (nse) {
2066 target->filter_map |= (1 << LOG_FLT_GB_NSE);
2067 target->filter_data[LOG_FLT_GB_NSE] = nse;
2068 } else if (target->filter_data[LOG_FLT_GB_NSE]) {
2069 target->filter_map = ~(1 << LOG_FLT_GB_NSE);
2070 target->filter_data[LOG_FLT_GB_NSE] = NULL;
2071 }
Alexander Couzens6a161492020-07-12 13:45:50 +02002072}
2073
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002074static void log_set_nsvc_filter(struct log_target *target,
2075 struct gprs_ns2_vc *nsvc)
Alexander Couzens6a161492020-07-12 13:45:50 +02002076{
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002077 if (nsvc) {
2078 target->filter_map |= (1 << LOG_FLT_GB_NSVC);
2079 target->filter_data[LOG_FLT_GB_NSVC] = nsvc;
2080 } else if (target->filter_data[LOG_FLT_GB_NSVC]) {
2081 target->filter_map = ~(1 << LOG_FLT_GB_NSVC);
2082 target->filter_data[LOG_FLT_GB_NSVC] = NULL;
2083 }
Alexander Couzens6a161492020-07-12 13:45:50 +02002084}
2085
Daniel Willmann751977b2020-12-02 18:59:44 +01002086DEFUN(logging_fltr_nse,
2087 logging_fltr_nse_cmd,
2088 "logging filter nse nsei <0-65535>",
2089 LOGGING_STR FILTER_STR
2090 "Filter based on NS Entity\n"
2091 "Identify NSE by NSEI\n"
2092 "Numeric identifier\n")
2093{
2094 struct log_target *tgt;
2095 struct gprs_ns2_nse *nse;
Daniel Willmann89106522020-12-04 01:36:59 +01002096 uint16_t id = atoi(argv[0]);
Daniel Willmann751977b2020-12-02 18:59:44 +01002097
2098 log_tgt_mutex_lock();
2099 tgt = osmo_log_vty2tgt(vty);
2100 if (!tgt) {
2101 log_tgt_mutex_unlock();
2102 return CMD_WARNING;
2103 }
2104
2105 nse = gprs_ns2_nse_by_nsei(vty_nsi, id);
2106 if (!nse) {
2107 vty_out(vty, "No NSE by that identifier%s", VTY_NEWLINE);
2108 log_tgt_mutex_unlock();
2109 return CMD_WARNING;
2110 }
2111
2112 log_set_nse_filter(tgt, nse);
2113 log_tgt_mutex_unlock();
2114 return CMD_SUCCESS;
2115}
2116
Alexander Couzens6a161492020-07-12 13:45:50 +02002117/* TODO: add filter for single connection by description */
2118DEFUN(logging_fltr_nsvc,
2119 logging_fltr_nsvc_cmd,
2120 "logging filter nsvc nsvci <0-65535>",
2121 LOGGING_STR FILTER_STR
2122 "Filter based on NS Virtual Connection\n"
2123 "Identify NS-VC by NSVCI\n"
2124 "Numeric identifier\n")
2125{
2126 struct log_target *tgt;
2127 struct gprs_ns2_vc *nsvc;
Daniel Willmann89106522020-12-04 01:36:59 +01002128 uint16_t id = atoi(argv[0]);
Alexander Couzens6a161492020-07-12 13:45:50 +02002129
2130 log_tgt_mutex_lock();
2131 tgt = osmo_log_vty2tgt(vty);
2132 if (!tgt) {
2133 log_tgt_mutex_unlock();
2134 return CMD_WARNING;
2135 }
2136
2137 nsvc = gprs_ns2_nsvc_by_nsvci(vty_nsi, id);
2138 if (!nsvc) {
2139 vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE);
2140 log_tgt_mutex_unlock();
2141 return CMD_WARNING;
2142 }
2143
2144 log_set_nsvc_filter(tgt, nsvc);
2145 log_tgt_mutex_unlock();
2146 return CMD_SUCCESS;
2147}
2148
Alexander Couzense43b46e2021-01-27 21:52:08 +01002149/*! initialized a reduced vty interface which excludes the configuration nodes besides timeouts.
2150 * This can be used by the PCU which can be only configured by the BTS/BSC and not by the vty.
2151 * \param[in] nsi NS instance on which we operate
2152 * \return 0 on success.
2153 */
2154int gprs_ns2_vty_init_reduced(struct gprs_ns2_inst *nsi)
Alexander Couzens6a161492020-07-12 13:45:50 +02002155{
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01002156 vty_nsi = nsi;
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002157 INIT_LLIST_HEAD(&binds);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002158 INIT_LLIST_HEAD(&nses);
Harald Welted164ef82021-03-04 22:29:17 +01002159 INIT_LLIST_HEAD(&ip_sns_default_binds);
Pau Espin Pedrolcaf53172021-01-28 13:37:50 +01002160
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002161 vty_fr_network = osmo_fr_network_alloc(nsi);
2162 if (!vty_fr_network)
2163 return -ENOMEM;
Alexander Couzens6a161492020-07-12 13:45:50 +02002164
Harald Welte25ee7552020-12-02 22:14:00 +01002165 install_lib_element_ve(&show_ns_cmd);
Harald Welte2fce19a2020-12-01 17:52:55 +01002166 install_lib_element_ve(&show_ns_binds_cmd);
2167 install_lib_element_ve(&show_ns_entities_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002168 install_lib_element_ve(&show_ns_pers_cmd);
2169 install_lib_element_ve(&show_nse_cmd);
Daniel Willmann751977b2020-12-02 18:59:44 +01002170 install_lib_element_ve(&logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002171 install_lib_element_ve(&logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002172
Daniel Willmanndbab7142020-11-18 14:19:56 +01002173 install_lib_element(ENABLE_NODE, &nsvc_force_unconf_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002174 install_lib_element(ENABLE_NODE, &nsvc_block_cmd);
Daniel Willmanndbab7142020-11-18 14:19:56 +01002175
Daniel Willmann751977b2020-12-02 18:59:44 +01002176 install_lib_element(CFG_LOG_NODE, &logging_fltr_nse_cmd);
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002177 install_lib_element(CFG_LOG_NODE, &logging_fltr_nsvc_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002178
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002179 install_lib_element(CONFIG_NODE, &cfg_ns_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002180
Alexander Couzens6a161492020-07-12 13:45:50 +02002181 install_node(&ns_node, config_write_ns);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002182 /* TODO: convert into osmo timer */
Vadim Yanitskiy8e7c4962020-10-04 15:37:31 +07002183 install_lib_element(L_NS_NODE, &cfg_ns_timer_cmd);
Alexander Couzense43b46e2021-01-27 21:52:08 +01002184
2185 return 0;
2186}
2187
2188int gprs_ns2_vty_init(struct gprs_ns2_inst *nsi)
2189{
2190 int rc = gprs_ns2_vty_init_reduced(nsi);
2191 if (rc)
2192 return rc;
2193
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002194 install_lib_element(L_NS_NODE, &cfg_ns_nsei_cmd);
2195 install_lib_element(L_NS_NODE, &cfg_no_ns_nsei_cmd);
2196 install_lib_element(L_NS_NODE, &cfg_ns_bind_cmd);
2197 install_lib_element(L_NS_NODE, &cfg_no_ns_bind_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002198
Harald Welted164ef82021-03-04 22:29:17 +01002199 install_lib_element(L_NS_NODE, &cfg_ns_ip_sns_default_bind_cmd);
2200 install_lib_element(L_NS_NODE, &cfg_no_ns_ip_sns_default_bind_cmd);
2201
Alexander Couzens260cd522021-01-28 20:31:31 +01002202 install_node(&ns_bind_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002203 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_listen_cmd);
2204 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_listen_cmd);
2205 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_dscp_cmd);
2206 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_dscp_cmd);
Alexander Couzensc4704762021-02-08 23:13:12 +01002207 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_ip_sns_weight_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002208 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_ipaccess_cmd);
2209 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_ipaccess_cmd);
2210 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_fr_cmd);
2211 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_fr_cmd);
Harald Welte42e36462021-03-03 18:12:09 +01002212 install_lib_element(L_NS_BIND_NODE, &cfg_ns_bind_accept_sns_cmd);
2213 install_lib_element(L_NS_BIND_NODE, &cfg_no_ns_bind_accept_sns_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002214
Alexander Couzens260cd522021-01-28 20:31:31 +01002215 install_node(&ns_nse_node, NULL);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002216 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_fr_cmd);
2217 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvci_cmd);
2218 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_fr_dlci_cmd);
2219 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_udp_cmd);
Alexander Couzensbf5d0db2021-02-12 04:04:13 +01002220 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_udp_weights_cmd);
Alexander Couzensda1bf8e2021-01-25 16:27:33 +01002221 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_udp_cmd);
2222 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_nsvc_ipa_cmd);
2223 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_nsvc_ipa_cmd);
Alexander Couzens5fa431c2021-02-08 23:21:54 +01002224 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_remote_cmd);
2225 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_remote_cmd);
Alexander Couzens6b9d2322021-02-12 03:17:59 +01002226 install_lib_element(L_NS_NSE_NODE, &cfg_ns_nse_ip_sns_bind_cmd);
2227 install_lib_element(L_NS_NSE_NODE, &cfg_no_ns_nse_ip_sns_bind_cmd);
Alexander Couzens6a161492020-07-12 13:45:50 +02002228
2229 return 0;
2230}