pespin has uploaded this change for review. (
https://gerrit.osmocom.org/c/libosmo-sigtran/+/40456?usp=email )
Change subject: Split AS/ASP/XUA_SRV VTY code to its own files
......................................................................
Split AS/ASP/XUA_SRV VTY code to its own files
This allows readers finding more easily and focusing on the relevant
subset of VTY code for each node/object.
Change-Id: I90643bea41098cd6b711e493d4dc9852e88504b1
---
M src/Makefile.am
A src/ss7_as_vty.c
A src/ss7_asp_vty.c
M src/ss7_internal.h
M src/ss7_vty.c
A src/ss7_vty.h
A src/ss7_xua_srv_vty.c
7 files changed, 2,234 insertions(+), 2,015 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmo-sigtran refs/changes/56/40456/1
diff --git a/src/Makefile.am b/src/Makefile.am
index bba3d22..53b80c0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -15,6 +15,7 @@
ss7_route.h \
ss7_route_table.h \
ss7_user.h \
+ ss7_vty.h \
ss7_xua_srv.h \
xua_asp_fsm.h \
xua_as_fsm.h \
@@ -54,7 +55,9 @@
sccp_vty.c \
ss7.c \
ss7_as.c \
+ ss7_as_vty.c \
ss7_asp.c \
+ ss7_asp_vty.c \
ss7_asp_peer.c \
ss7_combined_linkset.c \
ss7_hmrt.c \
@@ -63,6 +66,7 @@
ss7_linkset.c \
ss7_vty.c \
ss7_xua_srv.c \
+ ss7_xua_srv_vty.c \
ss7_route.c \
ss7_route_table.c \
ss7_user.c \
diff --git a/src/ss7_as_vty.c b/src/ss7_as_vty.c
new file mode 100644
index 0000000..6293de2
--- /dev/null
+++ b/src/ss7_as_vty.c
@@ -0,0 +1,627 @@
+/* SS7 AS VTY Interface */
+
+/* (C) 2015-2021 by Harald Welte <laforge(a)gnumonks.org>
+ * (C) 2025 by sysmocom s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <osmocom/vty/vty.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/logging.h>
+#include <osmocom/vty/telnet_interface.h>
+#include <osmocom/vty/misc.h>
+
+#include <osmocom/sigtran/protocol/mtp.h>
+
+#include "ss7_as.h"
+#include "ss7_asp.h"
+#include "ss7_route.h"
+#include "ss7_route_table.h"
+#include "ss7_internal.h"
+#include "ss7_vty.h"
+
+/***********************************************************************
+ * Application Server
+ ***********************************************************************/
+
+static struct cmd_node as_node = {
+ L_CS7_AS_NODE,
+ "%s(config-cs7-as)# ",
+ 1,
+};
+
+DEFUN_ATTR(cs7_as, cs7_as_cmd,
+ "as NAME " XUA_VAR_STR,
+ "Configure an Application Server\n"
+ "Name of the Application Server\n"
+ XUA_VAR_HELP_STR,
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_instance *inst = vty->index;
+ struct osmo_ss7_as *as;
+ const char *name = argv[0];
+ enum osmo_ss7_asp_protocol protocol = parse_asp_proto(argv[1]);
+
+ if (protocol == OSMO_SS7_ASP_PROT_NONE) {
+ vty_out(vty, "invalid protocol '%s'%s", argv[1], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ as = osmo_ss7_as_find_or_create(inst, name, protocol);
+ if (!as) {
+ vty_out(vty, "cannot create AS '%s'%s", name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ as->cfg.name = talloc_strdup(as, name);
+
+ vty->node = L_CS7_AS_NODE;
+ vty->index = as;
+ vty->index_sub = &as->cfg.description;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(no_cs7_as, no_cs7_as_cmd,
+ "no as NAME",
+ NO_STR "Disable Application Server\n"
+ "Name of AS\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_instance *inst = vty->index;
+ const char *name = argv[0];
+ struct osmo_ss7_as *as;
+
+ as = osmo_ss7_as_find_by_name(inst, name);
+ if (!as) {
+ vty_out(vty, "No AS named '%s' found%s", name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ osmo_ss7_as_destroy(as);
+ return CMD_SUCCESS;
+}
+
+/* TODO: routing-key */
+DEFUN_ATTR(as_asp, as_asp_cmd,
+ "asp NAME",
+ "Specify that a given ASP is part of this AS\n"
+ "Name of ASP to be added to AS\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_as *as = vty->index;
+
+ if (osmo_ss7_as_add_asp(as, argv[0])) {
+ vty_out(vty, "cannot find ASP '%s'%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(as_no_asp, as_no_asp_cmd,
+ "no asp NAME",
+ NO_STR "Specify ASP to be removed from this AS\n"
+ "Name of ASP to be removed\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_as *as = vty->index;
+
+ if (osmo_ss7_as_del_asp(as, argv[0])) {
+ vty_out(vty, "cannot find ASP '%s'%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_USRATTR(as_traf_mode, as_traf_mode_cmd,
+ OSMO_SCCP_LIB_ATTR_RSTRT_ASP,
+ "traffic-mode (broadcast | roundrobin | override)",
+ "Specifies traffic mode of operation of the ASP within the AS\n"
+ "Broadcast to all ASP within AS\n"
+ "Round-Robin between all ASP within AS\n"
+ "Override\n")
+{
+ struct osmo_ss7_as *as = vty->index;
+
+ as->cfg.mode = get_string_value(osmo_ss7_as_traffic_mode_vals, argv[0]);
+ as->cfg.mode_set_by_vty = true;
+ return CMD_SUCCESS;
+}
+
+DEFUN_USRATTR(as_traf_mode_loadshare, as_traf_mode_loadshare_cmd,
+ OSMO_SCCP_LIB_ATTR_RSTRT_ASP,
+ "traffic-mode loadshare [bindings] [sls] [opc-sls] [opc-shift]
[<0-2>]",
+ "Specifies traffic mode of operation of the ASP within the AS\n"
+ "Share Load among all ASP within AS\n"
+ "Configure Loadshare parameters\n"
+ "Configure Loadshare SLS generation parameters\n"
+ "Generate extended SLS with OPC information\n"
+ "Shift OPC bits used during routing decision\n"
+ "How many bits from ITU OPC field (starting from least-significant-bit) to
skip (default=0). 6 bits are always used\n"
+ )
+{
+ struct osmo_ss7_as *as = vty->index;
+
+ as->cfg.mode = OSMO_SS7_AS_TMOD_LOADSHARE;
+ as->cfg.mode_set_by_vty = true;
+ if (argc < 3) {
+ as->cfg.loadshare.opc_sls = false;
+ as->cfg.loadshare.opc_shift = 0;
+ return CMD_SUCCESS;
+ }
+ as->cfg.loadshare.opc_sls = true;
+ if (argc < 5) {
+ as->cfg.loadshare.opc_shift = 0;
+ return CMD_SUCCESS;
+ }
+ as->cfg.loadshare.opc_shift = atoi(argv[4]);
+ return CMD_SUCCESS;
+}
+
+DEFUN_USRATTR(as_no_traf_mode, as_no_traf_mode_cmd,
+ OSMO_SCCP_LIB_ATTR_RSTRT_ASP,
+ "no traffic-mode",
+ NO_STR "Remove explicit traffic mode of operation of this AS\n")
+{
+ struct osmo_ss7_as *as = vty->index;
+
+ as->cfg.mode = 0;
+ as->cfg.mode_set_by_vty = false;
+
+ as->cfg.loadshare.sls_shift = 0;
+ as->cfg.loadshare.opc_sls = false;
+ as->cfg.loadshare.opc_shift = 0;
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(as_sls_shift, as_sls_shift_cmd,
+ "sls-shift <0-3>",
+ "Shift SLS bits used during routing decision\n"
+ "How many bits from SLS field (starting from least-significant-bit) to
skip\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_as *as = vty->index;
+ as->cfg.loadshare.sls_shift = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(as_bindingtable_reset, as_bindingtable_reset_cmd,
+ "binding-table reset",
+ "AS Loadshare binding table operations\n"
+ "Reset loadshare binding table\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_as *as = vty->index;
+ ss7_as_loadshare_binding_table_reset(as);
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(as_recov_tout, as_recov_tout_cmd,
+ "recovery-timeout <1-2000>",
+ "Specifies the recovery timeout value in milliseconds\n"
+ "Recovery Timeout in Milliseconds\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_as *as = vty->index;
+ as->cfg.recovery_timeout_msec = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(as_qos_clas, as_qos_class_cmd,
+ "qos-class " QOS_CLASS_RANGE_STR,
+ "Specity QoS Class of AS\n"
+ QOS_CLASS_RANGE_HELP_STR,
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_as *as = vty->index;
+ as->cfg.qos_class = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
+const struct value_string mtp_si_vals[] = {
+ { MTP_SI_SCCP, "sccp" },
+ { MTP_SI_TUP, "tup" },
+ { MTP_SI_ISUP, "isup" },
+ { MTP_SI_DUP, "dup" },
+ { MTP_SI_TESTING, "testing" },
+ { MTP_SI_B_ISUP, "b-isup" },
+ { MTP_SI_SAT_ISUP, "sat-isup" },
+ { MTP_SI_AAL2_SIG, "aal2" },
+ { MTP_SI_BICC, "bicc" },
+ { MTP_SI_GCP, "h248" },
+ { 0, NULL }
+};
+
+#define ROUTING_KEY_CMD "routing-key RCONTEXT DPC"
+#define ROUTING_KEY_CMD_STRS \
+ "Define a routing key\n" \
+ "Routing context number\n" \
+ "Destination Point Code\n"
+#define ROUTING_KEY_SI_ARG " si
(aal2|bicc|b-isup|h248|isup|sat-isup|sccp|tup)"
+#define ROUTING_KEY_SI_ARG_STRS \
+ "Match on Service Indicator\n" \
+ "ATM Adaption Layer 2\n" \
+ "Bearer Independent Call Control\n" \
+ "Broadband ISDN User Part\n" \
+ "H.248\n" \
+ "ISDN User Part\n" \
+ "Sattelite ISDN User Part\n" \
+ "Signalling Connection Control Part\n" \
+ "Telephony User Part\n"
+#define ROUTING_KEY_SSN_ARG " ssn SSN"
+#define ROUTING_KEY_SSN_ARG_STRS \
+ "Match on Sub-System Number\n" \
+ "Sub-System Number to match on\n"
+
+static int _rout_key(struct vty *vty,
+ const char *rcontext, const char *dpc,
+ const char *si, const char *ssn)
+{
+ struct osmo_ss7_as *as = vty->index;
+ struct osmo_ss7_routing_key *rkey = &as->cfg.routing_key;
+ struct osmo_ss7_route *rt;
+ int pc;
+
+ if (as->cfg.proto == OSMO_SS7_ASP_PROT_IPA && atoi(rcontext) != 0) {
+ vty_out(vty, "IPA doesn't support routing contexts; only permitted routing
context "
+ "is 0\n");
+ return CMD_WARNING;
+ }
+
+ pc = osmo_ss7_pointcode_parse(as->inst, dpc);
+ if (pc < 0) {
+ vty_out(vty, "Invalid point code (%s)%s", dpc, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* When libosmo-sigtran is used in ASP role, the VTY routing table node
+ * (config-cs7-rt) is not available. However, when we add a routing key
+ * to an AS we still have to put a matching route into the routing
+ * table. This is done automatically by first removing the old route
+ * (users may change the routing key via VTY during runtime) and then
+ * putting a new route (see below). */
+ if (cs7_role == CS7_ROLE_ASP) {
+ rt = ss7_route_table_find_route_by_dpc_mask(as->inst->rtable_system, rkey->pc,
0xffffff);
+ if (rt)
+ ss7_route_destroy(rt);
+ }
+
+ rkey->pc = pc;
+
+ rkey->context = atoi(rcontext); /* FIXME: input validation */
+ rkey->si = si ? get_string_value(mtp_si_vals, si) : 0; /* FIXME: input validation */
+ rkey->ssn = ssn ? atoi(ssn) : 0; /* FIXME: input validation */
+
+ /* automatically add new route (see also comment above) */
+ if (cs7_role == CS7_ROLE_ASP) {
+ if (!ss7_route_create(as->inst->rtable_system, rkey->pc, 0xffffff,
as->cfg.name)) {
+ vty_out(vty, "Cannot create route (pc=%s, linkset=%s) to AS %s", dpc,
as->cfg.name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(as_rout_key, as_rout_key_cmd,
+ ROUTING_KEY_CMD,
+ ROUTING_KEY_CMD_STRS,
+ CMD_ATTR_IMMEDIATE)
+{
+ return _rout_key(vty, argv[0], argv[1], NULL, NULL);
+}
+
+DEFUN_ATTR(as_rout_key_si, as_rout_key_si_cmd,
+ ROUTING_KEY_CMD ROUTING_KEY_SI_ARG,
+ ROUTING_KEY_CMD_STRS ROUTING_KEY_SI_ARG_STRS,
+ CMD_ATTR_IMMEDIATE)
+{
+ return _rout_key(vty, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN_ATTR(as_rout_key_ssn, as_rout_key_ssn_cmd,
+ ROUTING_KEY_CMD ROUTING_KEY_SSN_ARG,
+ ROUTING_KEY_CMD_STRS ROUTING_KEY_SSN_ARG_STRS,
+ CMD_ATTR_IMMEDIATE)
+{
+ return _rout_key(vty, argv[0], argv[1], NULL, argv[2]);
+}
+
+DEFUN_ATTR(as_rout_key_si_ssn, as_rout_key_si_ssn_cmd,
+ ROUTING_KEY_CMD ROUTING_KEY_SI_ARG ROUTING_KEY_SSN_ARG,
+ ROUTING_KEY_CMD_STRS ROUTING_KEY_SI_ARG_STRS ROUTING_KEY_SSN_ARG_STRS,
+ CMD_ATTR_IMMEDIATE)
+{
+ return _rout_key(vty, argv[0], argv[1], argv[2], argv[3]);
+}
+
+DEFUN_ATTR(as_pc_override, as_pc_override_cmd,
+ "point-code override dpc PC",
+ "Point Code Specific Features\n"
+ "Override (force) a point-code to hard-coded value\n"
+ "Override Source Point Code\n"
+ "Override Destination Point Code\n"
+ "New Point Code\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_as *as = vty->index;
+ int pc = osmo_ss7_pointcode_parse(as->inst, argv[0]);
+ if (pc < 0) {
+ vty_out(vty, "Invalid point code (%s)%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (as->cfg.proto != OSMO_SS7_ASP_PROT_IPA) {
+ vty_out(vty, "Only IPA type AS support point-code override. "
+ "Be happy that you don't need it!%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ as->cfg.pc_override.dpc = pc;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(as_pc_patch_sccp, as_pc_patch_sccp_cmd,
+ "point-code override patch-sccp (disabled|both)",
+ "Point Code Specific Features\n"
+ "Override (force) a point-code to hard-coded value\n"
+ "Patch point code values into SCCP called/calling address\n"
+ "Don't patch any point codes into SCCP called/calling address\n"
+ "Patch both origin and destination point codes into SCCP called/calling
address\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_as *as = vty->index;
+
+ if (as->cfg.proto != OSMO_SS7_ASP_PROT_IPA) {
+ vty_out(vty, "Only IPA type AS support point-code patch-into-sccp. "
+ "Be happy that you don't need it!%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!strcmp(argv[0], "disabled"))
+ as->cfg.pc_override.sccp_mode = OSMO_SS7_PATCH_NONE;
+ else
+ as->cfg.pc_override.sccp_mode = OSMO_SS7_PATCH_BOTH;
+
+ return CMD_SUCCESS;
+}
+
+void ss7_vty_write_one_as(struct vty *vty, struct osmo_ss7_as *as, bool show_dyn_config)
+{
+ struct osmo_ss7_routing_key *rkey;
+ unsigned int i;
+
+ /* skip any dynamically allocated AS definitions */
+ if ((as->rkm_dyn_allocated || as->simple_client_allocated)
+ && !show_dyn_config)
+ return;
+
+ vty_out(vty, " as %s %s%s", as->cfg.name,
+ osmo_ss7_asp_protocol_name(as->cfg.proto), VTY_NEWLINE);
+ if (as->cfg.description)
+ vty_out(vty, " description %s%s", as->cfg.description, VTY_NEWLINE);
+ for (i = 0; i < ARRAY_SIZE(as->cfg.asps); i++) {
+ struct osmo_ss7_asp *asp = as->cfg.asps[i];
+ if (!asp)
+ continue;
+ /* skip any dynamically created ASPs (e.g. auto-created at connect time) */
+ if ((asp->dyn_allocated || asp->simple_client_allocated)
+ && !show_dyn_config)
+ continue;
+ vty_out(vty, " asp %s%s", asp->cfg.name, VTY_NEWLINE);
+ }
+ if (as->cfg.mode_set_by_vty) {
+ vty_out(vty, " traffic-mode %s%s",
osmo_ss7_as_traffic_mode_name(as->cfg.mode), VTY_NEWLINE);
+ if (as->cfg.mode == OSMO_SS7_AS_TMOD_LOADSHARE) {
+ if (as->cfg.loadshare.opc_sls) {
+ vty_out(vty, " bindings sls opc-sls");
+ if (as->cfg.loadshare.opc_shift != 0)
+ vty_out(vty, " opc-shift %u", as->cfg.loadshare.opc_shift);
+ }
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
+
+ if (as->cfg.loadshare.sls_shift != 0)
+ vty_out(vty, " sls-shift %u%s", as->cfg.loadshare.sls_shift,
VTY_NEWLINE);
+ }
+
+ if (as->cfg.recovery_timeout_msec != 2000) {
+ vty_out(vty, " recovery-timeout %u%s",
+ as->cfg.recovery_timeout_msec, VTY_NEWLINE);
+ }
+ if (as->cfg.qos_class)
+ vty_out(vty, " qos-class %u%s", as->cfg.qos_class, VTY_NEWLINE);
+ rkey = &as->cfg.routing_key;
+ vty_out(vty, " routing-key %u %s", rkey->context,
+ osmo_ss7_pointcode_print(as->inst, rkey->pc));
+ if (rkey->si)
+ vty_out(vty, " si %s",
+ get_value_string(mtp_si_vals, rkey->si));
+ if (rkey->ssn)
+ vty_out(vty, " ssn %u", rkey->ssn);
+ vty_out(vty, "%s", VTY_NEWLINE);
+
+ if (as->cfg.pc_override.dpc)
+ vty_out(vty, " point-code override dpc %s%s",
+ osmo_ss7_pointcode_print(as->inst, as->cfg.pc_override.dpc), VTY_NEWLINE);
+
+ if (as->cfg.pc_override.sccp_mode)
+ vty_out(vty, " point-code override patch-sccp both%s", VTY_NEWLINE);
+}
+
+static void show_one_as(struct vty *vty, struct osmo_ss7_as *as)
+{
+ vty_out(vty, "%-12s %-12s %-10u %-13s %4s %13s %3s %5s %4s %10s%s",
+ as->cfg.name, osmo_fsm_inst_state_name(as->fi), as->cfg.routing_key.context,
+ osmo_ss7_pointcode_print(as->inst, as->cfg.routing_key.pc),
+ "", "", "", "", "",
osmo_ss7_as_traffic_mode_name(as->cfg.mode),
+ VTY_NEWLINE);
+}
+
+static int show_as(struct vty *vty, int id, const char *as_name, const char *filter)
+{
+ struct osmo_ss7_instance *inst;
+ struct osmo_ss7_as *as = NULL;
+
+ inst = osmo_ss7_instance_find(id);
+ if (!inst) {
+ vty_out(vty, "%% No SS7 instance %d found%s", id, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (as_name) {
+ as = osmo_ss7_as_find_by_name(inst, as_name);
+ if (!as) {
+ vty_out(vty, "%% No AS '%s' found%s", as_name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ vty_out(vty, " Routing Routing Key
Cic Cic Traffic%s", VTY_NEWLINE);
+ vty_out(vty, "AS Name State Context Dpc Si Opc
Ssn Min Max Mode%s", VTY_NEWLINE);
+ vty_out(vty, "------------ ------------ ---------- ------------- ---- -------------
--- ----- ----- -------%s", VTY_NEWLINE);
+
+ if (as) {
+ show_one_as(vty, as);
+ return CMD_SUCCESS;
+ }
+
+ llist_for_each_entry(as, &inst->as_list, list) {
+ if (filter && !strcmp(filter, "m3ua") && as->cfg.proto !=
OSMO_SS7_ASP_PROT_M3UA)
+ continue;
+ if (filter && !strcmp(filter, "sua") && as->cfg.proto !=
OSMO_SS7_ASP_PROT_SUA)
+ continue;
+ if (filter && !strcmp(filter, "active") &&
!osmo_ss7_as_active(as))
+ continue;
+ show_one_as(vty, as);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN(show_cs7_as, show_cs7_as_cmd,
+ "show cs7 instance <0-15> as (active|all|m3ua|sua)",
+ SHOW_STR CS7_STR INST_STR INST_STR "Application Server (AS)\n"
+ "Display all active ASs\n"
+ "Display all ASs (default)\n"
+ "Display all m3ua ASs\n"
+ "Display all SUA ASs\n")
+{
+ const char *filter = argv[1];
+ int id = atoi(argv[0]);
+
+ return show_as(vty, id, NULL, filter);
+}
+
+DEFUN(show_cs7_as_name, show_cs7_as_name_cmd,
+ "show cs7 instance <0-15> as name AS_NAME",
+ SHOW_STR CS7_STR INST_STR INST_STR "Application Server (AS)\n"
+ "Look up AS with a given name\n"
+ "Name of the Application Server (AS)\n")
+{
+ int id = atoi(argv[0]);
+ const char *as_name = argv[1];
+
+ return show_as(vty, id, as_name, NULL);
+}
+
+DEFUN(show_cs7_as_bindingtable_name, show_cs7_as_bindingtable_name_cmd,
+ "show cs7 instance <0-15> as binding-table name AS_NAME",
+ SHOW_STR CS7_STR INST_STR INST_STR "Application Server (AS)\n"
+ "Display binding table\n"
+ "Look up AS with a given name\n"
+ "Name of the Application Server (AS)\n")
+{
+ int id = atoi(argv[0]);
+ const char *as_name = argv[1];
+ struct osmo_ss7_instance *inst;
+ struct osmo_ss7_as *as = NULL;
+
+ inst = osmo_ss7_instance_find(id);
+ if (!inst) {
+ vty_out(vty, "No SS7 instance %d found%s", id, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (as_name) {
+ as = osmo_ss7_as_find_by_name(inst, as_name);
+ if (!as) {
+ vty_out(vty, "No AS %s found%s", as_name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ vty_out(vty, "Loadshare Seed Normal ASP Active Alternative ASP
Active%s", VTY_NEWLINE);
+ vty_out(vty, "-------------- --------------- ------ ---------------
------%s", VTY_NEWLINE);
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(as->aesls_table); i++) {
+ struct osmo_ss7_as_esls_entry *e = &as->aesls_table[i];
+ vty_out(vty, "%-15u %-16s %-7s %-16s %-7s%s",
+ i,
+ e->normal_asp ? e->normal_asp->cfg.name : "-",
+ e->normal_asp ? (osmo_ss7_asp_active(e->normal_asp) ? "Yes" :
"No") : "-",
+ e->alt_asp ? e->alt_asp->cfg.name : "-",
+ e->alt_asp ? (osmo_ss7_asp_active(e->alt_asp) ? "Yes" :
"No") : "-",
+ VTY_NEWLINE);
+ }
+
+ return CMD_SUCCESS;
+}
+
+int ss7_vty_node_as_go_parent(struct vty *vty)
+{
+ struct osmo_ss7_as *as = vty->index;
+ vty->node = L_CS7_NODE;
+ vty->index = as->inst;
+ return 0;
+}
+
+void ss7_vty_init_node_as(void)
+{
+ install_node(&as_node, NULL);
+ install_lib_element_ve(&show_cs7_as_cmd);
+ install_lib_element_ve(&show_cs7_as_name_cmd);
+ install_lib_element_ve(&show_cs7_as_bindingtable_name_cmd);
+ install_lib_element(L_CS7_NODE, &cs7_as_cmd);
+ install_lib_element(L_CS7_NODE, &no_cs7_as_cmd);
+ install_lib_element(L_CS7_AS_NODE, &cfg_description_cmd);
+ install_lib_element(L_CS7_AS_NODE, &as_asp_cmd);
+ install_lib_element(L_CS7_AS_NODE, &as_no_asp_cmd);
+ install_lib_element(L_CS7_AS_NODE, &as_traf_mode_cmd);
+ install_lib_element(L_CS7_AS_NODE, &as_traf_mode_loadshare_cmd);
+ install_lib_element(L_CS7_AS_NODE, &as_no_traf_mode_cmd);
+ install_lib_element(L_CS7_AS_NODE, &as_sls_shift_cmd);
+ install_lib_element(L_CS7_AS_NODE, &as_bindingtable_reset_cmd);
+ install_lib_element(L_CS7_AS_NODE, &as_recov_tout_cmd);
+ install_lib_element(L_CS7_AS_NODE, &as_qos_class_cmd);
+ install_lib_element(L_CS7_AS_NODE, &as_rout_key_cmd);
+ install_lib_element(L_CS7_AS_NODE, &as_rout_key_si_cmd);
+ install_lib_element(L_CS7_AS_NODE, &as_rout_key_ssn_cmd);
+ install_lib_element(L_CS7_AS_NODE, &as_rout_key_si_ssn_cmd);
+ install_lib_element(L_CS7_AS_NODE, &as_pc_override_cmd);
+ install_lib_element(L_CS7_AS_NODE, &as_pc_patch_sccp_cmd);
+}
diff --git a/src/ss7_asp_vty.c b/src/ss7_asp_vty.c
new file mode 100644
index 0000000..2934ea3
--- /dev/null
+++ b/src/ss7_asp_vty.c
@@ -0,0 +1,1163 @@
+/* SS7 ASP VTY Interface */
+
+/* (C) 2015-2021 by Harald Welte <laforge(a)gnumonks.org>
+ * (C) 2025 by sysmocom s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+
+#include <osmocom/core/sockaddr_str.h>
+
+#include <osmocom/vty/vty.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/logging.h>
+#include <osmocom/vty/telnet_interface.h>
+#include <osmocom/vty/misc.h>
+
+#include <osmocom/netif/stream.h>
+
+#include <osmocom/sigtran/osmo_ss7.h>
+
+#include "xua_internal.h"
+#include "ss7_as.h"
+#include "ss7_asp.h"
+#include "ss7_combined_linkset.h"
+#include <ss7_linkset.h>
+#include "ss7_internal.h"
+#include "ss7_vty.h"
+
+#include <netinet/tcp.h>
+
+#ifdef HAVE_LIBSCTP
+#include <netinet/sctp.h>
+#include <osmocom/netif/sctp.h>
+#endif
+
+/***********************************************************************
+ * Application Server Process
+ ***********************************************************************/
+
+static struct cmd_node asp_node = {
+ L_CS7_ASP_NODE,
+ "%s(config-cs7-asp)# ",
+ 1,
+};
+
+/* netinet/tcp.h */
+static const struct value_string tcp_info_state_values[] = {
+ { TCP_ESTABLISHED, "ESTABLISHED" },
+ { TCP_SYN_SENT, "SYN_SENT" },
+ { TCP_SYN_RECV, "SYN_RECV" },
+ { TCP_FIN_WAIT1, "FIN_WAIT1" },
+ { TCP_FIN_WAIT2, "FIN_WAIT2" },
+ { TCP_TIME_WAIT, "TIME_WAIT" },
+ { TCP_CLOSE, "CLOSE" },
+ { TCP_CLOSE_WAIT, "CLOSE_WAIT" },
+ { TCP_LAST_ACK, "LAST_ACK" },
+ { TCP_LISTEN, "LISTEN" },
+ { TCP_CLOSING, "CLOSING" },
+ {}
+};
+
+
+static const struct value_string asp_quirk_names[] = {
+ { OSMO_SS7_ASP_QUIRK_NO_NOTIFY, "no_notify" },
+ { OSMO_SS7_ASP_QUIRK_DAUD_IN_ASP, "daud_in_asp" },
+ { OSMO_SS7_ASP_QUIRK_SNM_INACTIVE, "snm_inactive" },
+ { 0, NULL }
+};
+
+static const struct value_string asp_quirk_descs[] = {
+ { OSMO_SS7_ASP_QUIRK_NO_NOTIFY, "Peer SG doesn't send NTFY(AS-INACTIVE) after
ASP-UP" },
+ { OSMO_SS7_ASP_QUIRK_DAUD_IN_ASP, "Allow Rx of DAUD in ASP role" },
+ { OSMO_SS7_ASP_QUIRK_SNM_INACTIVE, "Allow Rx of [S]SNM in AS-INACTIVE state"
},
+ { 0, NULL }
+};
+
+DEFUN_ATTR(cs7_asp, cs7_asp_cmd,
+ "asp NAME <0-65535> <0-65535> " XUA_VAR_STR,
+ "Configure Application Server Process\n"
+ "Name of ASP\n"
+ "Remote port number\n"
+ "Local port number\n"
+ XUA_VAR_HELP_STR,
+ CMD_ATTR_NODE_EXIT)
+{
+ struct osmo_ss7_instance *inst = vty->index;
+ const char *name = argv[0];
+ uint16_t remote_port = atoi(argv[1]);
+ uint16_t local_port = atoi(argv[2]);
+ enum osmo_ss7_asp_protocol proto = parse_asp_proto(argv[3]);
+ struct osmo_ss7_asp *asp;
+ int trans_proto;
+
+ if (proto == OSMO_SS7_ASP_PROT_NONE) {
+ vty_out(vty, "invalid protocol '%s'%s", argv[3], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* argv[4] can be supplied by an alias (see below) */
+ if (argc > 4)
+ trans_proto = parse_trans_proto(argv[4]);
+ else /* default transport protocol */
+ trans_proto = ss7_default_trans_proto_for_asp_proto(proto);
+ if (trans_proto < 0)
+ return CMD_WARNING;
+
+ asp = osmo_ss7_asp_find2(inst, name,
+ remote_port, local_port,
+ trans_proto, proto);
+ if (!asp) {
+ asp = osmo_ss7_asp_find_or_create2(inst, name,
+ remote_port, local_port,
+ trans_proto, proto);
+ if (!asp) {
+ vty_out(vty, "cannot create ASP '%s'%s", name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ asp->cfg.is_server = true;
+ asp->cfg.role = OSMO_SS7_ASP_ROLE_SG;
+ }
+
+ /* Reset value, will be checked at osmo_ss7_vty_go_parent() */
+ asp->cfg.explicit_shutdown_state_by_vty_since_node_enter = false;
+
+ vty->node = L_CS7_ASP_NODE;
+ vty->index = asp;
+ vty->index_sub = &asp->cfg.description;
+ return CMD_SUCCESS;
+}
+
+/* XXX: workaround for
https://osmocom.org/issues/6360, can be removed once it's
fixed.
+ * Currently we hit an assert if we make the IPPROTO_VAR_STR optional in cs7_asp_cmd. */
+ALIAS_ATTR(cs7_asp, cs7_asp_trans_proto_cmd,
+ "asp NAME <0-65535> <0-65535> " XUA_VAR_STR " "
IPPROTO_VAR_STR,
+ "Configure Application Server Process\n"
+ "Name of ASP\n"
+ "Remote port number\n"
+ "Local port number\n"
+ XUA_VAR_HELP_STR
+ IPPROTO_VAR_HELP_STR,
+ CMD_ATTR_NODE_EXIT);
+
+DEFUN_ATTR(no_cs7_asp, no_cs7_asp_cmd,
+ "no asp NAME",
+ NO_STR "Disable Application Server Process\n"
+ "Name of ASP\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_instance *inst = vty->index;
+ const char *name = argv[0];
+ struct osmo_ss7_asp *asp;
+
+ asp = osmo_ss7_asp_find_by_name(inst, name);
+ if (!asp) {
+ vty_out(vty, "No ASP named '%s' found%s", name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ osmo_ss7_asp_destroy(asp);
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(asp_local_ip, asp_local_ip_cmd,
+ "local-ip " VTY_IPV46_CMD " [primary]",
+ "Specify Local IP Address from which to contact ASP\n"
+ "Local IPv4 Address from which to contact of ASP\n"
+ "Local IPv6 Address from which to contact of ASP\n"
+ "Signal the SCTP peer to use this address as Primary Address\n",
+ CMD_ATTR_NODE_EXIT)
+{
+ struct osmo_ss7_asp *asp = vty->index;
+ bool is_primary = argc > 1;
+ int old_idx_primary = asp->cfg.local.idx_primary;
+ int old_host_count = asp->cfg.local.host_cnt;
+ int rc;
+
+ if (ss7_asp_peer_add_host2(&asp->cfg.local, asp, argv[0], is_primary) != 0) {
+ vty_out(vty, "%% Failed adding host '%s' to set%s", argv[0],
VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!ss7_asp_is_started(asp))
+ return CMD_SUCCESS;
+ if (asp->cfg.proto == OSMO_SS7_ASP_PROT_IPA)
+ return CMD_SUCCESS;
+ /* The SCTP socket is already created. */
+
+ /* dynamically apply the new address if it was added to the set: */
+ if (asp->cfg.local.host_cnt > old_host_count) {
+ if ((rc = ss7_asp_apply_new_local_address(asp, asp->cfg.local.host_cnt - 1)) < 0)
{
+ /* Failed, rollback changes: */
+ TALLOC_FREE(asp->cfg.local.host[asp->cfg.local.host_cnt - 1]);
+ asp->cfg.local.host_cnt--;
+ vty_out(vty, "%% Failed adding new local address '%s'%s", argv[0],
VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ vty_out(vty, "%% Local address '%s' added to the active socket bind
set%s", argv[0], VTY_NEWLINE);
+ }
+
+ /* dynamically apply the new primary if it changed: */
+ if (is_primary && asp->cfg.local.idx_primary != old_idx_primary) {
+ if ((rc = ss7_asp_apply_peer_primary_address(asp)) < 0) {
+ /* Failed, rollback changes: */
+ asp->cfg.local.idx_primary = old_idx_primary;
+ vty_out(vty, "%% Failed announcing primary '%s' to peer%s", argv[0],
VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ vty_out(vty, "%% Local address '%s' announced as primary to the peer on
the active socket%s", argv[0], VTY_NEWLINE);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(asp_no_local_ip, asp_no_local_ip_cmd,
+ "no local-ip " VTY_IPV46_CMD,
+ NO_STR "Specify Local IP Address from which to contact ASP\n"
+ "Local IPv4 Address from which to contact of ASP\n"
+ "Local IPv6 Address from which to contact of ASP\n",
+ CMD_ATTR_NODE_EXIT)
+{
+ struct osmo_ss7_asp *asp = vty->index;
+ int idx = ss7_asp_peer_find_host(&asp->cfg.local, argv[0]);
+ int rc;
+
+ if (idx < 0) {
+ vty_out(vty, "%% Local address '%s' not found in set%s", argv[0],
VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (ss7_asp_is_started(asp)) {
+ if (asp->cfg.proto != OSMO_SS7_ASP_PROT_IPA) {
+ if ((rc = ss7_asp_apply_drop_local_address(asp, idx)) < 0) {
+ vty_out(vty, "%% Failed removing local address '%s' from existing
socket%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ vty_out(vty, "%% Local address '%s' removed from active socket
connection%s", argv[0], VTY_NEWLINE);
+ }
+ }
+
+ if (ss7_asp_peer_del_host(&asp->cfg.local, argv[0]) != 0) {
+ vty_out(vty, "%% Failed deleting local address '%s' from set%s",
argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(asp_remote_ip, asp_remote_ip_cmd,
+ "remote-ip " VTY_IPV46_CMD " [primary]",
+ "Specify Remote IP Address of ASP\n"
+ "Remote IPv4 Address of ASP\n"
+ "Remote IPv6 Address of ASP\n"
+ "Set remote address as SCTP Primary Address\n",
+ CMD_ATTR_NODE_EXIT)
+{
+ struct osmo_ss7_asp *asp = vty->index;
+ bool is_primary = argc > 1;
+ int old_idx_primary = asp->cfg.remote.idx_primary;
+ int rc;
+
+ if (ss7_asp_peer_add_host2(&asp->cfg.remote, asp, argv[0], is_primary) != 0) {
+ vty_out(vty, "%% Failed adding host '%s' to set%s", argv[0],
VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!ss7_asp_is_started(asp))
+ return CMD_SUCCESS;
+ if (asp->cfg.proto == OSMO_SS7_ASP_PROT_IPA)
+ return CMD_SUCCESS;
+
+ /* The SCTP socket is already created, dynamically apply the new primary if it changed:
*/
+ if (asp->cfg.proto != OSMO_SS7_ASP_PROT_IPA && ss7_asp_is_started(asp)) {
+ if ((rc = ss7_asp_apply_primary_address(asp)) < 0) {
+ /* Failed, rollback changes: */
+ asp->cfg.remote.idx_primary = old_idx_primary;
+ vty_out(vty, "%% Failed applying primary on host '%s'%s", argv[0],
VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(asp_no_remote_ip, asp_no_remote_ip_cmd,
+ "no remote-ip " VTY_IPV46_CMD,
+ NO_STR "Specify Remote IP Address of ASP\n"
+ "Remote IPv4 Address of ASP\n"
+ "Remote IPv6 Address of ASP\n",
+ CMD_ATTR_NODE_EXIT)
+{
+ struct osmo_ss7_asp *asp = vty->index;
+ int idx = ss7_asp_peer_find_host(&asp->cfg.remote, argv[0]);
+
+ if (idx < 0) {
+ vty_out(vty, "%% Remote address '%s' not found in set%s", argv[0],
VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (ss7_asp_peer_del_host(&asp->cfg.remote, argv[0]) != 0) {
+ vty_out(vty, "%% Failed deleting remote address '%s' from set%s",
argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(asp_qos_clas, asp_qos_class_cmd,
+ "qos-class " QOS_CLASS_RANGE_STR,
+ "Specify QoS Class of ASP\n"
+ QOS_CLASS_RANGE_HELP_STR,
+ CMD_ATTR_NODE_EXIT)
+{
+ struct osmo_ss7_asp *asp = vty->index;
+ asp->cfg.qos_class = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(asp_role, asp_role_cmd,
+ "role (sg|asp|ipsp)",
+ "Specify the xUA role for this ASP\n"
+ "SG (Signaling Gateway)\n"
+ "ASP (Application Server Process)\n"
+ "IPSP (IP Signalling Point)\n",
+ CMD_ATTR_NODE_EXIT)
+{
+ struct osmo_ss7_asp *asp = vty->index;
+
+ if (!strcmp(argv[0], "ipsp")) {
+ vty_out(vty, "IPSP role isn't supported yet%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (!strcmp(argv[0], "sg"))
+ asp->cfg.role = OSMO_SS7_ASP_ROLE_SG;
+ else if (!strcmp(argv[0], "asp"))
+ asp->cfg.role = OSMO_SS7_ASP_ROLE_ASP;
+ else
+ OSMO_ASSERT(0);
+
+ asp->cfg.role_set_by_vty = true;
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(asp_transport_role, asp_transport_role_cmd,
+ "transport-role (client|server)",
+ "Specify the transport layer role for this ASP\n"
+ "Operate as a client; connect to a server\n"
+ "Operate as a server; wait for client connections\n",
+ CMD_ATTR_NODE_EXIT)
+{
+ struct osmo_ss7_asp *asp = vty->index;
+
+ if (!strcmp(argv[0], "client"))
+ asp->cfg.is_server = false;
+ else if (!strcmp(argv[0], "server"))
+ asp->cfg.is_server = true;
+ else
+ OSMO_ASSERT(0);
+
+ asp->cfg.trans_role_set_by_vty = true;
+ return CMD_SUCCESS;
+}
+
+ALIAS_ATTR(asp_transport_role, asp_sctp_role_cmd,
+ "sctp-role (client|server)",
+ "Specify the SCTP role for this ASP\n"
+ "Operate as SCTP client; connect to a server\n"
+ "Operate as SCTP server; wait for client connections\n",
+ CMD_ATTR_HIDDEN | CMD_ATTR_NODE_EXIT);
+
+#define ASP_SCTP_PARAM_INIT_DESC \
+ "Configure SCTP parameters\n" \
+ "Configure INIT related parameters\n" \
+ "Configure INIT Number of Outbound Streams\n" \
+ "Configure INIT Maximum Inboud Streams\n" \
+ "Configure INIT Maximum Attempts\n" \
+ "Configure INIT Timeout (milliseconds)\n"
+#define ASP_SCTP_PARAM_INIT_FIELDS
"(num-ostreams|max-instreams|max-attempts|timeout)"
+
+DEFUN_ATTR(asp_sctp_param_init, asp_sctp_param_init_cmd,
+ "sctp-param init " ASP_SCTP_PARAM_INIT_FIELDS "
<0-65535>",
+ ASP_SCTP_PARAM_INIT_DESC
+ "Value of the parameter\n",
+ CMD_ATTR_NODE_EXIT)
+{
+ struct osmo_ss7_asp *asp = vty->index;
+
+ uint16_t val = atoi(argv[1]);
+
+ if (strcmp(argv[0], "num-ostreams") == 0) {
+ asp->cfg.sctp_init.num_ostreams_present = true;
+ asp->cfg.sctp_init.num_ostreams_value = val;
+ } else if (strcmp(argv[0], "max-instreams") == 0) {
+ asp->cfg.sctp_init.max_instreams_present = true;
+ asp->cfg.sctp_init.max_instreams_value = val;
+ } else if (strcmp(argv[0], "max-attempts") == 0) {
+ asp->cfg.sctp_init.max_attempts_present = true;
+ asp->cfg.sctp_init.max_attempts_value = val;
+ } else if (strcmp(argv[0], "timeout") == 0) {
+ asp->cfg.sctp_init.max_init_timeo_present = true;
+ asp->cfg.sctp_init.max_init_timeo_value = val;
+ } else {
+ OSMO_ASSERT(0);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(asp_no_sctp_param_init, asp_no_sctp_param_init_cmd,
+ "no sctp-param init " ASP_SCTP_PARAM_INIT_FIELDS,
+ NO_STR ASP_SCTP_PARAM_INIT_DESC,
+ CMD_ATTR_NODE_EXIT)
+{
+ struct osmo_ss7_asp *asp = vty->index;
+
+ if (strcmp(argv[0], "num-ostreams") == 0)
+ asp->cfg.sctp_init.num_ostreams_present = false;
+ else if (strcmp(argv[0], "max-instreams") == 0)
+ asp->cfg.sctp_init.max_instreams_present = false;
+ else if (strcmp(argv[0], "max-attempts") == 0)
+ asp->cfg.sctp_init.max_attempts_present = false;
+ else if (strcmp(argv[0], "timeout") == 0)
+ asp->cfg.sctp_init.max_init_timeo_present = false;
+ else
+ OSMO_ASSERT(0);
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(asp_block, asp_block_cmd,
+ "block",
+ "Allows a SCTP Association with ASP, but doesn't let it become
active\n",
+ CMD_ATTR_NODE_EXIT)
+{
+ /* TODO */
+ vty_out(vty, "Not supported yet%s", VTY_NEWLINE);
+ return CMD_WARNING;
+}
+
+DEFUN_ATTR(asp_shutdown, asp_shutdown_cmd,
+ "shutdown",
+ "Terminates SCTP association; New associations will be rejected\n",
+ CMD_ATTR_NODE_EXIT)
+{
+ struct osmo_ss7_asp *asp = vty->index;
+
+ LOGPASP(asp, DLSS7, LOGL_NOTICE, "Applying Adm State change: %s -> %s\n",
+ get_value_string(osmo_ss7_asp_admin_state_names, asp->cfg.adm_state),
+ get_value_string(osmo_ss7_asp_admin_state_names, OSMO_SS7_ASP_ADM_S_SHUTDOWN));
+
+ asp->cfg.explicit_shutdown_state_by_vty_since_node_enter = true;
+ asp->cfg.adm_state = OSMO_SS7_ASP_ADM_S_SHUTDOWN;
+ ss7_asp_restart_after_reconfigure(asp);
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(asp_no_shutdown, asp_no_shutdown_cmd,
+ "no shutdown",
+ NO_STR "Terminates SCTP association; New associations will be rejected\n",
+ CMD_ATTR_NODE_EXIT)
+{
+ struct osmo_ss7_asp *asp = vty->index;
+
+ LOGPASP(asp, DLSS7, LOGL_NOTICE, "Applying Adm State change: %s -> %s\n",
+ get_value_string(osmo_ss7_asp_admin_state_names, asp->cfg.adm_state),
+ get_value_string(osmo_ss7_asp_admin_state_names, OSMO_SS7_ASP_ADM_S_ENABLED));
+
+ asp->cfg.explicit_shutdown_state_by_vty_since_node_enter = true;
+ asp->cfg.adm_state = OSMO_SS7_ASP_ADM_S_ENABLED;
+ ss7_asp_restart_after_reconfigure(asp);
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(asp_quirk, asp_quirk_cmd,
+ "OVERWRITTEN",
+ "OVERWRITTEN\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_asp *asp = vty->index;
+ int quirk = get_string_value(asp_quirk_names, argv[0]);
+
+ if (quirk < 0)
+ return CMD_WARNING;
+
+ asp->cfg.quirks |= quirk;
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(asp_no_quirk, asp_no_quirk_cmd,
+ "OVERWRITTEN",
+ "OVERWRITTEN\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_asp *asp = vty->index;
+ int quirk = get_string_value(asp_quirk_names, argv[0]);
+
+ if (quirk < 0)
+ return CMD_WARNING;
+
+ asp->cfg.quirks &= ~quirk;
+ return CMD_SUCCESS;
+}
+
+/* timer lm <name> <1-999999>
+ * (cmdstr and doc are dynamically generated from ss7_asp_lm_timer_names.) */
+DEFUN_ATTR(asp_timer, asp_timer_cmd,
+ NULL, NULL, CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_asp *asp = vty->index;
+ enum ss7_asp_lm_timer timer = get_string_value(ss7_asp_lm_timer_names, argv[0]);
+
+ if (timer <= 0 || timer >= SS7_ASP_LM_TIMERS_LEN) {
+ vty_out(vty, "%% Invalid timer: %s%s", argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ osmo_tdef_set(asp->cfg.T_defs_lm, timer, atoi(argv[1]), OSMO_TDEF_S);
+ return CMD_SUCCESS;
+}
+
+static void gen_asp_timer_cmd_strs(struct cmd_element *cmd)
+{
+ int i;
+ char *cmd_str = NULL;
+ char *doc_str = NULL;
+
+ OSMO_ASSERT(cmd->string == NULL);
+ OSMO_ASSERT(cmd->doc == NULL);
+
+ osmo_talloc_asprintf(tall_vty_ctx, cmd_str, "timer lm (");
+ osmo_talloc_asprintf(tall_vty_ctx, doc_str,
+ "Configure ASP default timer values\n"
+ "Configure ASP default lm timer values\n");
+
+ for (i = 0; ss7_asp_lm_timer_names[i].str; i++) {
+ const struct osmo_tdef *def;
+ enum ss7_asp_lm_timer timer;
+
+ timer = ss7_asp_lm_timer_names[i].value;
+ def = osmo_tdef_get_entry((struct osmo_tdef *)&ss7_asp_lm_timer_defaults, timer);
+ OSMO_ASSERT(def);
+
+ osmo_talloc_asprintf(tall_vty_ctx, cmd_str, "%s%s",
+ i ? "|" : "",
+ ss7_asp_lm_timer_names[i].str);
+ osmo_talloc_asprintf(tall_vty_ctx, doc_str, "%s (default: %lu)\n",
+ def->desc,
+ def->default_val);
+ }
+
+ osmo_talloc_asprintf(tall_vty_ctx, cmd_str, ") <1-999999>");
+ osmo_talloc_asprintf(tall_vty_ctx, doc_str,
+ "Timer value, in seconds\n");
+
+ cmd->string = cmd_str;
+ cmd->doc = doc_str;
+}
+
+static void write_asp_timers(struct vty *vty, const char *indent,
+ struct osmo_ss7_asp *asp)
+{
+ int i;
+
+ for (i = 0; ss7_asp_lm_timer_names[i].str; i++) {
+ const struct osmo_tdef *tdef = osmo_tdef_get_entry(asp->cfg.T_defs_lm,
ss7_asp_lm_timer_names[i].value);
+ if (!tdef)
+ continue;
+ if (tdef->val == tdef->default_val)
+ continue;
+ vty_out(vty, "%stimer lm %s %lu%s", indent, ss7_asp_lm_timer_names[i].str,
+ tdef->val, VTY_NEWLINE);
+ }
+}
+
+static char *as_list_for_asp(const struct osmo_ss7_asp *asp, char *buf, size_t buf_len)
+{
+ struct osmo_strbuf sb = { .buf = buf, .len = buf_len };
+ const struct osmo_ss7_as *as;
+ unsigned int count = 0;
+ llist_for_each_entry(as, &asp->inst->as_list, list) {
+ if (!osmo_ss7_as_has_asp(as, asp))
+ continue;
+ OSMO_STRBUF_PRINTF(sb, "%s%s", count != 0 ? "," : "",
as->cfg.name);
+ count++;
+ break;
+ }
+
+ if (count == 0)
+ OSMO_STRBUF_PRINTF(sb, "?");
+ return buf;
+}
+
+/* Similar to osmo_sock_multiaddr_get_name_buf(), but aimed at listening sockets (only
local part): */
+static char *get_sockname_buf(char *buf, size_t buf_len, int fd, int proto, bool local)
+{
+ char hostbuf[OSMO_SOCK_MAX_ADDRS][INET6_ADDRSTRLEN];
+ size_t num_hostbuf = ARRAY_SIZE(hostbuf);
+ char portbuf[6];
+ struct osmo_strbuf sb = { .buf = buf, .len = buf_len };
+ bool need_more_bufs;
+ int rc;
+
+ rc = osmo_sock_multiaddr_get_ip_and_port(fd, proto, &hostbuf[0][0],
+ &num_hostbuf, sizeof(hostbuf[0]),
+ portbuf, sizeof(portbuf), local);
+ if (rc < 0)
+ return NULL;
+
+ need_more_bufs = num_hostbuf > ARRAY_SIZE(hostbuf);
+ if (need_more_bufs)
+ num_hostbuf = ARRAY_SIZE(hostbuf);
+ OSMO_STRBUF_APPEND(sb, osmo_multiaddr_ip_and_port_snprintf,
+ &hostbuf[0][0], num_hostbuf, sizeof(hostbuf[0]), portbuf);
+ if (need_more_bufs)
+ OSMO_STRBUF_PRINTF(sb, "<need-more-bufs!>");
+
+ return buf;
+}
+
+static void show_one_asp(struct vty *vty, struct osmo_ss7_asp *asp)
+{
+ char as_buf[64];
+ char buf_loc[OSMO_SOCK_MULTIADDR_PEER_STR_MAXLEN];
+ char buf_rem[sizeof(buf_loc)];
+
+ int fd = ss7_asp_get_fd(asp);
+ if (fd > 0) {
+ const int trans_proto = asp->cfg.trans_proto;
+ if (!get_sockname_buf(buf_loc, sizeof(buf_loc), fd, trans_proto, true))
+ OSMO_STRLCPY_ARRAY(buf_loc, "<sockname-error>");
+ if (!get_sockname_buf(buf_rem, sizeof(buf_rem), fd, trans_proto, false))
+ OSMO_STRLCPY_ARRAY(buf_rem, "<sockname-error>");
+ } else {
+ ss7_asp_peer_snprintf(buf_loc, sizeof(buf_loc), &asp->cfg.local);
+ ss7_asp_peer_snprintf(buf_rem, sizeof(buf_rem), &asp->cfg.remote);
+ }
+
+ vty_out(vty, "%-12s %-12s %-13s %-4s %-4s %-9s %-23s %-23s%s",
+ asp->cfg.name,
+ as_list_for_asp(asp, as_buf, sizeof(as_buf)),
+ asp->fi ? osmo_fsm_inst_state_name(asp->fi) : "uninitialized",
+ get_value_string(osmo_ss7_asp_protocol_vals, asp->cfg.proto),
+ osmo_str_tolower(get_value_string(osmo_ss7_asp_role_names, asp->cfg.role)),
+ asp->cfg.is_server ? "server" : "client",
+ buf_loc, buf_rem,
+ VTY_NEWLINE);
+}
+
+static int show_asp(struct vty *vty, int id, const char *asp_name)
+{
+ struct osmo_ss7_instance *inst;
+ struct osmo_ss7_asp *asp = NULL;
+
+ inst = osmo_ss7_instance_find(id);
+ if (!inst) {
+ vty_out(vty, "No SS7 instance %d found%s", id, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (asp_name) {
+ asp = osmo_ss7_asp_find_by_name(inst, asp_name);
+ if (!asp) {
+ vty_out(vty, "No ASP %s found%s", asp_name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ vty_out(vty, "ASP Name AS Name State Type Role SCTP Role
Local Addresses Remote Addresses%s", VTY_NEWLINE);
+ vty_out(vty, "------------ ------------ ------------- ---- ---- ---------
----------------------- -----------------------%s", VTY_NEWLINE);
+
+ if (asp) {
+ show_one_asp(vty, asp);
+ return CMD_SUCCESS;
+ }
+
+ llist_for_each_entry(asp, &inst->asp_list, list)
+ show_one_asp(vty, asp);
+ return CMD_SUCCESS;
+}
+
+DEFUN(show_cs7_asp, show_cs7_asp_cmd,
+ "show cs7 instance <0-15> asp",
+ SHOW_STR CS7_STR INST_STR INST_STR
+ "Application Server Process (ASP)\n")
+{
+ int id = atoi(argv[0]);
+
+ return show_asp(vty, id, NULL);
+}
+
+DEFUN(show_cs7_asp_name, show_cs7_asp_name_cmd,
+ "show cs7 instance <0-15> asp name ASP_NAME",
+ SHOW_STR CS7_STR INST_STR INST_STR
+ "Application Server Process (ASP)\n"
+ "Lookup ASP with a given name\n"
+ "Name of the Application Server Process (ASP)\n")
+{
+ int id = atoi(argv[0]);
+ const char *asp_name = argv[1];
+
+ return show_asp(vty, id, asp_name);
+}
+
+static void show_one_asp_remaddr_tcp(struct vty *vty, struct osmo_ss7_asp *asp)
+{
+ struct osmo_sockaddr osa = {};
+ struct tcp_info tcpi = {};
+ socklen_t len;
+ int fd, rc;
+
+ fd = ss7_asp_get_fd(asp);
+ if (fd < 0) {
+ vty_out(vty, "%-12s %-46s uninitialized%s", asp->cfg.name, "",
VTY_NEWLINE);
+ return;
+ }
+
+ len = sizeof(osa.u.sas);
+ rc = getpeername(fd, &osa.u.sa, &len);
+
+ len = sizeof(tcpi);
+ rc = getsockopt(fd, SOL_TCP, TCP_INFO, &tcpi, &len);
+ if (rc < 0) {
+ char buf_err[128];
+ strerror_r(errno, buf_err, sizeof(buf_err));
+ vty_out(vty, "%-12s %-46s getsockopt(TCP_INFO) failed: %s%s",
+ asp->cfg.name, osmo_sockaddr_to_str(&osa), buf_err, VTY_NEWLINE);
+ return;
+ }
+
+ vty_out(vty, "%-12s %-46s TCP_%-19s %-8u %-8u %-8u %-8u%s",
+ asp->cfg.name,
+ osmo_sockaddr_to_str(&osa),
+ get_value_string(tcp_info_state_values, tcpi.tcpi_state),
+ tcpi.tcpi_snd_cwnd, tcpi.tcpi_rtt,
+ tcpi.tcpi_rto, tcpi.tcpi_pmtu,
+ VTY_NEWLINE);
+}
+
+#ifdef HAVE_LIBSCTP
+static void show_one_asp_remaddr_sctp(struct vty *vty, struct osmo_ss7_asp *asp)
+{
+ struct sctp_paddrinfo pinfo[OSMO_SOCK_MAX_ADDRS];
+ struct osmo_sockaddr osa = {};
+ size_t pinfo_cnt = ARRAY_SIZE(pinfo);
+ bool more_needed;
+ int fd, rc;
+ unsigned int i;
+
+ fd = ss7_asp_get_fd(asp);
+ if (fd < 0) {
+ vty_out(vty, "%-12s %-46s uninitialized%s", asp->cfg.name, "",
VTY_NEWLINE);
+ return;
+ }
+
+ rc = osmo_sock_sctp_get_peer_addr_info(fd, &pinfo[0], &pinfo_cnt);
+ if (rc < 0) {
+ char buf_err[128];
+ strerror_r(errno, buf_err, sizeof(buf_err));
+ vty_out(vty, "%-12s %-46s getsockopt(SCTP_GET_PEER_ADDR_INFO) failed:
%s%s", asp->cfg.name, "", buf_err, VTY_NEWLINE);
+ return;
+ }
+
+ more_needed = pinfo_cnt > ARRAY_SIZE(pinfo);
+ if (pinfo_cnt > ARRAY_SIZE(pinfo))
+ pinfo_cnt = ARRAY_SIZE(pinfo);
+
+ for (i = 0; i < pinfo_cnt; i++) {
+ osa.u.sas = pinfo[i].spinfo_address;
+ vty_out(vty, "%-12s %-46s SCTP_%-18s %-8u %-8u %-8u %-8u%s",
+ asp->cfg.name,
+ osmo_sockaddr_to_str(&osa),
+ osmo_sctp_spinfo_state_str(pinfo[i].spinfo_state),
+ pinfo[i].spinfo_cwnd, pinfo[i].spinfo_srtt,
+ pinfo[i].spinfo_rto, pinfo[i].spinfo_mtu,
+ VTY_NEWLINE);
+ }
+
+ if (more_needed)
+ vty_out(vty, "%-12s more address buffers needed!%s", asp->cfg.name,
VTY_NEWLINE);
+}
+#endif
+
+static void show_one_asp_remaddr(struct vty *vty, struct osmo_ss7_asp *asp)
+{
+ switch (asp->cfg.trans_proto) {
+ case IPPROTO_TCP:
+ show_one_asp_remaddr_tcp(vty, asp);
+ break;
+#ifdef HAVE_LIBSCTP
+ case IPPROTO_SCTP:
+ show_one_asp_remaddr_sctp(vty, asp);
+ break;
+#endif
+ default:
+ vty_out(vty, "%-12s %-46s unknown proto %d%s",
+ asp->cfg.name, "", asp->cfg.trans_proto, VTY_NEWLINE);
+ break;
+ }
+}
+
+static int show_asp_remaddr(struct vty *vty, int id, const char *asp_name)
+{
+ struct osmo_ss7_instance *inst;
+ struct osmo_ss7_asp *asp = NULL;
+
+ inst = osmo_ss7_instance_find(id);
+ if (!inst) {
+ vty_out(vty, "No SS7 instance %d found%s", id, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (asp_name) {
+ asp = osmo_ss7_asp_find_by_name(inst, asp_name);
+ if (!asp) {
+ vty_out(vty, "No ASP %s found%s", asp_name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ vty_out(vty, "ASP Name Remote IP Address & Port
State CWND SRTT RTO MTU%s", VTY_NEWLINE);
+ vty_out(vty, "------------ ----------------------------------------------
----------------------- -------- -------- -------- --------%s", VTY_NEWLINE);
+
+ if (asp) {
+ show_one_asp_remaddr(vty, asp);
+ return CMD_SUCCESS;
+ }
+
+ llist_for_each_entry(asp, &inst->asp_list, list) {
+ show_one_asp_remaddr(vty, asp);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN(show_cs7_asp_remaddr, show_cs7_asp_remaddr_cmd,
+ "show cs7 instance <0-15> asp-remaddr",
+ SHOW_STR CS7_STR INST_STR INST_STR
+ "Application Server Process (ASP) remote addresses information\n")
+{
+ int id = atoi(argv[0]);
+
+ return show_asp_remaddr(vty, id, NULL);
+}
+
+
+DEFUN(show_cs7_asp_remaddr_name, show_cs7_asp_remaddr_name_cmd,
+ "show cs7 instance <0-15> asp-remaddr name ASP_NAME",
+ SHOW_STR CS7_STR INST_STR INST_STR
+ "Application Server Process (ASP) remote addresses information\n"
+ "Lookup ASP with a given name\n"
+ "Name of the Application Server Process (ASP)\n")
+{
+ int id = atoi(argv[0]);
+ const char *asp_name = argv[1];
+
+ return show_asp_remaddr(vty, id, asp_name);
+}
+
+static void show_one_asp_assoc_status_tcp(struct vty *vty, struct osmo_ss7_asp *asp)
+{
+ struct osmo_sockaddr osa = {};
+ struct tcp_info tcpi = {};
+ socklen_t len;
+ int fd, rc;
+ int rx_pend_bytes = 0;
+
+ fd = ss7_asp_get_fd(asp);
+ if (fd < 0) {
+ vty_out(vty, "%-12s uninitialized%s", asp->cfg.name, VTY_NEWLINE);
+ return;
+ }
+
+ len = sizeof(osa.u.sas);
+ rc = getpeername(fd, &osa.u.sa, &len);
+
+ len = sizeof(tcpi);
+ rc = getsockopt(fd, SOL_TCP, TCP_INFO, &tcpi, &len);
+ if (rc < 0) {
+ char buf_err[128];
+ strerror_r(errno, buf_err, sizeof(buf_err));
+ vty_out(vty, "%-12s getsockopt(TCP_INFO) failed: %s%s",
+ asp->cfg.name, buf_err, VTY_NEWLINE);
+ return;
+ }
+
+ rc = ioctl(fd, FIONREAD, &rx_pend_bytes);
+
+ /* FIXME: RWND: struct tcp_info from linux/tcp.h contains more fields
+ * than the one from netinet/tcp.h we currently use, including
+ * "tcpi_rcv_wnd" which we could use to print RWND here. However,
+ * linux/tcp.h seems to be missing the state defines used in
+ * "tcp_info_state_values", so we cannot use that one instead.
+ */
+
+ vty_out(vty, "%-12s TCP_%-19s %-9s %-10s %-8s %-9u %-7u %-9u
%-46s%s",
+ asp->cfg.name,
+ get_value_string(tcp_info_state_values, tcpi.tcpi_state),
+ "-", "-", "-", tcpi.tcpi_unacked, rx_pend_bytes,
+ tcpi.tcpi_pmtu, osmo_sockaddr_to_str(&osa),
+ VTY_NEWLINE);
+}
+
+#ifdef HAVE_LIBSCTP
+static void show_one_asp_assoc_status_sctp(struct vty *vty, struct osmo_ss7_asp *asp)
+{
+ struct osmo_sockaddr osa = {};
+ struct sctp_status st;
+ socklen_t len;
+ int fd, rc;
+
+ fd = ss7_asp_get_fd(asp);
+ if (fd < 0) {
+ vty_out(vty, "%-12s uninitialized%s", asp->cfg.name, VTY_NEWLINE);
+ return;
+ }
+
+ memset(&st, 0, sizeof(st));
+ len = sizeof(st);
+ rc = getsockopt(fd, IPPROTO_SCTP, SCTP_STATUS, &st, &len);
+ if (rc < 0) {
+ char buf_err[128];
+ strerror_r(errno, buf_err, sizeof(buf_err));
+ vty_out(vty, "%-12s getsockopt(SCTP_STATUS) failed: %s%s", asp->cfg.name,
buf_err, VTY_NEWLINE);
+ return;
+ }
+
+ osa.u.sas = st.sstat_primary.spinfo_address;
+ vty_out(vty, "%-12s SCTP_%-18s %-9u %-10u %-8u %-9u %-7u %-9u
%-46s%s",
+ asp->cfg.name,
+ osmo_sctp_sstat_state_str(st.sstat_state),
+ st.sstat_instrms, st.sstat_outstrms,
+ st.sstat_rwnd, st.sstat_unackdata, st.sstat_penddata,
+ st.sstat_fragmentation_point,
+ osmo_sockaddr_to_str(&osa),
+ VTY_NEWLINE);
+}
+#endif
+
+static void show_one_asp_assoc_status(struct vty *vty, struct osmo_ss7_asp *asp)
+{
+ switch (asp->cfg.trans_proto) {
+ case IPPROTO_TCP:
+ show_one_asp_assoc_status_tcp(vty, asp);
+ break;
+#ifdef HAVE_LIBSCTP
+ case IPPROTO_SCTP:
+ show_one_asp_assoc_status_sctp(vty, asp);
+ break;
+#endif
+ default:
+ vty_out(vty, "%-12s unknown proto %d%s",
+ asp->cfg.name, asp->cfg.trans_proto, VTY_NEWLINE);
+ break;
+ }
+}
+
+static int show_asp_assoc_status(struct vty *vty, int id, const char *asp_name)
+{
+ struct osmo_ss7_instance *inst;
+ struct osmo_ss7_asp *asp = NULL;
+
+ inst = osmo_ss7_instance_find(id);
+ if (!inst) {
+ vty_out(vty, "No SS7 instance %d found%s", id, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (asp_name) {
+ asp = osmo_ss7_asp_find_by_name(inst, asp_name);
+ if (!asp) {
+ vty_out(vty, "No ASP %s found%s", asp_name, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ vty_out(vty, "ASP Name State InStreams OutStreams RWND
UnackData PenData FragPoint Current Primary Remote IP Address & Port%s",
VTY_NEWLINE);
+ vty_out(vty, "------------ ----------------------- --------- ----------
-------- --------- ------- ---------
----------------------------------------------%s", VTY_NEWLINE);
+
+ if (asp) {
+ show_one_asp_assoc_status(vty, asp);
+ return CMD_SUCCESS;
+ }
+
+ llist_for_each_entry(asp, &inst->asp_list, list)
+ show_one_asp_assoc_status(vty, asp);
+ return CMD_SUCCESS;
+}
+
+DEFUN(show_cs7_asp_assoc_status, show_cs7_asp_assoc_status_cmd,
+ "show cs7 instance <0-15> asp-assoc-status",
+ SHOW_STR CS7_STR INST_STR INST_STR
+ "Application Server Process (ASP) SCTP association status\n")
+{
+ int id = atoi(argv[0]);
+
+ return show_asp_assoc_status(vty, id, NULL);
+}
+
+
+DEFUN(show_cs7_asp_assoc_status_name, show_cs7_asp_assoc_status_name_cmd,
+ "show cs7 instance <0-15> asp-assoc-status name ASP_NAME",
+ SHOW_STR CS7_STR INST_STR INST_STR
+ "Application Server Process (ASP) SCTP association information\n"
+ "Lookup ASP with a given name\n"
+ "Name of the Application Server Process (ASP)\n")
+{
+ int id = atoi(argv[0]);
+ const char *asp_name = argv[1];
+
+ return show_asp_assoc_status(vty, id, asp_name);
+}
+
+void ss7_vty_write_one_asp(struct vty *vty, struct osmo_ss7_asp *asp, bool
show_dyn_config)
+{
+ int i;
+ /* skip any dynamically created ASPs (e.g. auto-created at connect time) */
+ if ((asp->dyn_allocated || asp->simple_client_allocated)
+ && !show_dyn_config)
+ return;
+
+ vty_out(vty, " asp %s %u %u %s",
+ asp->cfg.name, asp->cfg.remote.port, asp->cfg.local.port,
+ osmo_ss7_asp_protocol_name(asp->cfg.proto));
+ if (asp->cfg.trans_proto !=
ss7_default_trans_proto_for_asp_proto(asp->cfg.proto))
+ vty_out(vty, " %s", get_value_string(ipproto_vals,
asp->cfg.trans_proto));
+ vty_out(vty, "%s", VTY_NEWLINE);
+ if (asp->cfg.description)
+ vty_out(vty, " description %s%s", asp->cfg.description, VTY_NEWLINE);
+ for (i = 0; i < asp->cfg.local.host_cnt; i++) {
+ if (asp->cfg.local.host[i])
+ vty_out(vty, " local-ip %s%s%s", asp->cfg.local.host[i],
+ asp->cfg.local.idx_primary == i ? " primary" : "",
VTY_NEWLINE);
+ }
+ for (i = 0; i < asp->cfg.remote.host_cnt; i++) {
+ if (asp->cfg.remote.host[i])
+ vty_out(vty, " remote-ip %s%s%s", asp->cfg.remote.host[i],
+ asp->cfg.remote.idx_primary == i ? " primary" : "",
VTY_NEWLINE);
+ }
+ if (asp->cfg.qos_class)
+ vty_out(vty, " qos-class %u%s", asp->cfg.qos_class, VTY_NEWLINE);
+ vty_out(vty, " role %s%s",
osmo_str_tolower(get_value_string(osmo_ss7_asp_role_names, asp->cfg.role)),
+ VTY_NEWLINE);
+ if (asp->cfg.trans_proto == IPPROTO_SCTP)
+ vty_out(vty, " sctp-role %s%s", asp->cfg.is_server ? "server" :
"client", VTY_NEWLINE);
+ else
+ vty_out(vty, " transport-role %s%s", asp->cfg.is_server ?
"server" : "client", VTY_NEWLINE);
+ if (asp->cfg.sctp_init.num_ostreams_present)
+ vty_out(vty, " sctp-param init num-ostreams %u%s",
asp->cfg.sctp_init.num_ostreams_value, VTY_NEWLINE);
+ if (asp->cfg.sctp_init.max_instreams_present)
+ vty_out(vty, " sctp-param init max-instreams %u%s",
asp->cfg.sctp_init.max_instreams_value, VTY_NEWLINE);
+ if (asp->cfg.sctp_init.max_attempts_present)
+ vty_out(vty, " sctp-param init max-attempts %u%s",
asp->cfg.sctp_init.max_attempts_value, VTY_NEWLINE);
+ if (asp->cfg.sctp_init.max_init_timeo_present)
+ vty_out(vty, " sctp-param init timeout %u%s",
asp->cfg.sctp_init.max_init_timeo_value, VTY_NEWLINE);
+ for (i = 0; i < sizeof(uint32_t) * 8; i++) {
+ if (!(asp->cfg.quirks & ((uint32_t) 1 << i)))
+ continue;
+ vty_out(vty, " quirk %s%s", get_value_string(asp_quirk_names, (1 <<
i)), VTY_NEWLINE);
+ }
+ write_asp_timers(vty, " ", asp);
+
+ switch (asp->cfg.adm_state) {
+ case OSMO_SS7_ASP_ADM_S_SHUTDOWN:
+ vty_out(vty, " shutdown%s", VTY_NEWLINE);
+ break;
+ case OSMO_SS7_ASP_ADM_S_BLOCKED:
+ vty_out(vty, " blocked%s", VTY_NEWLINE);
+ break;
+ case OSMO_SS7_ASP_ADM_S_ENABLED:
+ /* Default, no need to print: */
+ vty_out(vty, " no shutdown%s", VTY_NEWLINE);
+ break;
+ }
+}
+
+int ss7_vty_node_asp_go_parent(struct vty *vty)
+{
+ struct osmo_ss7_asp *asp = vty->index;
+
+ if (asp->cfg.explicit_shutdown_state_by_vty_since_node_enter) {
+ /* Interactive VTY, inform of new behavior upon use of new '[no] shutdown'
commands: */
+ if (vty->type != VTY_FILE)
+ vty_out(vty, "%% NOTE: Skipping automatic restart of ASP since an explicit
'[no] shutdown' command was entered%s", VTY_NEWLINE);
+ asp->cfg.explicit_shutdown_state_by_vty_since_node_enter = false;
+ } else if (vty->type == VTY_FILE) {
+ /* Make sure config reading is backward compatible by starting the ASP if no explicit
'no shutdown' is read: */
+ vty_out(vty,
+ "%% VTY node 'asp' without a '[no] shutdown' command at the end
is deprecated, "
+ "please make sure you update your cfg file for future compatibility.%s",
+ VTY_NEWLINE);
+ ss7_asp_restart_after_reconfigure(asp);
+ } else {
+ /* Interactive VTY without '[no] shutdown' explicit cmd, remind the user that
we are no
+ * longer automatically restarting the ASP when going out of the "asp" node:
*/
+ vty_out(vty,
+ "%% NOTE: Make sure to use '[no] shutdown' command in 'asp' node
"
+ "in order to restart the ASP for new configs to be applied.%s",
+ VTY_NEWLINE);
+ }
+ vty->node = L_CS7_NODE;
+ vty->index = asp->inst;
+ return 0;
+}
+
+void ss7_vty_init_node_asp(void)
+{
+ asp_quirk_cmd.string = vty_cmd_string_from_valstr(g_ctx, asp_quirk_names,
+ "quirk (", "|", ")", VTY_DO_LOWER);
+ asp_quirk_cmd.doc = vty_cmd_string_from_valstr(g_ctx, asp_quirk_descs,
+ "Enable quirk to work around interop issues\n",
+ "\n", "\n", 0);
+ asp_no_quirk_cmd.string = vty_cmd_string_from_valstr(g_ctx, asp_quirk_names,
+ "no quirk (", "|", ")", VTY_DO_LOWER);
+ asp_no_quirk_cmd.doc = vty_cmd_string_from_valstr(g_ctx, asp_quirk_descs,
+ NO_STR "Disable quirk to work around interop issues\n",
+ "\n", "\n", 0);
+
+ install_node(&asp_node, NULL);
+ install_lib_element_ve(&show_cs7_asp_cmd);
+ install_lib_element_ve(&show_cs7_asp_name_cmd);
+ install_lib_element_ve(&show_cs7_asp_remaddr_cmd);
+ install_lib_element_ve(&show_cs7_asp_remaddr_name_cmd);
+ install_lib_element_ve(&show_cs7_asp_assoc_status_cmd);
+ install_lib_element_ve(&show_cs7_asp_assoc_status_name_cmd);
+ install_lib_element(L_CS7_NODE, &cs7_asp_cmd);
+ install_lib_element(L_CS7_NODE, &cs7_asp_trans_proto_cmd);
+ install_lib_element(L_CS7_NODE, &no_cs7_asp_cmd);
+ install_lib_element(L_CS7_ASP_NODE, &cfg_description_cmd);
+ install_lib_element(L_CS7_ASP_NODE, &asp_remote_ip_cmd);
+ install_lib_element(L_CS7_ASP_NODE, &asp_no_remote_ip_cmd);
+ install_lib_element(L_CS7_ASP_NODE, &asp_local_ip_cmd);
+ install_lib_element(L_CS7_ASP_NODE, &asp_no_local_ip_cmd);
+ install_lib_element(L_CS7_ASP_NODE, &asp_qos_class_cmd);
+ install_lib_element(L_CS7_ASP_NODE, &asp_role_cmd);
+ install_lib_element(L_CS7_ASP_NODE, &asp_transport_role_cmd);
+ install_lib_element(L_CS7_ASP_NODE, &asp_sctp_role_cmd);
+ install_lib_element(L_CS7_ASP_NODE, &asp_sctp_param_init_cmd);
+ install_lib_element(L_CS7_ASP_NODE, &asp_no_sctp_param_init_cmd);
+ install_lib_element(L_CS7_ASP_NODE, &asp_quirk_cmd);
+ install_lib_element(L_CS7_ASP_NODE, &asp_no_quirk_cmd);
+ gen_asp_timer_cmd_strs(&asp_timer_cmd);
+ install_lib_element(L_CS7_ASP_NODE, &asp_timer_cmd);
+ install_lib_element(L_CS7_ASP_NODE, &asp_block_cmd);
+ install_lib_element(L_CS7_ASP_NODE, &asp_shutdown_cmd);
+ install_lib_element(L_CS7_ASP_NODE, &asp_no_shutdown_cmd);
+}
diff --git a/src/ss7_internal.h b/src/ss7_internal.h
index 9475645..7dc2c57 100644
--- a/src/ss7_internal.h
+++ b/src/ss7_internal.h
@@ -28,3 +28,6 @@
int ss7_asp_xua_srv_conn_closed_cb(struct osmo_stream_srv *srv);
int xua_tcp_segmentation_cb(struct msgb *msg);
+
+/* VTY */
+#define XUA_VAR_STR "(sua|m3ua|ipa)"
diff --git a/src/ss7_vty.c b/src/ss7_vty.c
index 41872fe..862e9ff 100644
--- a/src/ss7_vty.c
+++ b/src/ss7_vty.c
@@ -1,4 +1,4 @@
-/* Core SS7 Instance/Linkset/Link/AS/ASP VTY Interface */
+/* Core SS7 Instance/Linkset/Link VTY Interface */
/* (C) 2015-2021 by Harald Welte <laforge(a)gnumonks.org>
* All Rights Reserved
@@ -26,20 +26,12 @@
#include <stdint.h>
#include <string.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#include <sys/ioctl.h>
-
-#include <osmocom/core/sockaddr_str.h>
-
#include <osmocom/vty/vty.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/misc.h>
-#include <osmocom/netif/stream.h>
-
#include <osmocom/sigtran/osmo_ss7.h>
#include <osmocom/sigtran/protocol/mtp.h>
@@ -53,34 +45,9 @@
#include "ss7_route.h"
#include "ss7_route_table.h"
#include "ss7_internal.h"
+#include "ss7_vty.h"
#include "ss7_xua_srv.h"
-#include <netinet/tcp.h>
-
-#ifdef HAVE_LIBSCTP
-#include <netinet/sctp.h>
-#include <osmocom/netif/sctp.h>
-#endif
-
-#define XUA_VAR_STR "(sua|m3ua|ipa)"
-
-#define XUA_VAR_HELP_STR \
- "SCCP User Adaptation\n" \
- "MTP3 User Adaptation\n" \
- "IPA Multiplex (SCCP Lite)\n"
-
-#define IPPROTO_VAR_STR "(sctp|tcp)"
-#define IPPROTO_VAR_HELP_STR \
- "SCTP (Stream Control Transmission Protocol)\n" \
- "TCP (Transmission Control Protocol)\n"
-
-#define QOS_CLASS_RANGE_STR "<0-7>"
-#define QOS_CLASS_RANGE_HELP_STR "QoS Class\n"
-#define QOS_CLASS_VAR_STR "(" QOS_CLASS_RANGE_STR "|default)"
-#define QOS_CLASS_VAR_HELP_STR \
- QOS_CLASS_RANGE_HELP_STR \
- "Default QoS Class (0)\n"
-
#define ROUTE_PRIO_RANGE_STR "<1-9>"
#define ROUTE_PRIO_RANGE_HELP_STR "Priority\n"
#define ROUTE_PRIO_VAR_STR "(" ROUTE_PRIO_RANGE_STR "|default)"
@@ -88,43 +55,28 @@
ROUTE_PRIO_RANGE_HELP_STR \
"Default Priority (5)\n"
-/* netinet/tcp.h */
-static const struct value_string tcp_info_state_values[] = {
- { TCP_ESTABLISHED, "ESTABLISHED" },
- { TCP_SYN_SENT, "SYN_SENT" },
- { TCP_SYN_RECV, "SYN_RECV" },
- { TCP_FIN_WAIT1, "FIN_WAIT1" },
- { TCP_FIN_WAIT2, "FIN_WAIT2" },
- { TCP_TIME_WAIT, "TIME_WAIT" },
- { TCP_CLOSE, "CLOSE" },
- { TCP_CLOSE_WAIT, "CLOSE_WAIT" },
- { TCP_LAST_ACK, "LAST_ACK" },
- { TCP_LISTEN, "LISTEN" },
- { TCP_CLOSING, "CLOSING" },
- {}
+const struct value_string ipproto_vals[] = {
+ { IPPROTO_SCTP, "sctp" },
+ { IPPROTO_TCP, "tcp" },
+ { 0, NULL },
};
-static const struct value_string asp_quirk_names[] = {
- { OSMO_SS7_ASP_QUIRK_NO_NOTIFY, "no_notify" },
- { OSMO_SS7_ASP_QUIRK_DAUD_IN_ASP, "daud_in_asp" },
- { OSMO_SS7_ASP_QUIRK_SNM_INACTIVE, "snm_inactive" },
- { 0, NULL }
-};
+int parse_trans_proto(const char *protocol)
+{
+ return get_string_value(ipproto_vals, protocol);
+}
-static const struct value_string asp_quirk_descs[] = {
- { OSMO_SS7_ASP_QUIRK_NO_NOTIFY, "Peer SG doesn't send NTFY(AS-INACTIVE) after
ASP-UP" },
- { OSMO_SS7_ASP_QUIRK_DAUD_IN_ASP, "Allow Rx of DAUD in ASP role" },
- { OSMO_SS7_ASP_QUIRK_SNM_INACTIVE, "Allow Rx of [S]SNM in AS-INACTIVE state"
},
- { 0, NULL }
-};
+enum osmo_ss7_asp_protocol parse_asp_proto(const char *protocol)
+{
+ return get_string_value(osmo_ss7_asp_protocol_vals, protocol);
+}
/***********************************************************************
* Core CS7 Configuration
***********************************************************************/
-enum cs7_role_t {CS7_ROLE_SG, CS7_ROLE_ASP};
-static enum cs7_role_t cs7_role;
-static void *g_ctx;
+enum cs7_role_t cs7_role;
+void *g_ctx;
static struct cmd_node cs7_node = {
L_CS7_NODE,
@@ -737,293 +689,6 @@
return CMD_SUCCESS;
}
-/***********************************************************************
- * xUA Listener Configuration (SG)
- ***********************************************************************/
-
-static const struct value_string ipproto_vals[] = {
- { IPPROTO_SCTP, "sctp" },
- { IPPROTO_TCP, "tcp" },
- { 0, NULL },
-};
-
-static int parse_trans_proto(const char *protocol)
-{
- return get_string_value(ipproto_vals, protocol);
-}
-
-static enum osmo_ss7_asp_protocol parse_asp_proto(const char *protocol)
-{
- return get_string_value(osmo_ss7_asp_protocol_vals, protocol);
-}
-
-static struct cmd_node xua_node = {
- L_CS7_XUA_NODE,
- "%s(config-cs7-listen)# ",
- 1,
-};
-
-DEFUN_ATTR(cs7_xua, cs7_xua_cmd,
- "listen " XUA_VAR_STR " <0-65534> [" IPPROTO_VAR_STR
"]",
- "Configure/Enable xUA Listener\n"
- XUA_VAR_HELP_STR
- "Port number\n"
- IPPROTO_VAR_HELP_STR,
- CMD_ATTR_IMMEDIATE)
-{
- struct osmo_ss7_instance *inst = vty->index;
- struct osmo_xua_server *xs;
- enum osmo_ss7_asp_protocol proto = parse_asp_proto(argv[0]);
- uint16_t port = atoi(argv[1]);
- int trans_proto;
-
- if (argc > 2)
- trans_proto = parse_trans_proto(argv[2]);
- else /* default transport protocol */
- trans_proto = ss7_default_trans_proto_for_asp_proto(proto);
- if (trans_proto < 0)
- return CMD_WARNING;
-
- xs = ss7_xua_server_find2(inst, trans_proto, proto, port);
- if (!xs) {
- xs = ss7_xua_server_create2(inst, trans_proto, proto, port, NULL);
- if (!xs)
- return CMD_WARNING;
- /* Drop first dummy address created automatically by _create(): */
- ss7_xua_server_set_local_hosts(xs, NULL, 0);
- }
-
- vty->node = L_CS7_XUA_NODE;
- vty->index = xs;
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(no_cs7_xua, no_cs7_xua_cmd,
- "no listen " XUA_VAR_STR " <0-65534> [" IPPROTO_VAR_STR
"]",
- NO_STR "Disable xUA Listener on given port\n"
- XUA_VAR_HELP_STR
- "Port number\n"
- IPPROTO_VAR_HELP_STR,
- CMD_ATTR_IMMEDIATE)
-{
- struct osmo_ss7_instance *inst = vty->index;
- struct osmo_xua_server *xs;
- enum osmo_ss7_asp_protocol proto = parse_asp_proto(argv[0]);
- uint16_t port = atoi(argv[1]);
- int trans_proto;
-
- if (argc > 2)
- trans_proto = parse_trans_proto(argv[2]);
- else /* default transport protocol */
- trans_proto = ss7_default_trans_proto_for_asp_proto(proto);
- if (trans_proto < 0)
- return CMD_WARNING;
-
- xs = ss7_xua_server_find2(inst, trans_proto, proto, port);
- if (!xs) {
- vty_out(vty, "No xUA server for port %u found%s", port, VTY_NEWLINE);
- return CMD_WARNING;
- }
- ss7_xua_server_destroy(xs);
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(xua_local_ip, xua_local_ip_cmd,
- "local-ip " VTY_IPV46_CMD,
- "Configure the Local IP Address for xUA\n"
- "IPv4 Address to use for XUA\n"
- "IPv6 Address to use for XUA\n",
- CMD_ATTR_IMMEDIATE)
-{
- struct osmo_xua_server *xs = vty->index;
-
- ss7_xua_server_add_local_host(xs, argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(xua_no_local_ip, xua_no_local_ip_cmd,
- "no local-ip " VTY_IPV46_CMD,
- NO_STR "Configure the Local IP Address for xUA\n"
- "IPv4 Address to use for XUA\n"
- "IPv6 Address to use for XUA\n",
- CMD_ATTR_NODE_EXIT)
-{
- struct osmo_xua_server *xs = vty->index;
-
- if (ss7_xua_server_del_local_host(xs, argv[0]) != 0) {
- vty_out(vty, "%% Failed deleting local address '%s' from set%s",
argv[0], VTY_NEWLINE);
- return CMD_WARNING;
- }
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(xua_accept_dyn_asp, xua_accept_dyn_asp_cmd,
- "accept-asp-connections (pre-configured|dynamic-permitted)",
- "Define what kind of ASP connections to accept\n"
- "Accept only pre-configured ASPs (source IP/port)\n"
- "Accept any connection and dynamically create an ASP definition\n",
- CMD_ATTR_IMMEDIATE)
-{
- struct osmo_xua_server *xs = vty->index;
-
- if (!strcmp(argv[0], "dynamic-permitted"))
- xs->cfg.accept_dyn_reg = true;
- else
- xs->cfg.accept_dyn_reg = false;
-
- return CMD_SUCCESS;
-}
-
-#define XUA_SRV_SCTP_PARAM_INIT_DESC \
- "Configure SCTP parameters\n" \
- "Configure INIT related parameters\n" \
- "Configure INIT Number of Outbound Streams\n" \
- "Configure INIT Maximum Inboud Streams\n"
-#define XUA_SRV_SCTP_PARAM_INIT_FIELDS "(num-ostreams|max-instreams)"
-
-DEFUN_ATTR(xua_sctp_param_init, xua_sctp_param_init_cmd,
- "sctp-param init " XUA_SRV_SCTP_PARAM_INIT_FIELDS "
<0-65535>",
- XUA_SRV_SCTP_PARAM_INIT_DESC
- "Value of the parameter\n",
- CMD_ATTR_NODE_EXIT)
-{
- struct osmo_xua_server *xs = vty->index;
-
- uint16_t val = atoi(argv[1]);
-
- if (strcmp(argv[0], "num-ostreams") == 0) {
- xs->cfg.sctp_init.num_ostreams_present = true;
- xs->cfg.sctp_init.num_ostreams_value = val;
- } else if (strcmp(argv[0], "max-instreams") == 0) {
- xs->cfg.sctp_init.max_instreams_present = true;
- xs->cfg.sctp_init.max_instreams_value = val;
- } else {
- OSMO_ASSERT(0);
- }
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(xua_no_sctp_param_init, xua_no_sctp_param_init_cmd,
- "no sctp-param init " XUA_SRV_SCTP_PARAM_INIT_FIELDS,
- NO_STR XUA_SRV_SCTP_PARAM_INIT_DESC,
- CMD_ATTR_NODE_EXIT)
-{
- struct osmo_xua_server *xs = vty->index;
-
- if (strcmp(argv[0], "num-ostreams") == 0)
- xs->cfg.sctp_init.num_ostreams_present = false;
- else if (strcmp(argv[0], "max-instreams") == 0)
- xs->cfg.sctp_init.max_instreams_present = false;
- else
- OSMO_ASSERT(0);
- return CMD_SUCCESS;
-}
-
-static void write_one_xua(struct vty *vty, struct osmo_xua_server *xs)
-{
- int i;
-
- vty_out(vty, " listen %s %u",
- get_value_string(osmo_ss7_asp_protocol_vals, xs->cfg.proto),
- xs->cfg.local.port);
- if (xs->cfg.trans_proto != ss7_default_trans_proto_for_asp_proto(xs->cfg.proto))
- vty_out(vty, " %s", get_value_string(ipproto_vals, xs->cfg.trans_proto));
- vty_out(vty, "%s", VTY_NEWLINE);
-
- for (i = 0; i < xs->cfg.local.host_cnt; i++) {
- if (xs->cfg.local.host[i])
- vty_out(vty, " local-ip %s%s", xs->cfg.local.host[i], VTY_NEWLINE);
- }
- if (xs->cfg.accept_dyn_reg)
- vty_out(vty, " accept-asp-connections dynamic-permitted%s", VTY_NEWLINE);
- if (xs->cfg.sctp_init.num_ostreams_present)
- vty_out(vty, " sctp-param init num-ostreams %u%s",
xs->cfg.sctp_init.num_ostreams_value, VTY_NEWLINE);
- if (xs->cfg.sctp_init.max_instreams_present)
- vty_out(vty, " sctp-param init max-instreams %u%s",
xs->cfg.sctp_init.max_instreams_value, VTY_NEWLINE);
-}
-
-static void vty_dump_xua_server(struct vty *vty, struct osmo_xua_server *xs)
-{
- char buf[OSMO_SOCK_MULTIADDR_PEER_STR_MAXLEN];
- const char *proto = get_value_string(osmo_ss7_asp_protocol_vals, xs->cfg.proto);
- int fd = xs->server ? osmo_stream_srv_link_get_fd(xs->server) : -1;
-
- if (fd < 0) {
- if (ss7_asp_peer_snprintf(buf, sizeof(buf), &xs->cfg.local) < 0)
- snprintf(buf, sizeof(buf), "<error>");
- } else {
- char hostbuf[OSMO_SOCK_MAX_ADDRS][INET6_ADDRSTRLEN];
- size_t num_hostbuf = ARRAY_SIZE(hostbuf);
- char portbuf[6];
- int rc;
- rc = osmo_sock_multiaddr_get_ip_and_port(fd, xs->cfg.trans_proto,
- &hostbuf[0][0], &num_hostbuf, sizeof(hostbuf[0]),
- portbuf, sizeof(portbuf), true);
- if (rc < 0) {
- snprintf(buf, sizeof(buf), "<error>");
- } else {
- if (num_hostbuf > ARRAY_SIZE(hostbuf))
- num_hostbuf = ARRAY_SIZE(hostbuf);
- osmo_multiaddr_ip_and_port_snprintf(buf, sizeof(buf),
- &hostbuf[0][0], num_hostbuf, sizeof(hostbuf[0]),
- portbuf);
- }
- }
- vty_out(vty, "xUA server for %s/%s on %s is %s%s",
- proto, get_value_string(ipproto_vals, xs->cfg.trans_proto),
- buf, fd >= 0 ? "listening" : "inactive", VTY_NEWLINE);
-}
-
-static int _show_cs7_xua(struct vty *vty,
- enum osmo_ss7_asp_protocol proto,
- int trans_proto, int local_port)
-{
- const struct osmo_ss7_instance *inst;
-
- llist_for_each_entry(inst, &osmo_ss7_instances, list) {
- struct osmo_xua_server *xs;
-
- llist_for_each_entry(xs, &inst->xua_servers, list) {
- if (xs->cfg.proto != proto)
- continue;
- if (local_port >= 0 && xs->cfg.local.port != local_port) /* optional */
- continue;
- if (trans_proto >= 0 && xs->cfg.trans_proto != trans_proto) /* optional
*/
- continue;
- vty_dump_xua_server(vty, xs);
- }
- }
-
- return CMD_SUCCESS;
-}
-
-#define SHOW_CS7_XUA_CMD \
- "show cs7 " XUA_VAR_STR
-#define SHOW_CS7_XUA_CMD_HELP \
- SHOW_STR CS7_STR XUA_VAR_HELP_STR
-
-DEFUN(show_cs7_xua, show_cs7_xua_cmd,
- SHOW_CS7_XUA_CMD " [<0-65534>]",
- SHOW_CS7_XUA_CMD_HELP "Local Port Number\n")
-{
- enum osmo_ss7_asp_protocol proto = parse_asp_proto(argv[0]);
- int local_port = (argc > 1) ? atoi(argv[1]) : -1;
-
- return _show_cs7_xua(vty, proto, -1, local_port);
-}
-
-DEFUN(show_cs7_xua_trans_proto, show_cs7_xua_trans_proto_cmd,
- SHOW_CS7_XUA_CMD " " IPPROTO_VAR_STR " [<0-65534>]",
- SHOW_CS7_XUA_CMD_HELP IPPROTO_VAR_HELP_STR "Local Port Number\n")
-{
- enum osmo_ss7_asp_protocol proto = parse_asp_proto(argv[0]);
- int trans_proto = parse_trans_proto(argv[1]);
- int local_port = (argc > 2) ? atoi(argv[2]) : -1;
-
- return _show_cs7_xua(vty, proto, trans_proto, local_port);
-}
-
DEFUN(show_cs7_config, show_cs7_config_cmd,
"show cs7 config",
SHOW_STR CS7_STR "Currently running cs7 configuration")
@@ -1059,1556 +724,6 @@
/***********************************************************************
- * Application Server Process
- ***********************************************************************/
-
-static struct cmd_node asp_node = {
- L_CS7_ASP_NODE,
- "%s(config-cs7-asp)# ",
- 1,
-};
-
-DEFUN_ATTR(cs7_asp, cs7_asp_cmd,
- "asp NAME <0-65535> <0-65535> " XUA_VAR_STR,
- "Configure Application Server Process\n"
- "Name of ASP\n"
- "Remote port number\n"
- "Local port number\n"
- XUA_VAR_HELP_STR,
- CMD_ATTR_NODE_EXIT)
-{
- struct osmo_ss7_instance *inst = vty->index;
- const char *name = argv[0];
- uint16_t remote_port = atoi(argv[1]);
- uint16_t local_port = atoi(argv[2]);
- enum osmo_ss7_asp_protocol proto = parse_asp_proto(argv[3]);
- struct osmo_ss7_asp *asp;
- int trans_proto;
-
- if (proto == OSMO_SS7_ASP_PROT_NONE) {
- vty_out(vty, "invalid protocol '%s'%s", argv[3], VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- /* argv[4] can be supplied by an alias (see below) */
- if (argc > 4)
- trans_proto = parse_trans_proto(argv[4]);
- else /* default transport protocol */
- trans_proto = ss7_default_trans_proto_for_asp_proto(proto);
- if (trans_proto < 0)
- return CMD_WARNING;
-
- asp = osmo_ss7_asp_find2(inst, name,
- remote_port, local_port,
- trans_proto, proto);
- if (!asp) {
- asp = osmo_ss7_asp_find_or_create2(inst, name,
- remote_port, local_port,
- trans_proto, proto);
- if (!asp) {
- vty_out(vty, "cannot create ASP '%s'%s", name, VTY_NEWLINE);
- return CMD_WARNING;
- }
- asp->cfg.is_server = true;
- asp->cfg.role = OSMO_SS7_ASP_ROLE_SG;
- }
-
- /* Reset value, will be checked at osmo_ss7_vty_go_parent() */
- asp->cfg.explicit_shutdown_state_by_vty_since_node_enter = false;
-
- vty->node = L_CS7_ASP_NODE;
- vty->index = asp;
- vty->index_sub = &asp->cfg.description;
- return CMD_SUCCESS;
-}
-
-/* XXX: workaround for
https://osmocom.org/issues/6360, can be removed once it's
fixed.
- * Currently we hit an assert if we make the IPPROTO_VAR_STR optional in cs7_asp_cmd. */
-ALIAS_ATTR(cs7_asp, cs7_asp_trans_proto_cmd,
- "asp NAME <0-65535> <0-65535> " XUA_VAR_STR " "
IPPROTO_VAR_STR,
- "Configure Application Server Process\n"
- "Name of ASP\n"
- "Remote port number\n"
- "Local port number\n"
- XUA_VAR_HELP_STR
- IPPROTO_VAR_HELP_STR,
- CMD_ATTR_NODE_EXIT);
-
-DEFUN_ATTR(no_cs7_asp, no_cs7_asp_cmd,
- "no asp NAME",
- NO_STR "Disable Application Server Process\n"
- "Name of ASP\n",
- CMD_ATTR_IMMEDIATE)
-{
- struct osmo_ss7_instance *inst = vty->index;
- const char *name = argv[0];
- struct osmo_ss7_asp *asp;
-
- asp = osmo_ss7_asp_find_by_name(inst, name);
- if (!asp) {
- vty_out(vty, "No ASP named '%s' found%s", name, VTY_NEWLINE);
- return CMD_WARNING;
- }
- osmo_ss7_asp_destroy(asp);
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(asp_local_ip, asp_local_ip_cmd,
- "local-ip " VTY_IPV46_CMD " [primary]",
- "Specify Local IP Address from which to contact ASP\n"
- "Local IPv4 Address from which to contact of ASP\n"
- "Local IPv6 Address from which to contact of ASP\n"
- "Signal the SCTP peer to use this address as Primary Address\n",
- CMD_ATTR_NODE_EXIT)
-{
- struct osmo_ss7_asp *asp = vty->index;
- bool is_primary = argc > 1;
- int old_idx_primary = asp->cfg.local.idx_primary;
- int old_host_count = asp->cfg.local.host_cnt;
- int rc;
-
- if (ss7_asp_peer_add_host2(&asp->cfg.local, asp, argv[0], is_primary) != 0) {
- vty_out(vty, "%% Failed adding host '%s' to set%s", argv[0],
VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (!ss7_asp_is_started(asp))
- return CMD_SUCCESS;
- if (asp->cfg.proto == OSMO_SS7_ASP_PROT_IPA)
- return CMD_SUCCESS;
- /* The SCTP socket is already created. */
-
- /* dynamically apply the new address if it was added to the set: */
- if (asp->cfg.local.host_cnt > old_host_count) {
- if ((rc = ss7_asp_apply_new_local_address(asp, asp->cfg.local.host_cnt - 1)) < 0)
{
- /* Failed, rollback changes: */
- TALLOC_FREE(asp->cfg.local.host[asp->cfg.local.host_cnt - 1]);
- asp->cfg.local.host_cnt--;
- vty_out(vty, "%% Failed adding new local address '%s'%s", argv[0],
VTY_NEWLINE);
- return CMD_WARNING;
- }
- vty_out(vty, "%% Local address '%s' added to the active socket bind
set%s", argv[0], VTY_NEWLINE);
- }
-
- /* dynamically apply the new primary if it changed: */
- if (is_primary && asp->cfg.local.idx_primary != old_idx_primary) {
- if ((rc = ss7_asp_apply_peer_primary_address(asp)) < 0) {
- /* Failed, rollback changes: */
- asp->cfg.local.idx_primary = old_idx_primary;
- vty_out(vty, "%% Failed announcing primary '%s' to peer%s", argv[0],
VTY_NEWLINE);
- return CMD_WARNING;
- }
- vty_out(vty, "%% Local address '%s' announced as primary to the peer on
the active socket%s", argv[0], VTY_NEWLINE);
- }
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(asp_no_local_ip, asp_no_local_ip_cmd,
- "no local-ip " VTY_IPV46_CMD,
- NO_STR "Specify Local IP Address from which to contact ASP\n"
- "Local IPv4 Address from which to contact of ASP\n"
- "Local IPv6 Address from which to contact of ASP\n",
- CMD_ATTR_NODE_EXIT)
-{
- struct osmo_ss7_asp *asp = vty->index;
- int idx = ss7_asp_peer_find_host(&asp->cfg.local, argv[0]);
- int rc;
-
- if (idx < 0) {
- vty_out(vty, "%% Local address '%s' not found in set%s", argv[0],
VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (ss7_asp_is_started(asp)) {
- if (asp->cfg.proto != OSMO_SS7_ASP_PROT_IPA) {
- if ((rc = ss7_asp_apply_drop_local_address(asp, idx)) < 0) {
- vty_out(vty, "%% Failed removing local address '%s' from existing
socket%s", argv[0], VTY_NEWLINE);
- return CMD_WARNING;
- }
- vty_out(vty, "%% Local address '%s' removed from active socket
connection%s", argv[0], VTY_NEWLINE);
- }
- }
-
- if (ss7_asp_peer_del_host(&asp->cfg.local, argv[0]) != 0) {
- vty_out(vty, "%% Failed deleting local address '%s' from set%s",
argv[0], VTY_NEWLINE);
- return CMD_WARNING;
- }
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(asp_remote_ip, asp_remote_ip_cmd,
- "remote-ip " VTY_IPV46_CMD " [primary]",
- "Specify Remote IP Address of ASP\n"
- "Remote IPv4 Address of ASP\n"
- "Remote IPv6 Address of ASP\n"
- "Set remote address as SCTP Primary Address\n",
- CMD_ATTR_NODE_EXIT)
-{
- struct osmo_ss7_asp *asp = vty->index;
- bool is_primary = argc > 1;
- int old_idx_primary = asp->cfg.remote.idx_primary;
- int rc;
-
- if (ss7_asp_peer_add_host2(&asp->cfg.remote, asp, argv[0], is_primary) != 0) {
- vty_out(vty, "%% Failed adding host '%s' to set%s", argv[0],
VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (!ss7_asp_is_started(asp))
- return CMD_SUCCESS;
- if (asp->cfg.proto == OSMO_SS7_ASP_PROT_IPA)
- return CMD_SUCCESS;
-
- /* The SCTP socket is already created, dynamically apply the new primary if it changed:
*/
- if (asp->cfg.proto != OSMO_SS7_ASP_PROT_IPA && ss7_asp_is_started(asp)) {
- if ((rc = ss7_asp_apply_primary_address(asp)) < 0) {
- /* Failed, rollback changes: */
- asp->cfg.remote.idx_primary = old_idx_primary;
- vty_out(vty, "%% Failed applying primary on host '%s'%s", argv[0],
VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(asp_no_remote_ip, asp_no_remote_ip_cmd,
- "no remote-ip " VTY_IPV46_CMD,
- NO_STR "Specify Remote IP Address of ASP\n"
- "Remote IPv4 Address of ASP\n"
- "Remote IPv6 Address of ASP\n",
- CMD_ATTR_NODE_EXIT)
-{
- struct osmo_ss7_asp *asp = vty->index;
- int idx = ss7_asp_peer_find_host(&asp->cfg.remote, argv[0]);
-
- if (idx < 0) {
- vty_out(vty, "%% Remote address '%s' not found in set%s", argv[0],
VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (ss7_asp_peer_del_host(&asp->cfg.remote, argv[0]) != 0) {
- vty_out(vty, "%% Failed deleting remote address '%s' from set%s",
argv[0], VTY_NEWLINE);
- return CMD_WARNING;
- }
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(asp_qos_clas, asp_qos_class_cmd,
- "qos-class " QOS_CLASS_RANGE_STR,
- "Specify QoS Class of ASP\n"
- QOS_CLASS_RANGE_HELP_STR,
- CMD_ATTR_NODE_EXIT)
-{
- struct osmo_ss7_asp *asp = vty->index;
- asp->cfg.qos_class = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(asp_role, asp_role_cmd,
- "role (sg|asp|ipsp)",
- "Specify the xUA role for this ASP\n"
- "SG (Signaling Gateway)\n"
- "ASP (Application Server Process)\n"
- "IPSP (IP Signalling Point)\n",
- CMD_ATTR_NODE_EXIT)
-{
- struct osmo_ss7_asp *asp = vty->index;
-
- if (!strcmp(argv[0], "sg")) {
- asp->cfg.role = OSMO_SS7_ASP_ROLE_SG;
- } else if (!strcmp(argv[0], "asp")) {
- asp->cfg.role = OSMO_SS7_ASP_ROLE_ASP;
- } else if (!strcmp(argv[0], "ipsp")) {
- vty_out(vty, "IPSP role isn't supported yet%s", VTY_NEWLINE);
- return CMD_WARNING;
- } else
- OSMO_ASSERT(0);
-
- asp->cfg.role_set_by_vty = true;
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(asp_transport_role, asp_transport_role_cmd,
- "transport-role (client|server)",
- "Specify the transport layer role for this ASP\n"
- "Operate as a client; connect to a server\n"
- "Operate as a server; wait for client connections\n",
- CMD_ATTR_NODE_EXIT)
-{
- struct osmo_ss7_asp *asp = vty->index;
-
- if (!strcmp(argv[0], "client"))
- asp->cfg.is_server = false;
- else if (!strcmp(argv[0], "server"))
- asp->cfg.is_server = true;
- else
- OSMO_ASSERT(0);
-
- asp->cfg.trans_role_set_by_vty = true;
- return CMD_SUCCESS;
-}
-
-ALIAS_ATTR(asp_transport_role, asp_sctp_role_cmd,
- "sctp-role (client|server)",
- "Specify the SCTP role for this ASP\n"
- "Operate as SCTP client; connect to a server\n"
- "Operate as SCTP server; wait for client connections\n",
- CMD_ATTR_HIDDEN | CMD_ATTR_NODE_EXIT);
-
-#define ASP_SCTP_PARAM_INIT_DESC \
- "Configure SCTP parameters\n" \
- "Configure INIT related parameters\n" \
- "Configure INIT Number of Outbound Streams\n" \
- "Configure INIT Maximum Inboud Streams\n" \
- "Configure INIT Maximum Attempts\n" \
- "Configure INIT Timeout (milliseconds)\n"
-#define ASP_SCTP_PARAM_INIT_FIELDS
"(num-ostreams|max-instreams|max-attempts|timeout)"
-
-DEFUN_ATTR(asp_sctp_param_init, asp_sctp_param_init_cmd,
- "sctp-param init " ASP_SCTP_PARAM_INIT_FIELDS "
<0-65535>",
- ASP_SCTP_PARAM_INIT_DESC
- "Value of the parameter\n",
- CMD_ATTR_NODE_EXIT)
-{
- struct osmo_ss7_asp *asp = vty->index;
-
- uint16_t val = atoi(argv[1]);
-
- if (strcmp(argv[0], "num-ostreams") == 0) {
- asp->cfg.sctp_init.num_ostreams_present = true;
- asp->cfg.sctp_init.num_ostreams_value = val;
- } else if (strcmp(argv[0], "max-instreams") == 0) {
- asp->cfg.sctp_init.max_instreams_present = true;
- asp->cfg.sctp_init.max_instreams_value = val;
- } else if (strcmp(argv[0], "max-attempts") == 0) {
- asp->cfg.sctp_init.max_attempts_present = true;
- asp->cfg.sctp_init.max_attempts_value = val;
- } else if (strcmp(argv[0], "timeout") == 0) {
- asp->cfg.sctp_init.max_init_timeo_present = true;
- asp->cfg.sctp_init.max_init_timeo_value = val;
- } else {
- OSMO_ASSERT(0);
- }
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(asp_no_sctp_param_init, asp_no_sctp_param_init_cmd,
- "no sctp-param init " ASP_SCTP_PARAM_INIT_FIELDS,
- NO_STR ASP_SCTP_PARAM_INIT_DESC,
- CMD_ATTR_NODE_EXIT)
-{
- struct osmo_ss7_asp *asp = vty->index;
-
- if (strcmp(argv[0], "num-ostreams") == 0)
- asp->cfg.sctp_init.num_ostreams_present = false;
- else if (strcmp(argv[0], "max-instreams") == 0)
- asp->cfg.sctp_init.max_instreams_present = false;
- else if (strcmp(argv[0], "max-attempts") == 0)
- asp->cfg.sctp_init.max_attempts_present = false;
- else if (strcmp(argv[0], "timeout") == 0)
- asp->cfg.sctp_init.max_init_timeo_present = false;
- else
- OSMO_ASSERT(0);
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(asp_block, asp_block_cmd,
- "block",
- "Allows a SCTP Association with ASP, but doesn't let it become
active\n",
- CMD_ATTR_NODE_EXIT)
-{
- /* TODO */
- vty_out(vty, "Not supported yet%s", VTY_NEWLINE);
- return CMD_WARNING;
-}
-
-DEFUN_ATTR(asp_shutdown, asp_shutdown_cmd,
- "shutdown",
- "Terminates SCTP association; New associations will be rejected\n",
- CMD_ATTR_NODE_EXIT)
-{
- struct osmo_ss7_asp *asp = vty->index;
-
- LOGPASP(asp, DLSS7, LOGL_NOTICE, "Applying Adm State change: %s -> %s\n",
- get_value_string(osmo_ss7_asp_admin_state_names, asp->cfg.adm_state),
- get_value_string(osmo_ss7_asp_admin_state_names, OSMO_SS7_ASP_ADM_S_SHUTDOWN));
-
- asp->cfg.explicit_shutdown_state_by_vty_since_node_enter = true;
- asp->cfg.adm_state = OSMO_SS7_ASP_ADM_S_SHUTDOWN;
- ss7_asp_restart_after_reconfigure(asp);
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(asp_no_shutdown, asp_no_shutdown_cmd,
- "no shutdown",
- NO_STR "Terminates SCTP association; New associations will be rejected\n",
- CMD_ATTR_NODE_EXIT)
-{
- struct osmo_ss7_asp *asp = vty->index;
-
- LOGPASP(asp, DLSS7, LOGL_NOTICE, "Applying Adm State change: %s -> %s\n",
- get_value_string(osmo_ss7_asp_admin_state_names, asp->cfg.adm_state),
- get_value_string(osmo_ss7_asp_admin_state_names, OSMO_SS7_ASP_ADM_S_ENABLED));
-
- asp->cfg.explicit_shutdown_state_by_vty_since_node_enter = true;
- asp->cfg.adm_state = OSMO_SS7_ASP_ADM_S_ENABLED;
- ss7_asp_restart_after_reconfigure(asp);
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(asp_quirk, asp_quirk_cmd,
- "OVERWRITTEN",
- "OVERWRITTEN\n",
- CMD_ATTR_IMMEDIATE)
-{
- struct osmo_ss7_asp *asp = vty->index;
- int quirk = get_string_value(asp_quirk_names, argv[0]);
-
- if (quirk < 0)
- return CMD_WARNING;
-
- asp->cfg.quirks |= quirk;
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(asp_no_quirk, asp_no_quirk_cmd,
- "OVERWRITTEN",
- "OVERWRITTEN\n",
- CMD_ATTR_IMMEDIATE)
-{
- struct osmo_ss7_asp *asp = vty->index;
- int quirk = get_string_value(asp_quirk_names, argv[0]);
-
- if (quirk < 0)
- return CMD_WARNING;
-
- asp->cfg.quirks &= ~quirk;
- return CMD_SUCCESS;
-}
-
-/* timer lm <name> <1-999999>
- * (cmdstr and doc are dynamically generated from ss7_asp_lm_timer_names.) */
-DEFUN_ATTR(asp_timer, asp_timer_cmd,
- NULL, NULL, CMD_ATTR_IMMEDIATE)
-{
- struct osmo_ss7_asp *asp = vty->index;
- enum ss7_asp_lm_timer timer = get_string_value(ss7_asp_lm_timer_names, argv[0]);
-
- if (timer <= 0 || timer >= SS7_ASP_LM_TIMERS_LEN) {
- vty_out(vty, "%% Invalid timer: %s%s", argv[0], VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- osmo_tdef_set(asp->cfg.T_defs_lm, timer, atoi(argv[1]), OSMO_TDEF_S);
- return CMD_SUCCESS;
-}
-
-static void gen_asp_timer_cmd_strs(struct cmd_element *cmd)
-{
- int i;
- char *cmd_str = NULL;
- char *doc_str = NULL;
-
- OSMO_ASSERT(cmd->string == NULL);
- OSMO_ASSERT(cmd->doc == NULL);
-
- osmo_talloc_asprintf(tall_vty_ctx, cmd_str, "timer lm (");
- osmo_talloc_asprintf(tall_vty_ctx, doc_str,
- "Configure ASP default timer values\n"
- "Configure ASP default lm timer values\n");
-
- for (i = 0; ss7_asp_lm_timer_names[i].str; i++) {
- const struct osmo_tdef *def;
- enum ss7_asp_lm_timer timer;
-
- timer = ss7_asp_lm_timer_names[i].value;
- def = osmo_tdef_get_entry((struct osmo_tdef *)&ss7_asp_lm_timer_defaults, timer);
- OSMO_ASSERT(def);
-
- osmo_talloc_asprintf(tall_vty_ctx, cmd_str, "%s%s",
- i ? "|" : "",
- ss7_asp_lm_timer_names[i].str);
- osmo_talloc_asprintf(tall_vty_ctx, doc_str, "%s (default: %lu)\n",
- def->desc,
- def->default_val);
- }
-
- osmo_talloc_asprintf(tall_vty_ctx, cmd_str, ") <1-999999>");
- osmo_talloc_asprintf(tall_vty_ctx, doc_str,
- "Timer value, in seconds\n");
-
- cmd->string = cmd_str;
- cmd->doc = doc_str;
-}
-
-static void write_asp_timers(struct vty *vty, const char *indent,
- struct osmo_ss7_asp *asp)
-{
- int i;
-
- for (i = 0; ss7_asp_lm_timer_names[i].str; i++) {
- const struct osmo_tdef *tdef = osmo_tdef_get_entry(asp->cfg.T_defs_lm,
ss7_asp_lm_timer_names[i].value);
- if (!tdef)
- continue;
- if (tdef->val == tdef->default_val)
- continue;
- vty_out(vty, "%stimer lm %s %lu%s", indent, ss7_asp_lm_timer_names[i].str,
- tdef->val, VTY_NEWLINE);
- }
-}
-
-static char *as_list_for_asp(const struct osmo_ss7_asp *asp, char *buf, size_t buf_len)
-{
- struct osmo_strbuf sb = { .buf = buf, .len = buf_len };
- const struct osmo_ss7_as *as;
- unsigned int count = 0;
- llist_for_each_entry(as, &asp->inst->as_list, list) {
- if (!osmo_ss7_as_has_asp(as, asp))
- continue;
- OSMO_STRBUF_PRINTF(sb, "%s%s", count != 0 ? "," : "",
as->cfg.name);
- count++;
- break;
- }
-
- if (count == 0)
- OSMO_STRBUF_PRINTF(sb, "?");
- return buf;
-}
-
-/* Similar to osmo_sock_multiaddr_get_name_buf(), but aimed at listening sockets (only
local part): */
-static char *get_sockname_buf(char *buf, size_t buf_len, int fd, int proto, bool local)
-{
- char hostbuf[OSMO_SOCK_MAX_ADDRS][INET6_ADDRSTRLEN];
- size_t num_hostbuf = ARRAY_SIZE(hostbuf);
- char portbuf[6];
- struct osmo_strbuf sb = { .buf = buf, .len = buf_len };
- bool need_more_bufs;
- int rc;
-
- rc = osmo_sock_multiaddr_get_ip_and_port(fd, proto, &hostbuf[0][0],
- &num_hostbuf, sizeof(hostbuf[0]),
- portbuf, sizeof(portbuf), local);
- if (rc < 0)
- return NULL;
-
- need_more_bufs = num_hostbuf > ARRAY_SIZE(hostbuf);
- if (need_more_bufs)
- num_hostbuf = ARRAY_SIZE(hostbuf);
- OSMO_STRBUF_APPEND(sb, osmo_multiaddr_ip_and_port_snprintf,
- &hostbuf[0][0], num_hostbuf, sizeof(hostbuf[0]), portbuf);
- if (need_more_bufs)
- OSMO_STRBUF_PRINTF(sb, "<need-more-bufs!>");
-
- return buf;
-}
-
-static void show_one_asp(struct vty *vty, struct osmo_ss7_asp *asp)
-{
- char as_buf[64];
- char buf_loc[OSMO_SOCK_MULTIADDR_PEER_STR_MAXLEN];
- char buf_rem[sizeof(buf_loc)];
-
- int fd = ss7_asp_get_fd(asp);
- if (fd > 0) {
- const int trans_proto = asp->cfg.trans_proto;
- if (!get_sockname_buf(buf_loc, sizeof(buf_loc), fd, trans_proto, true))
- OSMO_STRLCPY_ARRAY(buf_loc, "<sockname-error>");
- if (!get_sockname_buf(buf_rem, sizeof(buf_rem), fd, trans_proto, false))
- OSMO_STRLCPY_ARRAY(buf_rem, "<sockname-error>");
- } else {
- ss7_asp_peer_snprintf(buf_loc, sizeof(buf_loc), &asp->cfg.local);
- ss7_asp_peer_snprintf(buf_rem, sizeof(buf_rem), &asp->cfg.remote);
- }
-
- vty_out(vty, "%-12s %-12s %-13s %-4s %-4s %-9s %-23s %-23s%s",
- asp->cfg.name,
- as_list_for_asp(asp, as_buf, sizeof(as_buf)),
- asp->fi ? osmo_fsm_inst_state_name(asp->fi) : "uninitialized",
- get_value_string(osmo_ss7_asp_protocol_vals, asp->cfg.proto),
- osmo_str_tolower(get_value_string(osmo_ss7_asp_role_names, asp->cfg.role)),
- asp->cfg.is_server ? "server" : "client",
- buf_loc, buf_rem,
- VTY_NEWLINE);
-}
-
-static int show_asp(struct vty *vty, int id, const char *asp_name)
-{
- struct osmo_ss7_instance *inst;
- struct osmo_ss7_asp *asp = NULL;
-
- inst = osmo_ss7_instance_find(id);
- if (!inst) {
- vty_out(vty, "No SS7 instance %d found%s", id, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (asp_name) {
- asp = osmo_ss7_asp_find_by_name(inst, asp_name);
- if (!asp) {
- vty_out(vty, "No ASP %s found%s", asp_name, VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
- vty_out(vty, "ASP Name AS Name State Type Role SCTP Role
Local Addresses Remote Addresses%s", VTY_NEWLINE);
- vty_out(vty, "------------ ------------ ------------- ---- ---- ---------
----------------------- -----------------------%s", VTY_NEWLINE);
-
- if (asp) {
- show_one_asp(vty, asp);
- return CMD_SUCCESS;
- }
-
- llist_for_each_entry(asp, &inst->asp_list, list)
- show_one_asp(vty, asp);
- return CMD_SUCCESS;
-}
-
-DEFUN(show_cs7_asp, show_cs7_asp_cmd,
- "show cs7 instance <0-15> asp",
- SHOW_STR CS7_STR INST_STR INST_STR
- "Application Server Process (ASP)\n")
-{
- int id = atoi(argv[0]);
-
- return show_asp(vty, id, NULL);
-}
-
-DEFUN(show_cs7_asp_name, show_cs7_asp_name_cmd,
- "show cs7 instance <0-15> asp name ASP_NAME",
- SHOW_STR CS7_STR INST_STR INST_STR
- "Application Server Process (ASP)\n"
- "Lookup ASP with a given name\n"
- "Name of the Application Server Process (ASP)\n")
-{
- int id = atoi(argv[0]);
- const char *asp_name = argv[1];
-
- return show_asp(vty, id, asp_name);
-}
-
-static void show_one_asp_remaddr_tcp(struct vty *vty, struct osmo_ss7_asp *asp)
-{
- struct osmo_sockaddr osa = {};
- struct tcp_info tcpi = {};
- socklen_t len;
- int fd, rc;
-
- fd = ss7_asp_get_fd(asp);
- if (fd < 0) {
- vty_out(vty, "%-12s %-46s uninitialized%s", asp->cfg.name, "",
VTY_NEWLINE);
- return;
- }
-
- len = sizeof(osa.u.sas);
- rc = getpeername(fd, &osa.u.sa, &len);
-
- len = sizeof(tcpi);
- rc = getsockopt(fd, SOL_TCP, TCP_INFO, &tcpi, &len);
- if (rc < 0) {
- char buf_err[128];
- strerror_r(errno, buf_err, sizeof(buf_err));
- vty_out(vty, "%-12s %-46s getsockopt(TCP_INFO) failed: %s%s",
- asp->cfg.name, osmo_sockaddr_to_str(&osa), buf_err, VTY_NEWLINE);
- return;
- }
-
- vty_out(vty, "%-12s %-46s TCP_%-19s %-8u %-8u %-8u %-8u%s",
- asp->cfg.name,
- osmo_sockaddr_to_str(&osa),
- get_value_string(tcp_info_state_values, tcpi.tcpi_state),
- tcpi.tcpi_snd_cwnd, tcpi.tcpi_rtt,
- tcpi.tcpi_rto, tcpi.tcpi_pmtu,
- VTY_NEWLINE);
-}
-
-#ifdef HAVE_LIBSCTP
-static void show_one_asp_remaddr_sctp(struct vty *vty, struct osmo_ss7_asp *asp)
-{
- struct sctp_paddrinfo pinfo[OSMO_SOCK_MAX_ADDRS];
- struct osmo_sockaddr osa = {};
- size_t pinfo_cnt = ARRAY_SIZE(pinfo);
- bool more_needed;
- int fd, rc;
- unsigned int i;
-
- fd = ss7_asp_get_fd(asp);
- if (fd < 0) {
- vty_out(vty, "%-12s %-46s uninitialized%s", asp->cfg.name, "",
VTY_NEWLINE);
- return;
- }
-
- rc = osmo_sock_sctp_get_peer_addr_info(fd, &pinfo[0], &pinfo_cnt);
- if (rc < 0) {
- char buf_err[128];
- strerror_r(errno, buf_err, sizeof(buf_err));
- vty_out(vty, "%-12s %-46s getsockopt(SCTP_GET_PEER_ADDR_INFO) failed:
%s%s", asp->cfg.name, "", buf_err, VTY_NEWLINE);
- return;
- }
-
- more_needed = pinfo_cnt > ARRAY_SIZE(pinfo);
- if (pinfo_cnt > ARRAY_SIZE(pinfo))
- pinfo_cnt = ARRAY_SIZE(pinfo);
-
- for (i = 0; i < pinfo_cnt; i++) {
- osa.u.sas = pinfo[i].spinfo_address;
- vty_out(vty, "%-12s %-46s SCTP_%-18s %-8u %-8u %-8u %-8u%s",
- asp->cfg.name,
- osmo_sockaddr_to_str(&osa),
- osmo_sctp_spinfo_state_str(pinfo[i].spinfo_state),
- pinfo[i].spinfo_cwnd, pinfo[i].spinfo_srtt,
- pinfo[i].spinfo_rto, pinfo[i].spinfo_mtu,
- VTY_NEWLINE);
- }
-
- if (more_needed)
- vty_out(vty, "%-12s more address buffers needed!%s", asp->cfg.name,
VTY_NEWLINE);
-}
-#endif
-
-static void show_one_asp_remaddr(struct vty *vty, struct osmo_ss7_asp *asp)
-{
- switch (asp->cfg.trans_proto) {
- case IPPROTO_TCP:
- show_one_asp_remaddr_tcp(vty, asp);
- break;
-#ifdef HAVE_LIBSCTP
- case IPPROTO_SCTP:
- show_one_asp_remaddr_sctp(vty, asp);
- break;
-#endif
- default:
- vty_out(vty, "%-12s %-46s unknown proto %d%s",
- asp->cfg.name, "", asp->cfg.trans_proto, VTY_NEWLINE);
- break;
- }
-}
-
-static int show_asp_remaddr(struct vty *vty, int id, const char *asp_name)
-{
- struct osmo_ss7_instance *inst;
- struct osmo_ss7_asp *asp = NULL;
-
- inst = osmo_ss7_instance_find(id);
- if (!inst) {
- vty_out(vty, "No SS7 instance %d found%s", id, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (asp_name) {
- asp = osmo_ss7_asp_find_by_name(inst, asp_name);
- if (!asp) {
- vty_out(vty, "No ASP %s found%s", asp_name, VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
- vty_out(vty, "ASP Name Remote IP Address & Port
State CWND SRTT RTO MTU%s", VTY_NEWLINE);
- vty_out(vty, "------------ ----------------------------------------------
----------------------- -------- -------- -------- --------%s", VTY_NEWLINE);
-
- if (asp) {
- show_one_asp_remaddr(vty, asp);
- return CMD_SUCCESS;
- }
-
- llist_for_each_entry(asp, &inst->asp_list, list) {
- show_one_asp_remaddr(vty, asp);
- }
- return CMD_SUCCESS;
-}
-
-DEFUN(show_cs7_asp_remaddr, show_cs7_asp_remaddr_cmd,
- "show cs7 instance <0-15> asp-remaddr",
- SHOW_STR CS7_STR INST_STR INST_STR
- "Application Server Process (ASP) remote addresses information\n")
-{
- int id = atoi(argv[0]);
-
- return show_asp_remaddr(vty, id, NULL);
-}
-
-
-DEFUN(show_cs7_asp_remaddr_name, show_cs7_asp_remaddr_name_cmd,
- "show cs7 instance <0-15> asp-remaddr name ASP_NAME",
- SHOW_STR CS7_STR INST_STR INST_STR
- "Application Server Process (ASP) remote addresses information\n"
- "Lookup ASP with a given name\n"
- "Name of the Application Server Process (ASP)\n")
-{
- int id = atoi(argv[0]);
- const char *asp_name = argv[1];
-
- return show_asp_remaddr(vty, id, asp_name);
-}
-
-static void show_one_asp_assoc_status_tcp(struct vty *vty, struct osmo_ss7_asp *asp)
-{
- struct osmo_sockaddr osa = {};
- struct tcp_info tcpi = {};
- socklen_t len;
- int fd, rc;
- int rx_pend_bytes = 0;
-
- fd = ss7_asp_get_fd(asp);
- if (fd < 0) {
- vty_out(vty, "%-12s uninitialized%s", asp->cfg.name, VTY_NEWLINE);
- return;
- }
-
- len = sizeof(osa.u.sas);
- rc = getpeername(fd, &osa.u.sa, &len);
-
- len = sizeof(tcpi);
- rc = getsockopt(fd, SOL_TCP, TCP_INFO, &tcpi, &len);
- if (rc < 0) {
- char buf_err[128];
- strerror_r(errno, buf_err, sizeof(buf_err));
- vty_out(vty, "%-12s getsockopt(TCP_INFO) failed: %s%s",
- asp->cfg.name, buf_err, VTY_NEWLINE);
- return;
- }
-
- rc = ioctl(fd, FIONREAD, &rx_pend_bytes);
-
- /* FIXME: RWND: struct tcp_info from linux/tcp.h contains more fields
- * than the one from netinet/tcp.h we currently use, including
- * "tcpi_rcv_wnd" which we could use to print RWND here. However,
- * linux/tcp.h seems to be missing the state defines used in
- * "tcp_info_state_values", so we cannot use that one instead.
- */
-
- vty_out(vty, "%-12s TCP_%-19s %-9s %-10s %-8s %-9u %-7u %-9u
%-46s%s",
- asp->cfg.name,
- get_value_string(tcp_info_state_values, tcpi.tcpi_state),
- "-", "-", "-", tcpi.tcpi_unacked, rx_pend_bytes,
- tcpi.tcpi_pmtu, osmo_sockaddr_to_str(&osa),
- VTY_NEWLINE);
-}
-
-#ifdef HAVE_LIBSCTP
-static void show_one_asp_assoc_status_sctp(struct vty *vty, struct osmo_ss7_asp *asp)
-{
- struct osmo_sockaddr osa = {};
- struct sctp_status st;
- socklen_t len;
- int fd, rc;
-
- fd = ss7_asp_get_fd(asp);
- if (fd < 0) {
- vty_out(vty, "%-12s uninitialized%s", asp->cfg.name, VTY_NEWLINE);
- return;
- }
-
- memset(&st, 0, sizeof(st));
- len = sizeof(st);
- rc = getsockopt(fd, IPPROTO_SCTP, SCTP_STATUS, &st, &len);
- if (rc < 0) {
- char buf_err[128];
- strerror_r(errno, buf_err, sizeof(buf_err));
- vty_out(vty, "%-12s getsockopt(SCTP_STATUS) failed: %s%s", asp->cfg.name,
buf_err, VTY_NEWLINE);
- return;
- }
-
- osa.u.sas = st.sstat_primary.spinfo_address;
- vty_out(vty, "%-12s SCTP_%-18s %-9u %-10u %-8u %-9u %-7u %-9u
%-46s%s",
- asp->cfg.name,
- osmo_sctp_sstat_state_str(st.sstat_state),
- st.sstat_instrms, st.sstat_outstrms,
- st.sstat_rwnd, st.sstat_unackdata, st.sstat_penddata,
- st.sstat_fragmentation_point,
- osmo_sockaddr_to_str(&osa),
- VTY_NEWLINE);
-}
-#endif
-
-static void show_one_asp_assoc_status(struct vty *vty, struct osmo_ss7_asp *asp)
-{
- switch (asp->cfg.trans_proto) {
- case IPPROTO_TCP:
- show_one_asp_assoc_status_tcp(vty, asp);
- break;
-#ifdef HAVE_LIBSCTP
- case IPPROTO_SCTP:
- show_one_asp_assoc_status_sctp(vty, asp);
- break;
-#endif
- default:
- vty_out(vty, "%-12s unknown proto %d%s",
- asp->cfg.name, asp->cfg.trans_proto, VTY_NEWLINE);
- break;
- }
-}
-
-static int show_asp_assoc_status(struct vty *vty, int id, const char *asp_name)
-{
- struct osmo_ss7_instance *inst;
- struct osmo_ss7_asp *asp = NULL;
-
- inst = osmo_ss7_instance_find(id);
- if (!inst) {
- vty_out(vty, "No SS7 instance %d found%s", id, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (asp_name) {
- asp = osmo_ss7_asp_find_by_name(inst, asp_name);
- if (!asp) {
- vty_out(vty, "No ASP %s found%s", asp_name, VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
- vty_out(vty, "ASP Name State InStreams OutStreams RWND
UnackData PenData FragPoint Current Primary Remote IP Address & Port%s",
VTY_NEWLINE);
- vty_out(vty, "------------ ----------------------- --------- ----------
-------- --------- ------- ---------
----------------------------------------------%s", VTY_NEWLINE);
-
- if (asp) {
- show_one_asp_assoc_status(vty, asp);
- return CMD_SUCCESS;
- }
-
- llist_for_each_entry(asp, &inst->asp_list, list)
- show_one_asp_assoc_status(vty, asp);
- return CMD_SUCCESS;
-}
-
-DEFUN(show_cs7_asp_assoc_status, show_cs7_asp_assoc_status_cmd,
- "show cs7 instance <0-15> asp-assoc-status",
- SHOW_STR CS7_STR INST_STR INST_STR
- "Application Server Process (ASP) SCTP association status\n")
-{
- int id = atoi(argv[0]);
-
- return show_asp_assoc_status(vty, id, NULL);
-}
-
-
-DEFUN(show_cs7_asp_assoc_status_name, show_cs7_asp_assoc_status_name_cmd,
- "show cs7 instance <0-15> asp-assoc-status name ASP_NAME",
- SHOW_STR CS7_STR INST_STR INST_STR
- "Application Server Process (ASP) SCTP association information\n"
- "Lookup ASP with a given name\n"
- "Name of the Application Server Process (ASP)\n")
-{
- int id = atoi(argv[0]);
- const char *asp_name = argv[1];
-
- return show_asp_assoc_status(vty, id, asp_name);
-}
-
-static void write_one_asp(struct vty *vty, struct osmo_ss7_asp *asp, bool
show_dyn_config)
-{
- int i;
- /* skip any dynamically created ASPs (e.g. auto-created at connect time) */
- if ((asp->dyn_allocated || asp->simple_client_allocated)
- && !show_dyn_config)
- return;
-
- vty_out(vty, " asp %s %u %u %s",
- asp->cfg.name, asp->cfg.remote.port, asp->cfg.local.port,
- osmo_ss7_asp_protocol_name(asp->cfg.proto));
- if (asp->cfg.trans_proto !=
ss7_default_trans_proto_for_asp_proto(asp->cfg.proto))
- vty_out(vty, " %s", get_value_string(ipproto_vals,
asp->cfg.trans_proto));
- vty_out(vty, "%s", VTY_NEWLINE);
- if (asp->cfg.description)
- vty_out(vty, " description %s%s", asp->cfg.description, VTY_NEWLINE);
- for (i = 0; i < asp->cfg.local.host_cnt; i++) {
- if (asp->cfg.local.host[i])
- vty_out(vty, " local-ip %s%s%s", asp->cfg.local.host[i],
- asp->cfg.local.idx_primary == i ? " primary" : "",
VTY_NEWLINE);
- }
- for (i = 0; i < asp->cfg.remote.host_cnt; i++) {
- if (asp->cfg.remote.host[i])
- vty_out(vty, " remote-ip %s%s%s", asp->cfg.remote.host[i],
- asp->cfg.remote.idx_primary == i ? " primary" : "",
VTY_NEWLINE);
- }
- if (asp->cfg.qos_class)
- vty_out(vty, " qos-class %u%s", asp->cfg.qos_class, VTY_NEWLINE);
- vty_out(vty, " role %s%s",
osmo_str_tolower(get_value_string(osmo_ss7_asp_role_names, asp->cfg.role)),
- VTY_NEWLINE);
- if (asp->cfg.trans_proto == IPPROTO_SCTP)
- vty_out(vty, " sctp-role %s%s", asp->cfg.is_server ? "server" :
"client", VTY_NEWLINE);
- else
- vty_out(vty, " transport-role %s%s", asp->cfg.is_server ?
"server" : "client", VTY_NEWLINE);
- if (asp->cfg.sctp_init.num_ostreams_present)
- vty_out(vty, " sctp-param init num-ostreams %u%s",
asp->cfg.sctp_init.num_ostreams_value, VTY_NEWLINE);
- if (asp->cfg.sctp_init.max_instreams_present)
- vty_out(vty, " sctp-param init max-instreams %u%s",
asp->cfg.sctp_init.max_instreams_value, VTY_NEWLINE);
- if (asp->cfg.sctp_init.max_attempts_present)
- vty_out(vty, " sctp-param init max-attempts %u%s",
asp->cfg.sctp_init.max_attempts_value, VTY_NEWLINE);
- if (asp->cfg.sctp_init.max_init_timeo_present)
- vty_out(vty, " sctp-param init timeout %u%s",
asp->cfg.sctp_init.max_init_timeo_value, VTY_NEWLINE);
- for (i = 0; i < sizeof(uint32_t) * 8; i++) {
- if (!(asp->cfg.quirks & ((uint32_t) 1 << i)))
- continue;
- vty_out(vty, " quirk %s%s", get_value_string(asp_quirk_names, (1 <<
i)), VTY_NEWLINE);
- }
- write_asp_timers(vty, " ", asp);
-
- switch (asp->cfg.adm_state) {
- case OSMO_SS7_ASP_ADM_S_SHUTDOWN:
- vty_out(vty, " shutdown%s", VTY_NEWLINE);
- break;
- case OSMO_SS7_ASP_ADM_S_BLOCKED:
- vty_out(vty, " blocked%s", VTY_NEWLINE);
- break;
- case OSMO_SS7_ASP_ADM_S_ENABLED:
- /* Default, no need to print: */
- vty_out(vty, " no shutdown%s", VTY_NEWLINE);
- break;
- }
-}
-
-
-/***********************************************************************
- * Application Server
- ***********************************************************************/
-
-static struct cmd_node as_node = {
- L_CS7_AS_NODE,
- "%s(config-cs7-as)# ",
- 1,
-};
-
-DEFUN_ATTR(cs7_as, cs7_as_cmd,
- "as NAME " XUA_VAR_STR,
- "Configure an Application Server\n"
- "Name of the Application Server\n"
- XUA_VAR_HELP_STR,
- CMD_ATTR_IMMEDIATE)
-{
- struct osmo_ss7_instance *inst = vty->index;
- struct osmo_ss7_as *as;
- const char *name = argv[0];
- enum osmo_ss7_asp_protocol protocol = parse_asp_proto(argv[1]);
-
- if (protocol == OSMO_SS7_ASP_PROT_NONE) {
- vty_out(vty, "invalid protocol '%s'%s", argv[1], VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- as = osmo_ss7_as_find_or_create(inst, name, protocol);
- if (!as) {
- vty_out(vty, "cannot create AS '%s'%s", name, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- as->cfg.name = talloc_strdup(as, name);
-
- vty->node = L_CS7_AS_NODE;
- vty->index = as;
- vty->index_sub = &as->cfg.description;
-
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(no_cs7_as, no_cs7_as_cmd,
- "no as NAME",
- NO_STR "Disable Application Server\n"
- "Name of AS\n",
- CMD_ATTR_IMMEDIATE)
-{
- struct osmo_ss7_instance *inst = vty->index;
- const char *name = argv[0];
- struct osmo_ss7_as *as;
-
- as = osmo_ss7_as_find_by_name(inst, name);
- if (!as) {
- vty_out(vty, "No AS named '%s' found%s", name, VTY_NEWLINE);
- return CMD_WARNING;
- }
- osmo_ss7_as_destroy(as);
- return CMD_SUCCESS;
-}
-
-/* TODO: routing-key */
-DEFUN_ATTR(as_asp, as_asp_cmd,
- "asp NAME",
- "Specify that a given ASP is part of this AS\n"
- "Name of ASP to be added to AS\n",
- CMD_ATTR_IMMEDIATE)
-{
- struct osmo_ss7_as *as = vty->index;
-
- if (osmo_ss7_as_add_asp(as, argv[0])) {
- vty_out(vty, "cannot find ASP '%s'%s", argv[0], VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(as_no_asp, as_no_asp_cmd,
- "no asp NAME",
- NO_STR "Specify ASP to be removed from this AS\n"
- "Name of ASP to be removed\n",
- CMD_ATTR_IMMEDIATE)
-{
- struct osmo_ss7_as *as = vty->index;
-
- if (osmo_ss7_as_del_asp(as, argv[0])) {
- vty_out(vty, "cannot find ASP '%s'%s", argv[0], VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN_USRATTR(as_traf_mode, as_traf_mode_cmd,
- OSMO_SCCP_LIB_ATTR_RSTRT_ASP,
- "traffic-mode (broadcast | roundrobin | override)",
- "Specifies traffic mode of operation of the ASP within the AS\n"
- "Broadcast to all ASP within AS\n"
- "Round-Robin between all ASP within AS\n"
- "Override\n")
-{
- struct osmo_ss7_as *as = vty->index;
-
- as->cfg.mode = get_string_value(osmo_ss7_as_traffic_mode_vals, argv[0]);
- as->cfg.mode_set_by_vty = true;
- return CMD_SUCCESS;
-}
-
-DEFUN_USRATTR(as_traf_mode_loadshare, as_traf_mode_loadshare_cmd,
- OSMO_SCCP_LIB_ATTR_RSTRT_ASP,
- "traffic-mode loadshare [bindings] [sls] [opc-sls] [opc-shift]
[<0-2>]",
- "Specifies traffic mode of operation of the ASP within the AS\n"
- "Share Load among all ASP within AS\n"
- "Configure Loadshare parameters\n"
- "Configure Loadshare SLS generation parameters\n"
- "Generate extended SLS with OPC information\n"
- "Shift OPC bits used during routing decision\n"
- "How many bits from ITU OPC field (starting from least-significant-bit) to
skip (default=0). 6 bits are always used\n"
- )
-{
- struct osmo_ss7_as *as = vty->index;
-
- as->cfg.mode = OSMO_SS7_AS_TMOD_LOADSHARE;
- as->cfg.mode_set_by_vty = true;
- if (argc < 3) {
- as->cfg.loadshare.opc_sls = false;
- as->cfg.loadshare.opc_shift = 0;
- return CMD_SUCCESS;
- }
- as->cfg.loadshare.opc_sls = true;
- if (argc < 5) {
- as->cfg.loadshare.opc_shift = 0;
- return CMD_SUCCESS;
- }
- as->cfg.loadshare.opc_shift = atoi(argv[4]);
- return CMD_SUCCESS;
-}
-
-DEFUN_USRATTR(as_no_traf_mode, as_no_traf_mode_cmd,
- OSMO_SCCP_LIB_ATTR_RSTRT_ASP,
- "no traffic-mode",
- NO_STR "Remove explicit traffic mode of operation of this AS\n")
-{
- struct osmo_ss7_as *as = vty->index;
-
- as->cfg.mode = 0;
- as->cfg.mode_set_by_vty = false;
-
- as->cfg.loadshare.sls_shift = 0;
- as->cfg.loadshare.opc_sls = false;
- as->cfg.loadshare.opc_shift = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(as_sls_shift, as_sls_shift_cmd,
- "sls-shift <0-3>",
- "Shift SLS bits used during routing decision\n"
- "How many bits from SLS field (starting from least-significant-bit) to
skip\n",
- CMD_ATTR_IMMEDIATE)
-{
- struct osmo_ss7_as *as = vty->index;
- as->cfg.loadshare.sls_shift = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(as_bindingtable_reset, as_bindingtable_reset_cmd,
- "binding-table reset",
- "AS Loadshare binding table operations\n"
- "Reset loadshare binding table\n",
- CMD_ATTR_IMMEDIATE)
-{
- struct osmo_ss7_as *as = vty->index;
- ss7_as_loadshare_binding_table_reset(as);
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(as_recov_tout, as_recov_tout_cmd,
- "recovery-timeout <1-2000>",
- "Specifies the recovery timeout value in milliseconds\n"
- "Recovery Timeout in Milliseconds\n",
- CMD_ATTR_IMMEDIATE)
-{
- struct osmo_ss7_as *as = vty->index;
- as->cfg.recovery_timeout_msec = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(as_qos_clas, as_qos_class_cmd,
- "qos-class " QOS_CLASS_RANGE_STR,
- "Specity QoS Class of AS\n"
- QOS_CLASS_RANGE_HELP_STR,
- CMD_ATTR_IMMEDIATE)
-{
- struct osmo_ss7_as *as = vty->index;
- as->cfg.qos_class = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-const struct value_string mtp_si_vals[] = {
- { MTP_SI_SCCP, "sccp" },
- { MTP_SI_TUP, "tup" },
- { MTP_SI_ISUP, "isup" },
- { MTP_SI_DUP, "dup" },
- { MTP_SI_TESTING, "testing" },
- { MTP_SI_B_ISUP, "b-isup" },
- { MTP_SI_SAT_ISUP, "sat-isup" },
- { MTP_SI_AAL2_SIG, "aal2" },
- { MTP_SI_BICC, "bicc" },
- { MTP_SI_GCP, "h248" },
- { 0, NULL }
-};
-
-#define ROUTING_KEY_CMD "routing-key RCONTEXT DPC"
-#define ROUTING_KEY_CMD_STRS \
- "Define a routing key\n" \
- "Routing context number\n" \
- "Destination Point Code\n"
-#define ROUTING_KEY_SI_ARG " si
(aal2|bicc|b-isup|h248|isup|sat-isup|sccp|tup)"
-#define ROUTING_KEY_SI_ARG_STRS \
- "Match on Service Indicator\n" \
- "ATM Adaption Layer 2\n" \
- "Bearer Independent Call Control\n" \
- "Broadband ISDN User Part\n" \
- "H.248\n" \
- "ISDN User Part\n" \
- "Sattelite ISDN User Part\n" \
- "Signalling Connection Control Part\n" \
- "Telephony User Part\n"
-#define ROUTING_KEY_SSN_ARG " ssn SSN"
-#define ROUTING_KEY_SSN_ARG_STRS \
- "Match on Sub-System Number\n" \
- "Sub-System Number to match on\n"
-
-static int _rout_key(struct vty *vty,
- const char *rcontext, const char *dpc,
- const char *si, const char *ssn)
-{
- struct osmo_ss7_as *as = vty->index;
- struct osmo_ss7_routing_key *rkey = &as->cfg.routing_key;
- struct osmo_ss7_route *rt;
- int pc;
-
- if (as->cfg.proto == OSMO_SS7_ASP_PROT_IPA && atoi(rcontext) != 0) {
- vty_out(vty, "IPA doesn't support routing contexts; only permitted routing
context "
- "is 0\n");
- return CMD_WARNING;
- }
-
- pc = osmo_ss7_pointcode_parse(as->inst, dpc);
- if (pc < 0) {
- vty_out(vty, "Invalid point code (%s)%s", dpc, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- /* When libosmo-sigtran is used in ASP role, the VTY routing table node
- * (config-cs7-rt) is not available. However, when we add a routing key
- * to an AS we still have to put a matching route into the routing
- * table. This is done automatically by first removing the old route
- * (users may change the routing key via VTY during runtime) and then
- * putting a new route (see below). */
- if (cs7_role == CS7_ROLE_ASP) {
- rt = ss7_route_table_find_route_by_dpc_mask(as->inst->rtable_system, rkey->pc,
0xffffff);
- if (rt)
- ss7_route_destroy(rt);
- }
-
- rkey->pc = pc;
-
- rkey->context = atoi(rcontext); /* FIXME: input validation */
- rkey->si = si ? get_string_value(mtp_si_vals, si) : 0; /* FIXME: input validation */
- rkey->ssn = ssn ? atoi(ssn) : 0; /* FIXME: input validation */
-
- /* automatically add new route (see also comment above) */
- if (cs7_role == CS7_ROLE_ASP) {
- if (!ss7_route_create(as->inst->rtable_system, rkey->pc, 0xffffff,
as->cfg.name)) {
- vty_out(vty, "Cannot create route (pc=%s, linkset=%s) to AS %s", dpc,
as->cfg.name, VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(as_rout_key, as_rout_key_cmd,
- ROUTING_KEY_CMD,
- ROUTING_KEY_CMD_STRS,
- CMD_ATTR_IMMEDIATE)
-{
- return _rout_key(vty, argv[0], argv[1], NULL, NULL);
-}
-
-DEFUN_ATTR(as_rout_key_si, as_rout_key_si_cmd,
- ROUTING_KEY_CMD ROUTING_KEY_SI_ARG,
- ROUTING_KEY_CMD_STRS ROUTING_KEY_SI_ARG_STRS,
- CMD_ATTR_IMMEDIATE)
-{
- return _rout_key(vty, argv[0], argv[1], argv[2], NULL);
-}
-
-DEFUN_ATTR(as_rout_key_ssn, as_rout_key_ssn_cmd,
- ROUTING_KEY_CMD ROUTING_KEY_SSN_ARG,
- ROUTING_KEY_CMD_STRS ROUTING_KEY_SSN_ARG_STRS,
- CMD_ATTR_IMMEDIATE)
-{
- return _rout_key(vty, argv[0], argv[1], NULL, argv[2]);
-}
-
-DEFUN_ATTR(as_rout_key_si_ssn, as_rout_key_si_ssn_cmd,
- ROUTING_KEY_CMD ROUTING_KEY_SI_ARG ROUTING_KEY_SSN_ARG,
- ROUTING_KEY_CMD_STRS ROUTING_KEY_SI_ARG_STRS ROUTING_KEY_SSN_ARG_STRS,
- CMD_ATTR_IMMEDIATE)
-{
- return _rout_key(vty, argv[0], argv[1], argv[2], argv[3]);
-}
-
-DEFUN_ATTR(as_pc_override, as_pc_override_cmd,
- "point-code override dpc PC",
- "Point Code Specific Features\n"
- "Override (force) a point-code to hard-coded value\n"
- "Override Source Point Code\n"
- "Override Destination Point Code\n"
- "New Point Code\n",
- CMD_ATTR_IMMEDIATE)
-{
- struct osmo_ss7_as *as = vty->index;
- int pc = osmo_ss7_pointcode_parse(as->inst, argv[0]);
- if (pc < 0) {
- vty_out(vty, "Invalid point code (%s)%s", argv[0], VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (as->cfg.proto != OSMO_SS7_ASP_PROT_IPA) {
- vty_out(vty, "Only IPA type AS support point-code override. "
- "Be happy that you don't need it!%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- as->cfg.pc_override.dpc = pc;
-
- return CMD_SUCCESS;
-}
-
-DEFUN_ATTR(as_pc_patch_sccp, as_pc_patch_sccp_cmd,
- "point-code override patch-sccp (disabled|both)",
- "Point Code Specific Features\n"
- "Override (force) a point-code to hard-coded value\n"
- "Patch point code values into SCCP called/calling address\n"
- "Don't patch any point codes into SCCP called/calling address\n"
- "Patch both origin and destination point codes into SCCP called/calling
address\n",
- CMD_ATTR_IMMEDIATE)
-{
- struct osmo_ss7_as *as = vty->index;
-
- if (as->cfg.proto != OSMO_SS7_ASP_PROT_IPA) {
- vty_out(vty, "Only IPA type AS support point-code patch-into-sccp. "
- "Be happy that you don't need it!%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (!strcmp(argv[0], "disabled"))
- as->cfg.pc_override.sccp_mode = OSMO_SS7_PATCH_NONE;
- else
- as->cfg.pc_override.sccp_mode = OSMO_SS7_PATCH_BOTH;
-
- return CMD_SUCCESS;
-}
-
-static void write_one_as(struct vty *vty, struct osmo_ss7_as *as, bool show_dyn_config)
-{
- struct osmo_ss7_routing_key *rkey;
- unsigned int i;
-
- /* skip any dynamically allocated AS definitions */
- if ((as->rkm_dyn_allocated || as->simple_client_allocated)
- && !show_dyn_config)
- return;
-
- vty_out(vty, " as %s %s%s", as->cfg.name,
- osmo_ss7_asp_protocol_name(as->cfg.proto), VTY_NEWLINE);
- if (as->cfg.description)
- vty_out(vty, " description %s%s", as->cfg.description, VTY_NEWLINE);
- for (i = 0; i < ARRAY_SIZE(as->cfg.asps); i++) {
- struct osmo_ss7_asp *asp = as->cfg.asps[i];
- if (!asp)
- continue;
- /* skip any dynamically created ASPs (e.g. auto-created at connect time) */
- if ((asp->dyn_allocated || asp->simple_client_allocated)
- && !show_dyn_config)
- continue;
- vty_out(vty, " asp %s%s", asp->cfg.name, VTY_NEWLINE);
- }
- if (as->cfg.mode_set_by_vty) {
- vty_out(vty, " traffic-mode %s%s",
osmo_ss7_as_traffic_mode_name(as->cfg.mode), VTY_NEWLINE);
- if (as->cfg.mode == OSMO_SS7_AS_TMOD_LOADSHARE) {
- if (as->cfg.loadshare.opc_sls) {
- vty_out(vty, " bindings sls opc-sls");
- if (as->cfg.loadshare.opc_shift != 0)
- vty_out(vty, " opc-shift %u", as->cfg.loadshare.opc_shift);
- }
- vty_out(vty, "%s", VTY_NEWLINE);
- }
-
- if (as->cfg.loadshare.sls_shift != 0)
- vty_out(vty, " sls-shift %u%s", as->cfg.loadshare.sls_shift,
VTY_NEWLINE);
- }
-
- if (as->cfg.recovery_timeout_msec != 2000) {
- vty_out(vty, " recovery-timeout %u%s",
- as->cfg.recovery_timeout_msec, VTY_NEWLINE);
- }
- if (as->cfg.qos_class)
- vty_out(vty, " qos-class %u%s", as->cfg.qos_class, VTY_NEWLINE);
- rkey = &as->cfg.routing_key;
- vty_out(vty, " routing-key %u %s", rkey->context,
- osmo_ss7_pointcode_print(as->inst, rkey->pc));
- if (rkey->si)
- vty_out(vty, " si %s",
- get_value_string(mtp_si_vals, rkey->si));
- if (rkey->ssn)
- vty_out(vty, " ssn %u", rkey->ssn);
- vty_out(vty, "%s", VTY_NEWLINE);
-
- if (as->cfg.pc_override.dpc)
- vty_out(vty, " point-code override dpc %s%s",
- osmo_ss7_pointcode_print(as->inst, as->cfg.pc_override.dpc), VTY_NEWLINE);
-
- if (as->cfg.pc_override.sccp_mode)
- vty_out(vty, " point-code override patch-sccp both%s", VTY_NEWLINE);
-}
-
-static void show_one_as(struct vty *vty, struct osmo_ss7_as *as)
-{
- vty_out(vty, "%-12s %-12s %-10u %-13s %4s %13s %3s %5s %4s %10s%s",
- as->cfg.name, osmo_fsm_inst_state_name(as->fi), as->cfg.routing_key.context,
- osmo_ss7_pointcode_print(as->inst, as->cfg.routing_key.pc),
- "", "", "", "", "",
osmo_ss7_as_traffic_mode_name(as->cfg.mode),
- VTY_NEWLINE);
-}
-
-static int show_as(struct vty *vty, int id, const char *as_name, const char *filter)
-{
- struct osmo_ss7_instance *inst;
- struct osmo_ss7_as *as = NULL;
-
- inst = osmo_ss7_instance_find(id);
- if (!inst) {
- vty_out(vty, "%% No SS7 instance %d found%s", id, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (as_name) {
- as = osmo_ss7_as_find_by_name(inst, as_name);
- if (!as) {
- vty_out(vty, "%% No AS '%s' found%s", as_name, VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
- vty_out(vty, " Routing Routing Key
Cic Cic Traffic%s", VTY_NEWLINE);
- vty_out(vty, "AS Name State Context Dpc Si Opc
Ssn Min Max Mode%s", VTY_NEWLINE);
- vty_out(vty, "------------ ------------ ---------- ------------- ---- -------------
--- ----- ----- -------%s", VTY_NEWLINE);
-
- if (as) {
- show_one_as(vty, as);
- return CMD_SUCCESS;
- }
-
- llist_for_each_entry(as, &inst->as_list, list) {
- if (filter && !strcmp(filter, "m3ua") && as->cfg.proto !=
OSMO_SS7_ASP_PROT_M3UA)
- continue;
- if (filter && !strcmp(filter, "sua") && as->cfg.proto !=
OSMO_SS7_ASP_PROT_SUA)
- continue;
- if (filter && !strcmp(filter, "active") &&
!osmo_ss7_as_active(as))
- continue;
- show_one_as(vty, as);
- }
- return CMD_SUCCESS;
-}
-
-DEFUN(show_cs7_as, show_cs7_as_cmd,
- "show cs7 instance <0-15> as (active|all|m3ua|sua)",
- SHOW_STR CS7_STR INST_STR INST_STR "Application Server (AS)\n"
- "Display all active ASs\n"
- "Display all ASs (default)\n"
- "Display all m3ua ASs\n"
- "Display all SUA ASs\n")
-{
- const char *filter = argv[1];
- int id = atoi(argv[0]);
-
- return show_as(vty, id, NULL, filter);
-}
-
-DEFUN(show_cs7_as_name, show_cs7_as_name_cmd,
- "show cs7 instance <0-15> as name AS_NAME",
- SHOW_STR CS7_STR INST_STR INST_STR "Application Server (AS)\n"
- "Look up AS with a given name\n"
- "Name of the Application Server (AS)\n")
-{
- int id = atoi(argv[0]);
- const char *as_name = argv[1];
-
- return show_as(vty, id, as_name, NULL);
-}
-
-DEFUN(show_cs7_as_bindingtable_name, show_cs7_as_bindingtable_name_cmd,
- "show cs7 instance <0-15> as binding-table name AS_NAME",
- SHOW_STR CS7_STR INST_STR INST_STR "Application Server (AS)\n"
- "Display binding table\n"
- "Look up AS with a given name\n"
- "Name of the Application Server (AS)\n")
-{
- int id = atoi(argv[0]);
- const char *as_name = argv[1];
- struct osmo_ss7_instance *inst;
- struct osmo_ss7_as *as = NULL;
-
- inst = osmo_ss7_instance_find(id);
- if (!inst) {
- vty_out(vty, "No SS7 instance %d found%s", id, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (as_name) {
- as = osmo_ss7_as_find_by_name(inst, as_name);
- if (!as) {
- vty_out(vty, "No AS %s found%s", as_name, VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
- vty_out(vty, "Loadshare Seed Normal ASP Active Alternative ASP
Active%s", VTY_NEWLINE);
- vty_out(vty, "-------------- --------------- ------ ---------------
------%s", VTY_NEWLINE);
-
- for (unsigned int i = 0; i < ARRAY_SIZE(as->aesls_table); i++) {
- struct osmo_ss7_as_esls_entry *e = &as->aesls_table[i];
- vty_out(vty, "%-15u %-16s %-7s %-16s %-7s%s",
- i,
- e->normal_asp ? e->normal_asp->cfg.name : "-",
- e->normal_asp ? (osmo_ss7_asp_active(e->normal_asp) ? "Yes" :
"No") : "-",
- e->alt_asp ? e->alt_asp->cfg.name : "-",
- e->alt_asp ? (osmo_ss7_asp_active(e->alt_asp) ? "Yes" :
"No") : "-",
- VTY_NEWLINE);
- }
-
- return CMD_SUCCESS;
-}
-
-/***********************************************************************
* SCCP addressbook handling
***********************************************************************/
@@ -3287,11 +1402,11 @@
/* first dump ASPs, as ASs reference them */
llist_for_each_entry(asp, &inst->asp_list, list)
- write_one_asp(vty, asp, show_dyn_config);
+ ss7_vty_write_one_asp(vty, asp, show_dyn_config);
/* then dump ASPs, as routes reference them */
llist_for_each_entry(as, &inst->as_list, list)
- write_one_as(vty, as, show_dyn_config);
+ ss7_vty_write_one_as(vty, as, show_dyn_config);
/* now dump everything that is relevent for the SG role */
if (cs7_role == CS7_ROLE_SG) {
@@ -3301,7 +1416,7 @@
write_one_rtable(vty, rtable);
llist_for_each_entry(oxs, &inst->xua_servers, list)
- write_one_xua(vty, oxs);
+ ss7_vty_write_one_oxs(vty, oxs);
}
/* Append SCCP Addressbook */
@@ -3313,57 +1428,21 @@
int osmo_ss7_vty_go_parent(struct vty *vty)
{
- struct osmo_ss7_as *as;
- struct osmo_ss7_asp *asp;
struct osmo_ss7_route_table *rtbl;
- struct osmo_xua_server *oxs;
struct osmo_sccp_addr_entry *entry;
switch (vty->node) {
case L_CS7_ASP_NODE:
- asp = vty->index;
- if (asp->cfg.explicit_shutdown_state_by_vty_since_node_enter) {
- /* Interactive VTY, inform of new behavior upon use of new '[no] shutdown'
commands: */
- if (vty->type != VTY_FILE)
- vty_out(vty, "%% NOTE: Skipping automatic restart of ASP since an explicit
'[no] shutdown' command was entered%s", VTY_NEWLINE);
- asp->cfg.explicit_shutdown_state_by_vty_since_node_enter = false;
- } else if (vty->type == VTY_FILE) {
- /* Make sure config reading is backward compatible by starting the ASP if no explicit
'no shutdown' is read: */
- vty_out(vty,
- "%% VTY node 'asp' without a '[no] shutdown' command at the end
is deprecated, "
- "please make sure you update your cfg file for future compatibility.%s",
- VTY_NEWLINE);
- ss7_asp_restart_after_reconfigure(asp);
- } else {
- /* Interactive VTY without '[no] shutdown' explicit cmd, remind the user that
we are no
- * longer automatically restarting the ASP when going out of the "asp" node:
*/
- vty_out(vty,
- "%% NOTE: Make sure to use '[no] shutdown' command in 'asp' node
"
- "in order to restart the ASP for new configs to be applied.%s",
- VTY_NEWLINE);
- }
- vty->node = L_CS7_NODE;
- vty->index = asp->inst;
- break;
+ return ss7_vty_node_asp_go_parent(vty);
case L_CS7_RTABLE_NODE:
rtbl = vty->index;
vty->node = L_CS7_NODE;
vty->index = rtbl->inst;
break;
case L_CS7_AS_NODE:
- as = vty->index;
- vty->node = L_CS7_NODE;
- vty->index = as->inst;
- break;
+ return ss7_vty_node_as_go_parent(vty);
case L_CS7_XUA_NODE:
- oxs = vty->index;
- /* If no local addr was set, or erased after _create(): */
- ss7_xua_server_set_default_local_hosts(oxs);
- if (ss7_xua_server_bind(oxs) < 0)
- vty_out(vty, "%% Unable to bind xUA server to IP(s)%s", VTY_NEWLINE);
- vty->node = L_CS7_NODE;
- vty->index = oxs->inst;
- break;
+ return ss7_vty_node_oxs_go_parent(vty);
case L_CS7_SCCPADDR_NODE:
entry = vty->index;
vty->node = L_CS7_NODE;
@@ -3437,20 +1516,8 @@
{
g_ctx = ctx;
- asp_quirk_cmd.string = vty_cmd_string_from_valstr(ctx, asp_quirk_names,
- "quirk (", "|", ")", VTY_DO_LOWER);
- asp_quirk_cmd.doc = vty_cmd_string_from_valstr(ctx, asp_quirk_descs,
- "Enable quirk to work around interop issues\n",
- "\n", "\n", 0);
- asp_no_quirk_cmd.string = vty_cmd_string_from_valstr(ctx, asp_quirk_names,
- "no quirk (", "|", ")", VTY_DO_LOWER);
- asp_no_quirk_cmd.doc = vty_cmd_string_from_valstr(ctx, asp_quirk_descs,
- NO_STR "Disable quirk to work around interop issues\n",
- "\n", "\n", 0);
-
install_lib_element_ve(&show_cs7_user_cmd);
- install_lib_element_ve(&show_cs7_xua_cmd);
- install_lib_element_ve(&show_cs7_xua_trans_proto_cmd);
+ ss7_vty_init_show_oxs();
install_lib_element_ve(&show_cs7_config_cmd);
install_lib_element(ENABLE_NODE, &cs7_asp_disconnect_cmd);
@@ -3469,57 +1536,8 @@
install_lib_element(L_CS7_NODE, &cs7_opc_dpc_shift_cmd);
install_lib_element(L_CS7_NODE, &cs7_sls_shift_cmd);
- install_node(&asp_node, NULL);
- install_lib_element_ve(&show_cs7_asp_cmd);
- install_lib_element_ve(&show_cs7_asp_name_cmd);
- install_lib_element_ve(&show_cs7_asp_remaddr_cmd);
- install_lib_element_ve(&show_cs7_asp_remaddr_name_cmd);
- install_lib_element_ve(&show_cs7_asp_assoc_status_cmd);
- install_lib_element_ve(&show_cs7_asp_assoc_status_name_cmd);
- install_lib_element(L_CS7_NODE, &cs7_asp_cmd);
- install_lib_element(L_CS7_NODE, &cs7_asp_trans_proto_cmd);
- install_lib_element(L_CS7_NODE, &no_cs7_asp_cmd);
- install_lib_element(L_CS7_ASP_NODE, &cfg_description_cmd);
- install_lib_element(L_CS7_ASP_NODE, &asp_remote_ip_cmd);
- install_lib_element(L_CS7_ASP_NODE, &asp_no_remote_ip_cmd);
- install_lib_element(L_CS7_ASP_NODE, &asp_local_ip_cmd);
- install_lib_element(L_CS7_ASP_NODE, &asp_no_local_ip_cmd);
- install_lib_element(L_CS7_ASP_NODE, &asp_qos_class_cmd);
- install_lib_element(L_CS7_ASP_NODE, &asp_role_cmd);
- install_lib_element(L_CS7_ASP_NODE, &asp_transport_role_cmd);
- install_lib_element(L_CS7_ASP_NODE, &asp_sctp_role_cmd);
- install_lib_element(L_CS7_ASP_NODE, &asp_sctp_param_init_cmd);
- install_lib_element(L_CS7_ASP_NODE, &asp_no_sctp_param_init_cmd);
- install_lib_element(L_CS7_ASP_NODE, &asp_quirk_cmd);
- install_lib_element(L_CS7_ASP_NODE, &asp_no_quirk_cmd);
- gen_asp_timer_cmd_strs(&asp_timer_cmd);
- install_lib_element(L_CS7_ASP_NODE, &asp_timer_cmd);
- install_lib_element(L_CS7_ASP_NODE, &asp_block_cmd);
- install_lib_element(L_CS7_ASP_NODE, &asp_shutdown_cmd);
- install_lib_element(L_CS7_ASP_NODE, &asp_no_shutdown_cmd);
-
- install_node(&as_node, NULL);
- install_lib_element_ve(&show_cs7_as_cmd);
- install_lib_element_ve(&show_cs7_as_name_cmd);
- install_lib_element_ve(&show_cs7_as_bindingtable_name_cmd);
- install_lib_element(L_CS7_NODE, &cs7_as_cmd);
- install_lib_element(L_CS7_NODE, &no_cs7_as_cmd);
- install_lib_element(L_CS7_AS_NODE, &cfg_description_cmd);
- install_lib_element(L_CS7_AS_NODE, &as_asp_cmd);
- install_lib_element(L_CS7_AS_NODE, &as_no_asp_cmd);
- install_lib_element(L_CS7_AS_NODE, &as_traf_mode_cmd);
- install_lib_element(L_CS7_AS_NODE, &as_traf_mode_loadshare_cmd);
- install_lib_element(L_CS7_AS_NODE, &as_no_traf_mode_cmd);
- install_lib_element(L_CS7_AS_NODE, &as_sls_shift_cmd);
- install_lib_element(L_CS7_AS_NODE, &as_bindingtable_reset_cmd);
- install_lib_element(L_CS7_AS_NODE, &as_recov_tout_cmd);
- install_lib_element(L_CS7_AS_NODE, &as_qos_class_cmd);
- install_lib_element(L_CS7_AS_NODE, &as_rout_key_cmd);
- install_lib_element(L_CS7_AS_NODE, &as_rout_key_si_cmd);
- install_lib_element(L_CS7_AS_NODE, &as_rout_key_ssn_cmd);
- install_lib_element(L_CS7_AS_NODE, &as_rout_key_si_ssn_cmd);
- install_lib_element(L_CS7_AS_NODE, &as_pc_override_cmd);
- install_lib_element(L_CS7_AS_NODE, &as_pc_patch_sccp_cmd);
+ ss7_vty_init_node_asp();
+ ss7_vty_init_node_as();
install_lib_element_ve(&show_cs7_route_cmd);
install_lib_element_ve(&show_cs7_route_bindingtable_cmd);
@@ -3545,12 +1563,5 @@
install_lib_element(L_CS7_RTABLE_NODE, &cs7_rt_upd_cmd);
install_lib_element(L_CS7_RTABLE_NODE, &cs7_rt_rem_cmd);
- install_node(&xua_node, NULL);
- install_lib_element(L_CS7_NODE, &cs7_xua_cmd);
- install_lib_element(L_CS7_NODE, &no_cs7_xua_cmd);
- install_lib_element(L_CS7_XUA_NODE, &xua_local_ip_cmd);
- install_lib_element(L_CS7_XUA_NODE, &xua_no_local_ip_cmd);
- install_lib_element(L_CS7_XUA_NODE, &xua_accept_dyn_asp_cmd);
- install_lib_element(L_CS7_XUA_NODE, &xua_sctp_param_init_cmd);
- install_lib_element(L_CS7_XUA_NODE, &xua_no_sctp_param_init_cmd);
+ ss7_vty_init_node_oxs();
}
diff --git a/src/ss7_vty.h b/src/ss7_vty.h
new file mode 100644
index 0000000..18dc5a6
--- /dev/null
+++ b/src/ss7_vty.h
@@ -0,0 +1,64 @@
+#pragma once
+
+/* Internal header used by libosmo-sccp, not available publicly for lib users */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <osmocom/vty/vty.h>
+
+#include <osmocom/netif/stream.h>
+#include <osmocom/sigtran/osmo_ss7.h>
+
+#include "ss7_instance.h"
+
+enum cs7_role_t {
+ CS7_ROLE_SG,
+ CS7_ROLE_ASP
+};
+
+extern void *g_ctx;
+extern enum cs7_role_t cs7_role;
+extern const struct value_string ipproto_vals[];
+
+#define CS7_STR "ITU-T Signaling System 7\n"
+#define PC_STR "Point Code\n"
+#define INST_STR "An instance of the SS7 stack\n"
+
+#define XUA_VAR_STR "(sua|m3ua|ipa)"
+
+#define XUA_VAR_HELP_STR \
+ "SCCP User Adaptation\n" \
+ "MTP3 User Adaptation\n" \
+ "IPA Multiplex (SCCP Lite)\n"
+
+#define IPPROTO_VAR_STR "(sctp|tcp)"
+#define IPPROTO_VAR_HELP_STR \
+ "SCTP (Stream Control Transmission Protocol)\n" \
+ "TCP (Transmission Control Protocol)\n"
+
+#define QOS_CLASS_RANGE_STR "<0-7>"
+#define QOS_CLASS_RANGE_HELP_STR "QoS Class\n"
+#define QOS_CLASS_VAR_STR "(" QOS_CLASS_RANGE_STR "|default)"
+#define QOS_CLASS_VAR_HELP_STR \
+ QOS_CLASS_RANGE_HELP_STR \
+ "Default QoS Class (0)\n"
+
+int parse_trans_proto(const char *protocol);
+enum osmo_ss7_asp_protocol parse_asp_proto(const char *protocol);
+
+/* ss7_asp_vty.c */
+void ss7_vty_init_node_asp(void);
+void ss7_vty_write_one_asp(struct vty *vty, struct osmo_ss7_asp *asp, bool
show_dyn_config);
+int ss7_vty_node_asp_go_parent(struct vty *vty);
+
+/* ss7_as_vty.c */
+void ss7_vty_init_node_as(void);
+void ss7_vty_write_one_as(struct vty *vty, struct osmo_ss7_as *as, bool
show_dyn_config);
+int ss7_vty_node_as_go_parent(struct vty *vty);
+
+/* ss7_xua_srv_vty.c */
+void ss7_vty_init_node_oxs(void);
+void ss7_vty_init_show_oxs(void);
+void ss7_vty_write_one_oxs(struct vty *vty, struct osmo_xua_server *xs);
+int ss7_vty_node_oxs_go_parent(struct vty *vty);
diff --git a/src/ss7_xua_srv_vty.c b/src/ss7_xua_srv_vty.c
new file mode 100644
index 0000000..3a5e4ae
--- /dev/null
+++ b/src/ss7_xua_srv_vty.c
@@ -0,0 +1,347 @@
+/* SS7 xua_srv VTY Interface */
+
+/* (C) 2015-2021 by Harald Welte <laforge(a)gnumonks.org>
+ * (C) 2025 by sysmocom s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <osmocom/vty/vty.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/logging.h>
+#include <osmocom/vty/telnet_interface.h>
+#include <osmocom/vty/misc.h>
+
+#include <osmocom/netif/stream.h>
+
+#include <osmocom/sigtran/osmo_ss7.h>
+
+#include "xua_internal.h"
+#include "ss7_asp.h"
+#include "ss7_internal.h"
+#include "ss7_vty.h"
+#include "ss7_xua_srv.h"
+
+/***********************************************************************
+ * xUA Listener Configuration (SG)
+ ***********************************************************************/
+
+static struct cmd_node xua_node = {
+ L_CS7_XUA_NODE,
+ "%s(config-cs7-listen)# ",
+ 1,
+};
+
+DEFUN_ATTR(cs7_xua, cs7_xua_cmd,
+ "listen " XUA_VAR_STR " <0-65534> [" IPPROTO_VAR_STR
"]",
+ "Configure/Enable xUA Listener\n"
+ XUA_VAR_HELP_STR
+ "Port number\n"
+ IPPROTO_VAR_HELP_STR,
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_instance *inst = vty->index;
+ struct osmo_xua_server *xs;
+ enum osmo_ss7_asp_protocol proto = parse_asp_proto(argv[0]);
+ uint16_t port = atoi(argv[1]);
+ int trans_proto;
+
+ if (argc > 2)
+ trans_proto = parse_trans_proto(argv[2]);
+ else /* default transport protocol */
+ trans_proto = ss7_default_trans_proto_for_asp_proto(proto);
+ if (trans_proto < 0)
+ return CMD_WARNING;
+
+ xs = ss7_xua_server_find2(inst, trans_proto, proto, port);
+ if (!xs) {
+ xs = ss7_xua_server_create2(inst, trans_proto, proto, port, NULL);
+ if (!xs)
+ return CMD_WARNING;
+ /* Drop first dummy address created automatically by _create(): */
+ ss7_xua_server_set_local_hosts(xs, NULL, 0);
+ }
+
+ vty->node = L_CS7_XUA_NODE;
+ vty->index = xs;
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(no_cs7_xua, no_cs7_xua_cmd,
+ "no listen " XUA_VAR_STR " <0-65534> [" IPPROTO_VAR_STR
"]",
+ NO_STR "Disable xUA Listener on given port\n"
+ XUA_VAR_HELP_STR
+ "Port number\n"
+ IPPROTO_VAR_HELP_STR,
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_ss7_instance *inst = vty->index;
+ struct osmo_xua_server *xs;
+ enum osmo_ss7_asp_protocol proto = parse_asp_proto(argv[0]);
+ uint16_t port = atoi(argv[1]);
+ int trans_proto;
+
+ if (argc > 2)
+ trans_proto = parse_trans_proto(argv[2]);
+ else /* default transport protocol */
+ trans_proto = ss7_default_trans_proto_for_asp_proto(proto);
+ if (trans_proto < 0)
+ return CMD_WARNING;
+
+ xs = ss7_xua_server_find2(inst, trans_proto, proto, port);
+ if (!xs) {
+ vty_out(vty, "No xUA server for port %u found%s", port, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ ss7_xua_server_destroy(xs);
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(xua_local_ip, xua_local_ip_cmd,
+ "local-ip " VTY_IPV46_CMD,
+ "Configure the Local IP Address for xUA\n"
+ "IPv4 Address to use for XUA\n"
+ "IPv6 Address to use for XUA\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_xua_server *xs = vty->index;
+
+ ss7_xua_server_add_local_host(xs, argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(xua_no_local_ip, xua_no_local_ip_cmd,
+ "no local-ip " VTY_IPV46_CMD,
+ NO_STR "Configure the Local IP Address for xUA\n"
+ "IPv4 Address to use for XUA\n"
+ "IPv6 Address to use for XUA\n",
+ CMD_ATTR_NODE_EXIT)
+{
+ struct osmo_xua_server *xs = vty->index;
+
+ if (ss7_xua_server_del_local_host(xs, argv[0]) != 0) {
+ vty_out(vty, "%% Failed deleting local address '%s' from set%s",
argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(xua_accept_dyn_asp, xua_accept_dyn_asp_cmd,
+ "accept-asp-connections (pre-configured|dynamic-permitted)",
+ "Define what kind of ASP connections to accept\n"
+ "Accept only pre-configured ASPs (source IP/port)\n"
+ "Accept any connection and dynamically create an ASP definition\n",
+ CMD_ATTR_IMMEDIATE)
+{
+ struct osmo_xua_server *xs = vty->index;
+
+ if (!strcmp(argv[0], "dynamic-permitted"))
+ xs->cfg.accept_dyn_reg = true;
+ else
+ xs->cfg.accept_dyn_reg = false;
+
+ return CMD_SUCCESS;
+}
+
+#define XUA_SRV_SCTP_PARAM_INIT_DESC \
+ "Configure SCTP parameters\n" \
+ "Configure INIT related parameters\n" \
+ "Configure INIT Number of Outbound Streams\n" \
+ "Configure INIT Maximum Inboud Streams\n"
+#define XUA_SRV_SCTP_PARAM_INIT_FIELDS "(num-ostreams|max-instreams)"
+
+DEFUN_ATTR(xua_sctp_param_init, xua_sctp_param_init_cmd,
+ "sctp-param init " XUA_SRV_SCTP_PARAM_INIT_FIELDS "
<0-65535>",
+ XUA_SRV_SCTP_PARAM_INIT_DESC
+ "Value of the parameter\n",
+ CMD_ATTR_NODE_EXIT)
+{
+ struct osmo_xua_server *xs = vty->index;
+
+ uint16_t val = atoi(argv[1]);
+
+ if (strcmp(argv[0], "num-ostreams") == 0) {
+ xs->cfg.sctp_init.num_ostreams_present = true;
+ xs->cfg.sctp_init.num_ostreams_value = val;
+ } else if (strcmp(argv[0], "max-instreams") == 0) {
+ xs->cfg.sctp_init.max_instreams_present = true;
+ xs->cfg.sctp_init.max_instreams_value = val;
+ } else {
+ OSMO_ASSERT(0);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN_ATTR(xua_no_sctp_param_init, xua_no_sctp_param_init_cmd,
+ "no sctp-param init " XUA_SRV_SCTP_PARAM_INIT_FIELDS,
+ NO_STR XUA_SRV_SCTP_PARAM_INIT_DESC,
+ CMD_ATTR_NODE_EXIT)
+{
+ struct osmo_xua_server *xs = vty->index;
+
+ if (strcmp(argv[0], "num-ostreams") == 0)
+ xs->cfg.sctp_init.num_ostreams_present = false;
+ else if (strcmp(argv[0], "max-instreams") == 0)
+ xs->cfg.sctp_init.max_instreams_present = false;
+ else
+ OSMO_ASSERT(0);
+ return CMD_SUCCESS;
+}
+
+void ss7_vty_write_one_oxs(struct vty *vty, struct osmo_xua_server *xs)
+{
+ int i;
+
+ vty_out(vty, " listen %s %u",
+ get_value_string(osmo_ss7_asp_protocol_vals, xs->cfg.proto),
+ xs->cfg.local.port);
+ if (xs->cfg.trans_proto != ss7_default_trans_proto_for_asp_proto(xs->cfg.proto))
+ vty_out(vty, " %s", get_value_string(ipproto_vals, xs->cfg.trans_proto));
+ vty_out(vty, "%s", VTY_NEWLINE);
+
+ for (i = 0; i < xs->cfg.local.host_cnt; i++) {
+ if (xs->cfg.local.host[i])
+ vty_out(vty, " local-ip %s%s", xs->cfg.local.host[i], VTY_NEWLINE);
+ }
+ if (xs->cfg.accept_dyn_reg)
+ vty_out(vty, " accept-asp-connections dynamic-permitted%s", VTY_NEWLINE);
+ if (xs->cfg.sctp_init.num_ostreams_present)
+ vty_out(vty, " sctp-param init num-ostreams %u%s",
xs->cfg.sctp_init.num_ostreams_value, VTY_NEWLINE);
+ if (xs->cfg.sctp_init.max_instreams_present)
+ vty_out(vty, " sctp-param init max-instreams %u%s",
xs->cfg.sctp_init.max_instreams_value, VTY_NEWLINE);
+}
+
+static void vty_dump_xua_server(struct vty *vty, struct osmo_xua_server *xs)
+{
+ char buf[OSMO_SOCK_MULTIADDR_PEER_STR_MAXLEN];
+ const char *proto = get_value_string(osmo_ss7_asp_protocol_vals, xs->cfg.proto);
+ int fd = xs->server ? osmo_stream_srv_link_get_fd(xs->server) : -1;
+
+ if (fd < 0) {
+ if (ss7_asp_peer_snprintf(buf, sizeof(buf), &xs->cfg.local) < 0)
+ snprintf(buf, sizeof(buf), "<error>");
+ } else {
+ char hostbuf[OSMO_SOCK_MAX_ADDRS][INET6_ADDRSTRLEN];
+ size_t num_hostbuf = ARRAY_SIZE(hostbuf);
+ char portbuf[6];
+ int rc;
+ rc = osmo_sock_multiaddr_get_ip_and_port(fd, xs->cfg.trans_proto,
+ &hostbuf[0][0], &num_hostbuf, sizeof(hostbuf[0]),
+ portbuf, sizeof(portbuf), true);
+ if (rc < 0) {
+ snprintf(buf, sizeof(buf), "<error>");
+ } else {
+ if (num_hostbuf > ARRAY_SIZE(hostbuf))
+ num_hostbuf = ARRAY_SIZE(hostbuf);
+ osmo_multiaddr_ip_and_port_snprintf(buf, sizeof(buf),
+ &hostbuf[0][0], num_hostbuf, sizeof(hostbuf[0]),
+ portbuf);
+ }
+ }
+ vty_out(vty, "xUA server for %s/%s on %s is %s%s",
+ proto, get_value_string(ipproto_vals, xs->cfg.trans_proto),
+ buf, fd >= 0 ? "listening" : "inactive", VTY_NEWLINE);
+}
+
+static int _show_cs7_xua(struct vty *vty,
+ enum osmo_ss7_asp_protocol proto,
+ int trans_proto, int local_port)
+{
+ const struct osmo_ss7_instance *inst;
+
+ llist_for_each_entry(inst, &osmo_ss7_instances, list) {
+ struct osmo_xua_server *xs;
+
+ llist_for_each_entry(xs, &inst->xua_servers, list) {
+ if (xs->cfg.proto != proto)
+ continue;
+ if (local_port >= 0 && xs->cfg.local.port != local_port) /* optional */
+ continue;
+ if (trans_proto >= 0 && xs->cfg.trans_proto != trans_proto) /* optional
*/
+ continue;
+ vty_dump_xua_server(vty, xs);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+#define SHOW_CS7_XUA_CMD \
+ "show cs7 " XUA_VAR_STR
+#define SHOW_CS7_XUA_CMD_HELP \
+ SHOW_STR CS7_STR XUA_VAR_HELP_STR
+
+DEFUN(show_cs7_xua, show_cs7_xua_cmd,
+ SHOW_CS7_XUA_CMD " [<0-65534>]",
+ SHOW_CS7_XUA_CMD_HELP "Local Port Number\n")
+{
+ enum osmo_ss7_asp_protocol proto = parse_asp_proto(argv[0]);
+ int local_port = (argc > 1) ? atoi(argv[1]) : -1;
+
+ return _show_cs7_xua(vty, proto, -1, local_port);
+}
+
+DEFUN(show_cs7_xua_trans_proto, show_cs7_xua_trans_proto_cmd,
+ SHOW_CS7_XUA_CMD " " IPPROTO_VAR_STR " [<0-65534>]",
+ SHOW_CS7_XUA_CMD_HELP IPPROTO_VAR_HELP_STR "Local Port Number\n")
+{
+ enum osmo_ss7_asp_protocol proto = parse_asp_proto(argv[0]);
+ int trans_proto = parse_trans_proto(argv[1]);
+ int local_port = (argc > 2) ? atoi(argv[2]) : -1;
+
+ return _show_cs7_xua(vty, proto, trans_proto, local_port);
+}
+
+int ss7_vty_node_oxs_go_parent(struct vty *vty)
+{
+ struct osmo_xua_server *oxs = vty->index;
+
+ /* If no local addr was set, or erased after _create(): */
+ ss7_xua_server_set_default_local_hosts(oxs);
+ if (ss7_xua_server_bind(oxs) < 0)
+ vty_out(vty, "%% Unable to bind xUA server to IP(s)%s", VTY_NEWLINE);
+ vty->node = L_CS7_NODE;
+ vty->index = oxs->inst;
+
+ return 0;
+}
+
+void ss7_vty_init_show_oxs(void)
+{
+ install_lib_element_ve(&show_cs7_xua_cmd);
+ install_lib_element_ve(&show_cs7_xua_trans_proto_cmd);
+}
+
+void ss7_vty_init_node_oxs(void)
+{
+ install_node(&xua_node, NULL);
+ install_lib_element(L_CS7_NODE, &cs7_xua_cmd);
+ install_lib_element(L_CS7_NODE, &no_cs7_xua_cmd);
+ install_lib_element(L_CS7_XUA_NODE, &xua_local_ip_cmd);
+ install_lib_element(L_CS7_XUA_NODE, &xua_no_local_ip_cmd);
+ install_lib_element(L_CS7_XUA_NODE, &xua_accept_dyn_asp_cmd);
+ install_lib_element(L_CS7_XUA_NODE, &xua_sctp_param_init_cmd);
+ install_lib_element(L_CS7_XUA_NODE, &xua_no_sctp_param_init_cmd);
+}
--
To view, visit
https://gerrit.osmocom.org/c/libosmo-sigtran/+/40456?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: libosmo-sigtran
Gerrit-Branch: master
Gerrit-Change-Id: I90643bea41098cd6b711e493d4dc9852e88504b1
Gerrit-Change-Number: 40456
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin(a)sysmocom.de>