aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVadim Yanitskiy <vyanitskiy@sysmocom.de>2024-02-27 00:29:30 +0700
committerVadim Yanitskiy <vyanitskiy@sysmocom.de>2024-02-27 00:45:31 +0700
commit22929b1c04538e0f4ad53698874285bbc3395345 (patch)
tree4319278e9bf57fb3fa4804b6b0ac2ed36b8eee51
parent85055b5ca256525bb3c96d2a73ab0cd004295a1c (diff)
Implement M3UA-over-TCP (in addition to SCTP)
RFC 4666 section 1.3.1 states that "TCP MAY be used as the underlying common transport protocol" under certain scenarios. There is even IANA-allocated TCP port 2905 for that purpose (see section 1.4.8). Since TCP is a stream oriented protocol, so we need to handle message boundaries ourselves by reading the M3UA header to know the PDU length. Change-Id: I8c76d271472befacbeb998a93bbdc9e8660d9b5d Related: SYS#5424
-rw-r--r--TODO-RELEASE5
-rw-r--r--include/osmocom/sigtran/osmo_ss7.h42
-rw-r--r--src/osmo_ss7.c92
-rw-r--r--src/osmo_ss7_asp.c217
-rw-r--r--src/osmo_ss7_vty.c191
-rw-r--r--src/osmo_ss7_xua_srv.c75
-rw-r--r--src/sccp_user.c30
-rw-r--r--src/ss7_internal.h6
-rw-r--r--tests/ss7/ss7_test.c3
-rw-r--r--tests/vty/ss7_asp_test.vty24
10 files changed, 575 insertions, 110 deletions
diff --git a/TODO-RELEASE b/TODO-RELEASE
index 25eeb6e..7785711 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -12,3 +12,8 @@ libosmo-netif >1.4.0 osmo_stream_{srv,cli}_get_fd()
libosmocore >1.9.0 osmo_sock_multiaddr_get_ip_and_port(), osmo_multiaddr_ip_and_port_snprintf()
libosmocore >1.9.0 osmo_sock_sctp_get_peer_addr_info()
libosmo-netif >1.4.0 osmo_sctp_spinfo_state_str(), osmo_sctp_sstat_state_str()
+libosmo-sigtran ABI change struct osmo_ss7_asp: new field(s) at the end
+libosmo-sigtran ABI change struct osmo_xua_server: new field(s) at the end
+libosmo-sigtran API added osmo_ss7_asp_get_trans_proto()
+libosmo-sigtran API added osmo_ss7_asp_{find2,find_or_create2}()
+libosmo-sigtran API added osmo_ss7_xua_server_{find2,create2}()
diff --git a/include/osmocom/sigtran/osmo_ss7.h b/include/osmocom/sigtran/osmo_ss7.h
index fc323a8..2324532 100644
--- a/include/osmocom/sigtran/osmo_ss7.h
+++ b/include/osmocom/sigtran/osmo_ss7.h
@@ -453,6 +453,9 @@ struct osmo_ss7_asp {
uint16_t max_attempts_value;
uint16_t max_init_timeo_value; /* ms */
} sctp_init;
+
+ /*! The underlaying transport protocol (one of IPPROTO_*) */
+ int trans_proto;
} cfg;
};
@@ -482,11 +485,21 @@ osmo_ss7_asp_find_by_proto(struct osmo_ss7_as *as,
struct osmo_ss7_asp *
osmo_ss7_asp_find(struct osmo_ss7_instance *inst, const char *name,
uint16_t remote_port, uint16_t local_port,
- enum osmo_ss7_asp_protocol proto);
+ enum osmo_ss7_asp_protocol proto)
+ OSMO_DEPRECATED("Use osmo_ss7_asp_find2() instead");
+struct osmo_ss7_asp *
+osmo_ss7_asp_find2(struct osmo_ss7_instance *inst, const char *name,
+ uint16_t remote_port, uint16_t local_port,
+ int trans_proto, enum osmo_ss7_asp_protocol proto);
struct osmo_ss7_asp *
osmo_ss7_asp_find_or_create(struct osmo_ss7_instance *inst, const char *name,
uint16_t remote_port, uint16_t local_port,
- enum osmo_ss7_asp_protocol proto);
+ enum osmo_ss7_asp_protocol proto)
+ OSMO_DEPRECATED("Use osmo_ss7_asp_find_or_create2() instead");
+struct osmo_ss7_asp *
+osmo_ss7_asp_find_or_create2(struct osmo_ss7_instance *inst, const char *name,
+ uint16_t remote_port, uint16_t local_port,
+ int trans_proto, enum osmo_ss7_asp_protocol proto);
void osmo_ss7_asp_destroy(struct osmo_ss7_asp *asp);
int osmo_ss7_asp_send(struct osmo_ss7_asp *asp, struct msgb *msg);
int osmo_ss7_asp_restart(struct osmo_ss7_asp *asp);
@@ -495,6 +508,7 @@ bool osmo_ss7_asp_active(const struct osmo_ss7_asp *asp);
int osmo_ss7_asp_get_log_subsys(const struct osmo_ss7_asp *asp);
const char *osmo_ss7_asp_get_name(const struct osmo_ss7_asp *asp);
enum osmo_ss7_asp_protocol osmo_ss7_asp_get_proto(const struct osmo_ss7_asp *asp);
+int osmo_ss7_asp_get_trans_proto(const struct osmo_ss7_asp *asp);
/*! Weak function to handle payload for unknown/unsupported PPID or IPA StreamID.
* This function can be overridden by application code to implement whatever handling
@@ -543,16 +557,32 @@ struct osmo_xua_server {
uint16_t num_ostreams_value;
uint16_t max_instreams_value;
} sctp_init;
+
+ /*! The underlaying transport protocol (one of IPPROTO_*) */
+ int trans_proto;
} cfg;
};
struct osmo_xua_server *
-osmo_ss7_xua_server_find(struct osmo_ss7_instance *inst, enum osmo_ss7_asp_protocol proto,
- uint16_t local_port);
+osmo_ss7_xua_server_find(struct osmo_ss7_instance *inst,
+ enum osmo_ss7_asp_protocol proto,
+ uint16_t local_port)
+ OSMO_DEPRECATED("Use osmo_ss7_xua_server_find2() instead");
+struct osmo_xua_server *
+osmo_ss7_xua_server_find2(struct osmo_ss7_instance *inst,
+ int trans_proto,
+ enum osmo_ss7_asp_protocol proto,
+ uint16_t local_port);
struct osmo_xua_server *
-osmo_ss7_xua_server_create(struct osmo_ss7_instance *inst, enum osmo_ss7_asp_protocol proto,
- uint16_t local_port, const char *local_host);
+osmo_ss7_xua_server_create(struct osmo_ss7_instance *inst,
+ enum osmo_ss7_asp_protocol proto,
+ uint16_t local_port, const char *local_host)
+ OSMO_DEPRECATED("Use osmo_ss7_xua_server_create2() instead");
+struct osmo_xua_server *
+osmo_ss7_xua_server_create2(struct osmo_ss7_instance *inst,
+ int trans_proto, enum osmo_ss7_asp_protocol proto,
+ uint16_t local_port, const char *local_host);
int
osmo_ss7_xua_server_bind(struct osmo_xua_server *xs);
diff --git a/src/osmo_ss7.c b/src/osmo_ss7.c
index 50ad172..74b0f50 100644
--- a/src/osmo_ss7.c
+++ b/src/osmo_ss7.c
@@ -1017,9 +1017,9 @@ osmo_ss7_asp_find_by_proto(struct osmo_ss7_as *as,
}
struct osmo_ss7_asp *
-osmo_ss7_asp_find(struct osmo_ss7_instance *inst, const char *name,
- uint16_t remote_port, uint16_t local_port,
- enum osmo_ss7_asp_protocol proto)
+osmo_ss7_asp_find2(struct osmo_ss7_instance *inst, const char *name,
+ uint16_t remote_port, uint16_t local_port,
+ int trans_proto, enum osmo_ss7_asp_protocol proto)
{
struct osmo_ss7_asp *asp;
@@ -1028,47 +1028,107 @@ osmo_ss7_asp_find(struct osmo_ss7_instance *inst, const char *name,
if (!asp)
return NULL;
- if ((asp->cfg.remote.port != remote_port || asp->cfg.local.port != local_port || asp->cfg.proto != proto))
+ if (asp->cfg.remote.port != remote_port || asp->cfg.local.port != local_port)
+ return NULL;
+ if (asp->cfg.trans_proto != trans_proto)
+ return NULL;
+ if (asp->cfg.proto != proto)
return NULL;
return asp;
}
struct osmo_ss7_asp *
-osmo_ss7_asp_find_or_create(struct osmo_ss7_instance *inst, const char *name,
- uint16_t remote_port, uint16_t local_port,
- enum osmo_ss7_asp_protocol proto)
+osmo_ss7_asp_find(struct osmo_ss7_instance *inst, const char *name,
+ uint16_t remote_port, uint16_t local_port,
+ enum osmo_ss7_asp_protocol proto)
+{
+ const int trans_proto = ss7_default_trans_proto_for_asp_proto(proto);
+
+ return osmo_ss7_asp_find2(inst, name,
+ remote_port, local_port,
+ trans_proto, proto);
+}
+
+struct osmo_ss7_asp *
+osmo_ss7_asp_find_or_create2(struct osmo_ss7_instance *inst, const char *name,
+ uint16_t remote_port, uint16_t local_port,
+ int trans_proto, enum osmo_ss7_asp_protocol proto)
{
struct osmo_ss7_asp *asp;
OSMO_ASSERT(ss7_initialized);
asp = osmo_ss7_asp_find_by_name(inst, name);
if (asp) {
- if (asp->cfg.remote.port != remote_port ||
- asp->cfg.local.port != local_port ||
- asp->cfg.proto != proto)
+ if (asp->cfg.remote.port != remote_port || asp->cfg.local.port != local_port)
+ return NULL;
+ if (asp->cfg.trans_proto != trans_proto)
+ return NULL;
+ if (asp->cfg.proto != proto)
return NULL;
return asp;
}
- return ss7_asp_alloc(inst, name, remote_port, local_port, proto);
+ return ss7_asp_alloc(inst, name, remote_port, local_port, trans_proto, proto);
}
+struct osmo_ss7_asp *
+osmo_ss7_asp_find_or_create(struct osmo_ss7_instance *inst, const char *name,
+ uint16_t remote_port, uint16_t local_port,
+ enum osmo_ss7_asp_protocol proto)
+{
+ const int trans_proto = ss7_default_trans_proto_for_asp_proto(proto);
+
+ return osmo_ss7_asp_find_or_create2(inst, name,
+ remote_port, local_port,
+ trans_proto, proto);
+}
+
+/*! \brief find an xUA server with the given parameters
+ * \param[in] inst SS7 Instance on which we operate
+ * \param[in] trans_proto transport protocol in use (one of IPPROTO_*)
+ * \param[in] proto protocol (xUA variant) in use
+ * \param[in] local_port local port of the server
+ * \returns \ref osmo_xua_server or NULL (not found)
+ */
struct osmo_xua_server *
-osmo_ss7_xua_server_find(struct osmo_ss7_instance *inst, enum osmo_ss7_asp_protocol proto,
- uint16_t local_port)
+osmo_ss7_xua_server_find2(struct osmo_ss7_instance *inst,
+ int trans_proto,
+ enum osmo_ss7_asp_protocol proto,
+ uint16_t local_port)
{
struct osmo_xua_server *xs;
OSMO_ASSERT(ss7_initialized);
llist_for_each_entry(xs, &inst->xua_servers, list) {
- if (proto == xs->cfg.proto &&
- local_port == xs->cfg.local.port)
- return xs;
+ if (trans_proto != xs->cfg.trans_proto)
+ continue;
+ if (proto != xs->cfg.proto)
+ continue;
+ if (local_port != xs->cfg.local.port)
+ continue;
+ return xs;
}
+
return NULL;
}
+/*! \brief find an xUA server with the given parameters
+ * \param[in] inst SS7 Instance on which we operate
+ * \param[in] proto protocol (xUA variant) in use
+ * \param[in] local_port local port of the server
+ * \returns \ref osmo_xua_server or NULL (not found)
+ */
+struct osmo_xua_server *
+osmo_ss7_xua_server_find(struct osmo_ss7_instance *inst,
+ enum osmo_ss7_asp_protocol proto,
+ uint16_t local_port)
+{
+ const int trans_proto = ss7_default_trans_proto_for_asp_proto(proto);
+
+ return osmo_ss7_xua_server_find2(inst, trans_proto, proto, local_port);
+}
+
bool osmo_ss7_pc_is_local(struct osmo_ss7_instance *inst, uint32_t pc)
{
OSMO_ASSERT(ss7_initialized);
diff --git a/src/osmo_ss7_asp.c b/src/osmo_ss7_asp.c
index a36d385..f211872 100644
--- a/src/osmo_ss7_asp.c
+++ b/src/osmo_ss7_asp.c
@@ -127,7 +127,32 @@ const struct value_string osmo_ss7_asp_role_names[] = {
{ 0, NULL }
};
-int ss7_asp_proto_to_ip_proto(enum osmo_ss7_asp_protocol proto)
+/* check if the given transport and ASP protocols are compatible (and implemented) */
+bool ss7_asp_protocol_check_trans_proto(enum osmo_ss7_asp_protocol proto, int trans_proto)
+{
+ switch (proto) {
+ case OSMO_SS7_ASP_PROT_IPA:
+ if (trans_proto == IPPROTO_TCP)
+ return true;
+ return false;
+ case OSMO_SS7_ASP_PROT_SUA:
+ if (trans_proto == IPPROTO_SCTP)
+ return true;
+ return false;
+ case OSMO_SS7_ASP_PROT_M3UA:
+ if (trans_proto == IPPROTO_SCTP)
+ return true;
+ if (trans_proto == IPPROTO_TCP)
+ return true;
+ return false;
+ case OSMO_SS7_ASP_PROT_NONE:
+ default:
+ return false;
+ }
+}
+
+/* get _default_ transport protocol for the given ASP protocol */
+int ss7_default_trans_proto_for_asp_proto(enum osmo_ss7_asp_protocol proto)
{
switch (proto) {
case OSMO_SS7_ASP_PROT_IPA:
@@ -503,9 +528,18 @@ ss7_asp_find_by_socket_addr(int fd)
struct osmo_ss7_asp *ss7_asp_alloc(struct osmo_ss7_instance *inst, const char *name,
uint16_t remote_port, uint16_t local_port,
- enum osmo_ss7_asp_protocol proto)
+ int trans_proto, enum osmo_ss7_asp_protocol proto)
{
- struct osmo_ss7_asp *asp = talloc_zero(inst, struct osmo_ss7_asp);
+ struct osmo_ss7_asp *asp;
+
+ if (!ss7_asp_protocol_check_trans_proto(proto, trans_proto)) {
+ LOGP(DLSCCP, LOGL_ERROR,
+ "ASP protocol '%s' with transport protocol %d is not supported",
+ osmo_ss7_asp_protocol_name(proto), trans_proto);
+ return NULL;
+ }
+
+ asp = talloc_zero(inst, struct osmo_ss7_asp);
asp->ctrg = rate_ctr_group_alloc(asp, &ss7_asp_rcgd, g_ss7_asp_rcg_idx++);
if (!asp->ctrg) {
talloc_free(asp);
@@ -517,6 +551,7 @@ struct osmo_ss7_asp *ss7_asp_alloc(struct osmo_ss7_instance *inst, const char *n
asp->cfg.remote.port = remote_port;
osmo_ss7_asp_peer_init(&asp->cfg.local);
asp->cfg.local.port = local_port;
+ asp->cfg.trans_proto = trans_proto;
asp->cfg.proto = proto;
asp->cfg.name = talloc_strdup(asp, name);
@@ -566,6 +601,7 @@ void osmo_ss7_asp_destroy(struct osmo_ss7_asp *asp)
static int xua_cli_read_cb(struct osmo_stream_cli *conn);
static int ipa_cli_read_cb(struct osmo_stream_cli *conn);
+static int m3ua_tcp_cli_read_cb(struct osmo_stream_cli *conn);
static int xua_cli_connect_cb(struct osmo_stream_cli *cli);
int osmo_ss7_asp_restart(struct osmo_ss7_asp *asp)
@@ -601,13 +637,27 @@ int osmo_ss7_asp_restart(struct osmo_ss7_asp *asp)
osmo_stream_cli_set_port(asp->client, asp->cfg.remote.port);
osmo_stream_cli_set_local_addrs(asp->client, (const char **)asp->cfg.local.host, asp->cfg.local.host_cnt);
osmo_stream_cli_set_local_port(asp->client, asp->cfg.local.port);
- osmo_stream_cli_set_proto(asp->client, ss7_asp_proto_to_ip_proto(asp->cfg.proto));
+ osmo_stream_cli_set_proto(asp->client, asp->cfg.trans_proto);
osmo_stream_cli_set_reconnect_timeout(asp->client, 5);
osmo_stream_cli_set_connect_cb(asp->client, xua_cli_connect_cb);
- if (asp->cfg.proto == OSMO_SS7_ASP_PROT_IPA)
+ switch (asp->cfg.proto) {
+ case OSMO_SS7_ASP_PROT_IPA:
+ OSMO_ASSERT(asp->cfg.trans_proto == IPPROTO_TCP);
osmo_stream_cli_set_read_cb(asp->client, ipa_cli_read_cb);
- else
+ break;
+ case OSMO_SS7_ASP_PROT_M3UA:
+ if (asp->cfg.trans_proto == IPPROTO_SCTP)
+ osmo_stream_cli_set_read_cb(asp->client, xua_cli_read_cb);
+ else if (asp->cfg.trans_proto == IPPROTO_TCP)
+ osmo_stream_cli_set_read_cb(asp->client, m3ua_tcp_cli_read_cb);
+ else
+ OSMO_ASSERT(0);
+ break;
+ default:
+ OSMO_ASSERT(asp->cfg.trans_proto == IPPROTO_SCTP);
osmo_stream_cli_set_read_cb(asp->client, xua_cli_read_cb);
+ break;
+ }
osmo_stream_cli_set_data(asp->client, asp);
byte = 1; /*AUTH is needed by ASCONF. enable, don't abort socket creation if AUTH can't be enabled */
osmo_stream_cli_set_param(asp->client, OSMO_STREAM_CLI_PAR_SCTP_SOCKOPT_AUTH_SUPPORTED, &byte, sizeof(byte));
@@ -838,6 +888,78 @@ out:
return rc;
}
+/* netif code tells us we can read something from the socket */
+int ss7_asp_m3ua_tcp_srv_conn_cb(struct osmo_stream_srv *conn)
+{
+ struct osmo_ss7_asp *asp = osmo_stream_srv_get_data(conn);
+ int fd = osmo_stream_srv_get_fd(conn);
+ struct msgb *msg = asp->pending_msg;
+ const struct xua_common_hdr *hdr;
+ size_t msg_length;
+ int rc;
+
+ OSMO_ASSERT(fd >= 0);
+
+ if (msg == NULL) {
+ msg = m3ua_msgb_alloc(__func__);
+ asp->pending_msg = msg;
+ }
+
+ /* read message header first */
+ if (msg->len < sizeof(*hdr)) {
+ errno = 0;
+ rc = recv(fd, msg->tail, sizeof(*hdr) - msg->len, 0);
+ if (rc <= 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0; /* need more data */
+ osmo_stream_srv_destroy(conn);
+ asp->pending_msg = NULL;
+ msgb_free(msg);
+ return rc;
+ }
+
+ msgb_put(msg, rc);
+ if (msg->len < sizeof(*hdr))
+ return 0; /* need more data */
+ }
+
+ hdr = (const struct xua_common_hdr *)msg->data;
+ msg_length = ntohl(hdr->msg_length); /* includes sizeof(*hdr) */
+
+ /* read the rest of the message */
+ if (msg->len < msg_length) {
+ errno = 0;
+ rc = recv(fd, msg->tail, msg_length - msg->len, 0);
+ if (rc <= 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0; /* need more data */
+ osmo_stream_srv_destroy(conn);
+ asp->pending_msg = NULL;
+ msgb_free(msg);
+ return rc;
+ }
+
+ msgb_put(msg, rc);
+ if (msg->len < msg_length)
+ return 0; /* need more data */
+ }
+
+ msg->dst = asp;
+ rate_ctr_inc2(asp->ctrg, SS7_ASP_CTR_PKT_RX_TOTAL);
+
+ /* spoof SCTP Stream ID */
+ if (hdr->msg_class == M3UA_MSGC_XFER)
+ msgb_sctp_stream(msg) = 1;
+ else
+ msgb_sctp_stream(msg) = 0;
+
+ rc = m3ua_rx_msg(asp, msg);
+ asp->pending_msg = NULL;
+ msgb_free(msg);
+
+ return rc;
+}
+
/* client has established SCTP connection to server */
static int xua_cli_connect_cb(struct osmo_stream_cli *cli)
{
@@ -858,7 +980,7 @@ static int xua_cli_connect_cb(struct osmo_stream_cli *cli)
* fed and the local port is known for sure. Apply SCTP Primary addresses
* if needed:
*/
- if (asp->cfg.proto != OSMO_SS7_ASP_PROT_IPA) {
+ if (asp->cfg.trans_proto == IPPROTO_SCTP) {
rc = ss7_asp_apply_peer_primary_address(asp);
rc = ss7_asp_apply_primary_address(asp);
}
@@ -926,6 +1048,78 @@ static int ipa_cli_read_cb(struct osmo_stream_cli *conn)
return ipa_rx_msg(asp, msg, fd & 0xf);
}
+/* read call-back for M3UA-over-TCP socket */
+static int m3ua_tcp_cli_read_cb(struct osmo_stream_cli *conn)
+{
+ struct osmo_ss7_asp *asp = osmo_stream_cli_get_data(conn);
+ int fd = osmo_stream_cli_get_fd(conn);
+ struct msgb *msg = asp->pending_msg;
+ const struct xua_common_hdr *hdr;
+ size_t msg_length;
+ int rc;
+
+ OSMO_ASSERT(fd >= 0);
+
+ if (msg == NULL) {
+ msg = m3ua_msgb_alloc(__func__);
+ asp->pending_msg = msg;
+ }
+
+ /* read message header first */
+ if (msg->len < sizeof(*hdr)) {
+ errno = 0;
+ rc = recv(fd, msg->tail, sizeof(*hdr) - msg->len, 0);
+ if (rc <= 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0; /* need more data */
+ xua_cli_close_and_reconnect(conn);
+ asp->pending_msg = NULL;
+ msgb_free(msg);
+ return rc;
+ }
+
+ msgb_put(msg, rc);
+ if (msg->len < sizeof(*hdr))
+ return 0; /* need more data */
+ }
+
+ hdr = (const struct xua_common_hdr *)msg->data;
+ msg_length = ntohl(hdr->msg_length); /* includes sizeof(*hdr) */
+
+ /* read the rest of the message */
+ if (msg->len < msg_length) {
+ errno = 0;
+ rc = recv(fd, msg->tail, msg_length - msg->len, 0);
+ if (rc <= 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0; /* need more data */
+ xua_cli_close_and_reconnect(conn);
+ asp->pending_msg = NULL;
+ msgb_free(msg);
+ return rc;
+ }
+
+ msgb_put(msg, rc);
+ if (msg->len < msg_length)
+ return 0; /* need more data */
+ }
+
+ msg->dst = asp;
+ rate_ctr_inc2(asp->ctrg, SS7_ASP_CTR_PKT_RX_TOTAL);
+
+ /* spoof SCTP Stream ID */
+ if (hdr->msg_class == M3UA_MSGC_XFER)
+ msgb_sctp_stream(msg) = 1;
+ else
+ msgb_sctp_stream(msg) = 0;
+
+ rc = m3ua_rx_msg(asp, msg);
+ asp->pending_msg = NULL;
+ msgb_free(msg);
+
+ return rc;
+}
+
static int xua_cli_read_cb(struct osmo_stream_cli *conn)
{
struct osmo_ss7_asp *asp = osmo_stream_cli_get_data(conn);
@@ -1135,6 +1329,15 @@ enum osmo_ss7_asp_protocol osmo_ss7_asp_get_proto(const struct osmo_ss7_asp *asp
return asp->cfg.proto;
}
+/*! \brief Get the transport proto of a given ASP
+ * \param[in] asp The ASP for which the transport proto is requested
+ * \returns The transport proto of the ASP (one of IPPROTO_*)
+ */
+int osmo_ss7_asp_get_trans_proto(const struct osmo_ss7_asp *asp)
+{
+ return asp->cfg.trans_proto;
+}
+
/*! \brief Get the fd of a given ASP
* \param[in] asp The ASP for which the fd is requested
* \returns The fd of the ASP if acailable, negative otherwise
diff --git a/src/osmo_ss7_vty.c b/src/osmo_ss7_vty.c
index 33e6e56..42a3383 100644
--- a/src/osmo_ss7_vty.c
+++ b/src/osmo_ss7_vty.c
@@ -62,6 +62,11 @@
"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"
+
/* netinet/tcp.h */
static const struct value_string tcp_info_state_values[] = {
{ TCP_ESTABLISHED, "ESTABLISHED" },
@@ -465,6 +470,17 @@ DEFUN(show_cs7_route, show_cs7_route_cmd,
* 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);
@@ -477,19 +493,29 @@ static struct cmd_node xua_node = {
};
DEFUN_ATTR(cs7_xua, cs7_xua_cmd,
- "listen " XUA_VAR_STR " <0-65534>",
+ "listen " XUA_VAR_STR " <0-65534> [" IPPROTO_VAR_STR "]",
"Configure/Enable xUA Listener\n"
- XUA_VAR_HELP_STR "SCTP Port number\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;
- xs = osmo_ss7_xua_server_find(inst, proto, port);
+ 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 = osmo_ss7_xua_server_find2(inst, trans_proto, proto, port);
if (!xs) {
- xs = osmo_ss7_xua_server_create(inst, proto, port, NULL);
+ xs = osmo_ss7_xua_server_create2(inst, trans_proto, proto, port, NULL);
if (!xs)
return CMD_WARNING;
/* Drop first dummy address created automatically by _create(): */
@@ -502,17 +528,27 @@ DEFUN_ATTR(cs7_xua, cs7_xua_cmd,
}
DEFUN_ATTR(no_cs7_xua, no_cs7_xua_cmd,
- "no listen " XUA_VAR_STR " <0-65534>",
- NO_STR "Disable xUA Listener on given SCTP Port\n"
- XUA_VAR_HELP_STR "SCTP Port number\n",
+ "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;
- xs = osmo_ss7_xua_server_find(inst, proto, port);
+ 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 = osmo_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;
@@ -616,9 +652,13 @@ DEFUN_ATTR(xua_no_sctp_param_init, xua_no_sctp_param_init_cmd,
static void write_one_xua(struct vty *vty, struct osmo_xua_server *xs)
{
int i;
- vty_out(vty, " listen %s %u%s",
+
+ vty_out(vty, " listen %s %u",
get_value_string(osmo_ss7_asp_protocol_vals, xs->cfg.proto),
- xs->cfg.local.port, VTY_NEWLINE);
+ 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])
@@ -646,7 +686,7 @@ static void vty_dump_xua_server(struct vty *vty, struct osmo_xua_server *xs)
size_t num_hostbuf = ARRAY_SIZE(hostbuf);
char portbuf[6];
int rc;
- rc = osmo_sock_multiaddr_get_ip_and_port(fd, ss7_asp_proto_to_ip_proto(xs->cfg.proto),
+ 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) {
@@ -659,37 +699,60 @@ static void vty_dump_xua_server(struct vty *vty, struct osmo_xua_server *xs)
portbuf);
}
}
- vty_out(vty, "xUA server for %s on %s is %s%s",
- proto, buf, fd >= 0 ? "listening" : "inactive", VTY_NEWLINE);
+ 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);
}
-DEFUN(show_cs7_xua, show_cs7_xua_cmd,
- "show cs7 "XUA_VAR_STR" [<0-65534>]",
- SHOW_STR CS7_STR XUA_VAR_HELP_STR "Port Number")
+static int _show_cs7_xua(struct vty *vty,
+ enum osmo_ss7_asp_protocol proto,
+ int trans_proto, int local_port)
{
- struct osmo_ss7_instance *inst;
- struct osmo_xua_server *xs;
- enum osmo_ss7_asp_protocol proto = parse_asp_proto(argv[0]);
+ const struct osmo_ss7_instance *inst;
llist_for_each_entry(inst, &osmo_ss7_instances, list) {
- if (argc > 1) {
- int port = atoi(argv[1]);
- xs = osmo_ss7_xua_server_find(inst, proto, port);
- if (!xs) {
- vty_out(vty, "%% No matching server found%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
+ 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);
- } else {
- llist_for_each_entry(xs, &inst->xua_servers, list) {
- if (xs->cfg.proto == proto)
- 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")
@@ -738,8 +801,8 @@ 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 SCTP port number\n"
- "Local SCTP port number\n"
+ "Remote port number\n"
+ "Local port number\n"
XUA_VAR_HELP_STR,
CMD_ATTR_NODE_EXIT)
{
@@ -747,17 +810,30 @@ DEFUN_ATTR(cs7_asp, cs7_asp_cmd,
const char *name = argv[0];
uint16_t remote_port = atoi(argv[1]);
uint16_t local_port = atoi(argv[2]);
- enum osmo_ss7_asp_protocol protocol = parse_asp_proto(argv[3]);
+ enum osmo_ss7_asp_protocol proto = parse_asp_proto(argv[3]);
struct osmo_ss7_asp *asp;
+ int trans_proto;
- if (protocol == OSMO_SS7_ASP_PROT_NONE) {
+ if (proto == OSMO_SS7_ASP_PROT_NONE) {
vty_out(vty, "invalid protocol '%s'%s", argv[3], VTY_NEWLINE);
return CMD_WARNING;
}
- asp = osmo_ss7_asp_find(inst, name, remote_port, local_port, protocol);
+ /* 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_create(inst, name, remote_port, local_port, protocol);
+ 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;
@@ -772,6 +848,18 @@ DEFUN_ATTR(cs7_asp, cs7_asp_cmd,
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"
@@ -1217,10 +1305,10 @@ static void show_one_asp(struct vty *vty, struct osmo_ss7_asp *asp)
int fd = ss7_asp_get_fd(asp);
if (fd > 0) {
- int proto = ss7_asp_proto_to_ip_proto(asp->cfg.proto);
- if (!get_sockname_buf(buf_loc, sizeof(buf_loc), fd, proto, true))
+ 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, proto, false))
+ if (!get_sockname_buf(buf_rem, sizeof(buf_rem), fd, trans_proto, false))
OSMO_STRLCPY_ARRAY(buf_rem, "<sockname-error>");
} else {
osmo_ss7_asp_peer_snprintf(buf_loc, sizeof(buf_loc), &asp->cfg.local);
@@ -1374,9 +1462,7 @@ static void show_one_asp_remaddr_sctp(struct vty *vty, struct osmo_ss7_asp *asp)
static void show_one_asp_remaddr(struct vty *vty, struct osmo_ss7_asp *asp)
{
- int proto = ss7_asp_proto_to_ip_proto(asp->cfg.proto);
-
- switch (proto) {
+ switch (asp->cfg.trans_proto) {
case IPPROTO_TCP:
show_one_asp_remaddr_tcp(vty, asp);
break;
@@ -1386,7 +1472,8 @@ static void show_one_asp_remaddr(struct vty *vty, struct osmo_ss7_asp *asp)
break;
#endif
default:
- vty_out(vty, "%-12s %-46s unknown proto %u%s", asp->cfg.name, "", proto, VTY_NEWLINE);
+ vty_out(vty, "%-12s %-46s unknown proto %d%s",
+ asp->cfg.name, "", asp->cfg.trans_proto, VTY_NEWLINE);
break;
}
}
@@ -1530,9 +1617,7 @@ static void show_one_asp_assoc_status_sctp(struct vty *vty, struct osmo_ss7_asp
static void show_one_asp_assoc_status(struct vty *vty, struct osmo_ss7_asp *asp)
{
- int proto = ss7_asp_proto_to_ip_proto(asp->cfg.proto);
-
- switch (proto) {
+ switch (asp->cfg.trans_proto) {
case IPPROTO_TCP:
show_one_asp_assoc_status_tcp(vty, asp);
break;
@@ -1542,7 +1627,8 @@ static void show_one_asp_assoc_status(struct vty *vty, struct osmo_ss7_asp *asp)
break;
#endif
default:
- vty_out(vty, "%-12s unknown proto %u%s", asp->cfg.name, proto, VTY_NEWLINE);
+ vty_out(vty, "%-12s unknown proto %d%s",
+ asp->cfg.name, asp->cfg.trans_proto, VTY_NEWLINE);
break;
}
}
@@ -1611,9 +1697,12 @@ static void write_one_asp(struct vty *vty, struct osmo_ss7_asp *asp, bool show_d
&& !show_dyn_config)
return;
- vty_out(vty, " asp %s %u %u %s%s",
+ 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), VTY_NEWLINE);
+ 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++) {
@@ -2862,6 +2951,7 @@ static void vty_init_shared(void *ctx)
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);
install_lib_element_ve(&show_cs7_config_cmd);
install_lib_element(ENABLE_NODE, &cs7_asp_disconnect_cmd);
@@ -2885,6 +2975,7 @@ static void vty_init_shared(void *ctx)
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);
diff --git a/src/osmo_ss7_xua_srv.c b/src/osmo_ss7_xua_srv.c
index 32266ff..0b83b19 100644
--- a/src/osmo_ss7_xua_srv.c
+++ b/src/osmo_ss7_xua_srv.c
@@ -67,19 +67,32 @@ static int xua_accept_cb(struct osmo_stream_srv_link *link, int fd)
struct osmo_ss7_asp *asp;
char *sock_name = osmo_sock_get_name(link, fd);
const char *proto_name = get_value_string(osmo_ss7_asp_protocol_vals, oxs->cfg.proto);
+ int (*read_cb)(struct osmo_stream_srv *conn) = NULL;
int rc = 0;
LOGP(DLSS7, LOGL_INFO, "%s: New %s connection accepted\n", sock_name, proto_name);
- if (oxs->cfg.proto == OSMO_SS7_ASP_PROT_IPA) {
- srv = osmo_stream_srv_create(oxs, link, fd,
- ss7_asp_ipa_srv_conn_cb,
- ss7_asp_xua_srv_conn_closed_cb, NULL);
- } else {
- srv = osmo_stream_srv_create(oxs, link, fd,
- ss7_asp_xua_srv_conn_cb,
- ss7_asp_xua_srv_conn_closed_cb, NULL);
+ switch (oxs->cfg.proto) {
+ case OSMO_SS7_ASP_PROT_IPA:
+ OSMO_ASSERT(oxs->cfg.trans_proto == IPPROTO_TCP);
+ read_cb = &ss7_asp_ipa_srv_conn_cb;
+ break;
+ case OSMO_SS7_ASP_PROT_M3UA:
+ if (oxs->cfg.trans_proto == IPPROTO_SCTP)
+ read_cb = &ss7_asp_xua_srv_conn_cb;
+ else if (oxs->cfg.trans_proto == IPPROTO_TCP)
+ read_cb = &ss7_asp_m3ua_tcp_srv_conn_cb;
+ else
+ OSMO_ASSERT(0);
+ break;
+ default:
+ OSMO_ASSERT(oxs->cfg.trans_proto == IPPROTO_SCTP);
+ read_cb = &ss7_asp_xua_srv_conn_cb;
+ break;
}
+
+ srv = osmo_stream_srv_create(oxs, link, fd, read_cb,
+ &ss7_asp_xua_srv_conn_closed_cb, NULL);
if (!srv) {
LOGP(DLSS7, LOGL_ERROR, "%s: Unable to create stream server "
"for connection\n", sock_name);
@@ -112,8 +125,9 @@ static int xua_accept_cb(struct osmo_stream_srv_link *link, int fd)
char namebuf[32];
static uint32_t dyn_asp_num = 0;
snprintf(namebuf, sizeof(namebuf), "asp-dyn-%u", dyn_asp_num++);
- asp = osmo_ss7_asp_find_or_create(oxs->inst, namebuf, 0, 0,
- oxs->cfg.proto);
+ asp = osmo_ss7_asp_find_or_create2(oxs->inst, namebuf, 0, 0,
+ oxs->cfg.trans_proto,
+ oxs->cfg.proto);
if (asp) {
char hostbuf[INET6_ADDRSTRLEN];
const char *hostbuf_ptr = &hostbuf[0];
@@ -157,7 +171,7 @@ static int xua_accept_cb(struct osmo_stream_srv_link *link, int fd)
* data */
osmo_stream_srv_set_data(srv, asp);
- if (oxs->cfg.proto != OSMO_SS7_ASP_PROT_IPA) {
+ if (oxs->cfg.trans_proto == IPPROTO_SCTP) {
rc = ss7_asp_apply_peer_primary_address(asp);
rc = ss7_asp_apply_primary_address(asp);
}
@@ -170,19 +184,29 @@ static int xua_accept_cb(struct osmo_stream_srv_link *link, int fd)
}
/*! \brief create a new xUA server configured with given ip/port
- * \param[in] ctx talloc allocation context
+ * \param[in] inst SS7 Instance on which we operate
+ * \param[in] trans_proto transport protocol to use (one of IPPROTO_*)
* \param[in] proto protocol (xUA variant) to use
* \param[in] local_port local SCTP port to bind/listen to
* \param[in] local_host local IP address to bind/listen to (optional)
* \returns callee-allocated \ref osmo_xua_server in case of success
*/
struct osmo_xua_server *
-osmo_ss7_xua_server_create(struct osmo_ss7_instance *inst, enum osmo_ss7_asp_protocol proto,
- uint16_t local_port, const char *local_host)
+osmo_ss7_xua_server_create2(struct osmo_ss7_instance *inst,
+ int trans_proto, enum osmo_ss7_asp_protocol proto,
+ uint16_t local_port, const char *local_host)
{
- struct osmo_xua_server *oxs = talloc_zero(inst, struct osmo_xua_server);
+ struct osmo_xua_server *oxs;
+
+ if (!ss7_asp_protocol_check_trans_proto(proto, trans_proto)) {
+ LOGP(DLSCCP, LOGL_ERROR,
+ "ASP protocol '%s' with transport protocol %d is not supported",
+ osmo_ss7_asp_protocol_name(proto), trans_proto);
+ return NULL;
+ }
OSMO_ASSERT(ss7_initialized);
+ oxs = talloc_zero(inst, struct osmo_xua_server);
if (!oxs)
return NULL;
@@ -191,6 +215,7 @@ osmo_ss7_xua_server_create(struct osmo_ss7_instance *inst, enum osmo_ss7_asp_pro
INIT_LLIST_HEAD(&oxs->asp_list);
+ oxs->cfg.trans_proto = trans_proto;
oxs->cfg.proto = proto;
oxs->cfg.local.port = local_port;
@@ -201,7 +226,7 @@ osmo_ss7_xua_server_create(struct osmo_ss7_instance *inst, enum osmo_ss7_asp_pro
osmo_stream_srv_link_set_nodelay(oxs->server, true);
osmo_stream_srv_link_set_port(oxs->server, oxs->cfg.local.port);
- osmo_stream_srv_link_set_proto(oxs->server, ss7_asp_proto_to_ip_proto(proto));
+ osmo_stream_srv_link_set_proto(oxs->server, trans_proto);
osmo_ss7_xua_server_set_local_host(oxs, local_host);
@@ -218,6 +243,24 @@ osmo_ss7_xua_server_create(struct osmo_ss7_instance *inst, enum osmo_ss7_asp_pro
return oxs;
}
+/*! \brief create a new xUA server configured with given ip/port
+ * \param[in] ctx talloc allocation context
+ * \param[in] proto protocol (xUA variant) to use
+ * \param[in] local_port local SCTP port to bind/listen to
+ * \param[in] local_host local IP address to bind/listen to (optional)
+ * \returns callee-allocated \ref osmo_xua_server in case of success
+ */
+struct osmo_xua_server *
+osmo_ss7_xua_server_create(struct osmo_ss7_instance *inst,
+ enum osmo_ss7_asp_protocol proto,
+ uint16_t local_port, const char *local_host)
+{
+ const int trans_proto = ss7_default_trans_proto_for_asp_proto(proto);
+
+ return osmo_ss7_xua_server_create2(inst, trans_proto, proto,
+ local_port, local_host);
+}
+
/*! \brief Set the xUA server to bind/listen to the currently configured ip/port
* \param[in] xs xUA server to operate
* \returns 0 on success, negative value on error.
diff --git a/src/sccp_user.c b/src/sccp_user.c
index 94b6d02..b72b2a6 100644
--- a/src/sccp_user.c
+++ b/src/sccp_user.c
@@ -515,6 +515,9 @@ osmo_sccp_simple_client_on_ss7_id(void *ctx, uint32_t ss7_id, const char *name,
struct osmo_ss7_asp *asp;
bool asp_created = false;
char *as_name, *asp_name = NULL;
+ int trans_proto;
+
+ trans_proto = ss7_default_trans_proto_for_asp_proto(prot);
/*! The function will examine the given CS7 instance and its sub
* components (as, asp, etc.). If necessary it will allocate
@@ -625,11 +628,10 @@ osmo_sccp_simple_client_on_ss7_id(void *ctx, uint32_t ss7_id, const char *name,
asp_name = talloc_asprintf(ctx, "asp-clnt-%s", name);
LOGP(DLSCCP, LOGL_NOTICE, "%s: No unassociated ASP for %s, creating new ASP %s\n",
name, osmo_ss7_asp_protocol_name(prot), asp_name);
- asp =
- osmo_ss7_asp_find_or_create(ss7, asp_name,
- default_remote_port,
- default_local_port,
- prot);
+ asp = osmo_ss7_asp_find_or_create2(ss7, asp_name,
+ default_remote_port,
+ default_local_port,
+ trans_proto, prot);
talloc_free(asp_name);
if (!asp)
goto out_rt;
@@ -678,7 +680,9 @@ osmo_sccp_simple_client_on_ss7_id(void *ctx, uint32_t ss7_id, const char *name,
LOGP(DLSCCP, LOGL_NOTICE,
"%s: Requesting an SCCP simple client on ASP %s configured with 'sctp-role server'\n",
name, asp->cfg.name);
- xs = osmo_ss7_xua_server_find(ss7, prot, asp->cfg.local.port);
+ xs = osmo_ss7_xua_server_find2(ss7,
+ asp->cfg.trans_proto, prot,
+ asp->cfg.local.port);
if (!xs) {
LOGP(DLSCCP, LOGL_ERROR, "%s: Requesting an SCCP simple client on ASP %s configured "
"with 'sctp-role server' but no matching xUA server was configured!\n",
@@ -755,8 +759,11 @@ osmo_sccp_simple_server_on_ss7_id(void *ctx, uint32_t ss7_id, uint32_t pc,
{
struct osmo_ss7_instance *ss7;
struct osmo_xua_server *xs;
+ int trans_proto;
int rc;
+ trans_proto = ss7_default_trans_proto_for_asp_proto(prot);
+
if (local_port < 0)
local_port = osmo_ss7_asp_protocol_port(prot);
@@ -766,7 +773,7 @@ osmo_sccp_simple_server_on_ss7_id(void *ctx, uint32_t ss7_id, uint32_t pc,
return NULL;
ss7->cfg.primary_pc = pc;
- xs = osmo_ss7_xua_server_create(ss7, prot, local_port, local_ip);
+ xs = osmo_ss7_xua_server_create2(ss7, trans_proto, prot, local_port, local_ip);
if (!xs)
goto out_ss7;
@@ -811,6 +818,9 @@ osmo_sccp_simple_server_add_clnt(struct osmo_sccp_instance *inst,
struct osmo_ss7_asp *asp;
struct osmo_xua_server *oxs;
char *as_name, *asp_name;
+ int trans_proto;
+
+ trans_proto = ss7_default_trans_proto_for_asp_proto(prot);
if (local_port < 0)
local_port = osmo_ss7_asp_protocol_port(prot);
@@ -831,10 +841,12 @@ osmo_sccp_simple_server_add_clnt(struct osmo_sccp_instance *inst,
if (!rt)
goto out_as;
- asp = osmo_ss7_asp_find_or_create(ss7, asp_name, remote_port, local_port, prot);
+ asp = osmo_ss7_asp_find_or_create2(ss7, asp_name,
+ remote_port, local_port,
+ trans_proto, prot);
if (!asp)
goto out_rt;
- oxs = osmo_ss7_xua_server_find(ss7, prot, local_port);
+ oxs = osmo_ss7_xua_server_find2(ss7, asp->cfg.trans_proto, prot, local_port);
if (!oxs)
goto out_asp;
if (osmo_ss7_asp_peer_set_hosts(&asp->cfg.local, asp,
diff --git a/src/ss7_internal.h b/src/ss7_internal.h
index fd01ca4..ed4fae7 100644
--- a/src/ss7_internal.h
+++ b/src/ss7_internal.h
@@ -16,15 +16,17 @@ struct osmo_ss7_as *ss7_as_alloc(struct osmo_ss7_instance *inst, const char *nam
struct osmo_ss7_asp *ss7_asp_alloc(struct osmo_ss7_instance *inst, const char *name,
uint16_t remote_port, uint16_t local_port,
- enum osmo_ss7_asp_protocol proto);
+ int trans_proto, enum osmo_ss7_asp_protocol proto);
bool ss7_asp_set_default_peer_hosts(struct osmo_ss7_asp *asp);
bool ss7_asp_is_started(const struct osmo_ss7_asp *asp);
int ss7_asp_get_fd(const struct osmo_ss7_asp *asp);
struct osmo_ss7_asp *ss7_asp_find_by_socket_addr(int fd);
-int ss7_asp_proto_to_ip_proto(enum osmo_ss7_asp_protocol proto);
+bool ss7_asp_protocol_check_trans_proto(enum osmo_ss7_asp_protocol proto, int trans_proto);
+int ss7_default_trans_proto_for_asp_proto(enum osmo_ss7_asp_protocol proto);
int ss7_asp_ipa_srv_conn_cb(struct osmo_stream_srv *conn);
int ss7_asp_xua_srv_conn_cb(struct osmo_stream_srv *conn);
+int ss7_asp_m3ua_tcp_srv_conn_cb(struct osmo_stream_srv *conn);
int ss7_asp_xua_srv_conn_closed_cb(struct osmo_stream_srv *srv);
int ss7_asp_apply_peer_primary_address(const struct osmo_ss7_asp *asp);
int ss7_asp_apply_primary_address(const struct osmo_ss7_asp *asp);
diff --git a/tests/ss7/ss7_test.c b/tests/ss7/ss7_test.c
index cf48b89..ad8dc77 100644
--- a/tests/ss7/ss7_test.c
+++ b/tests/ss7/ss7_test.c
@@ -248,7 +248,8 @@ static void test_as(void)
OSMO_ASSERT(osmo_ss7_as_find_by_rctx(s7i, 2342) == as);
OSMO_ASSERT(osmo_ss7_as_add_asp(as, "asp1") == -ENODEV);
- asp = osmo_ss7_asp_find_or_create(s7i, "asp1", 0, M3UA_PORT, OSMO_SS7_ASP_PROT_M3UA);
+ asp = osmo_ss7_asp_find_or_create2(s7i, "asp1", 0, M3UA_PORT,
+ IPPROTO_SCTP, OSMO_SS7_ASP_PROT_M3UA);
OSMO_ASSERT(asp);
OSMO_ASSERT(osmo_ss7_as_has_asp(as, asp) == false);
diff --git a/tests/vty/ss7_asp_test.vty b/tests/vty/ss7_asp_test.vty
index d91df24..7b36009 100644
--- a/tests/vty/ss7_asp_test.vty
+++ b/tests/vty/ss7_asp_test.vty
@@ -2,6 +2,7 @@ ss7_asp_vty_test> list
... !show cs7
show cs7 instance <0-15> users
show cs7 (sua|m3ua|ipa) [<0-65534>]
+ show cs7 (sua|m3ua|ipa) (sctp|tcp) [<0-65534>]
show cs7 config
show cs7 instance <0-15> asp
show cs7 instance <0-15> asp name ASP_NAME
@@ -23,6 +24,7 @@ ss7_asp_vty_test# list
... !show cs7
show cs7 instance <0-15> users
show cs7 (sua|m3ua|ipa) [<0-65534>]
+ show cs7 (sua|m3ua|ipa) (sctp|tcp) [<0-65534>]
show cs7 config
cs7 instance <0-15> asp NAME disconnect
show cs7 instance <0-15> asp
@@ -53,7 +55,18 @@ ss7_asp_vty_test# show cs7 ?
config Currently running cs7 configuration
ss7_asp_vty_test# show cs7 m3ua ?
- [<0-65534>] Port Number
+ [<0-65534>] Local Port Number
+ sctp SCTP (Stream Control Transmission Protocol)
+ tcp TCP (Transmission Control Protocol)
+
+ss7_asp_vty_test# show cs7 m3ua 2905 ?
+ <cr>
+
+ss7_asp_vty_test# show cs7 m3ua sctp ?
+ [<0-65534>] Local Port Number
+
+ss7_asp_vty_test# show cs7 m3ua sctp 2905 ?
+ <cr>
ss7_asp_vty_test# show cs7 instance ?
<0-15> An instance of the SS7 stack
@@ -96,6 +109,7 @@ ss7_asp_vty_test(config-cs7)# list
point-code delimiter (default|dash)
xua rkm routing-key-allocation (static-only|dynamic-permitted)
asp NAME <0-65535> <0-65535> (sua|m3ua|ipa)
+ asp NAME <0-65535> <0-65535> (sua|m3ua|ipa) (sctp|tcp)
no asp NAME
as NAME (sua|m3ua|ipa)
no as NAME
@@ -154,13 +168,17 @@ ss7_asp_vty_test(config-cs7)# xua rkm routing-key-allocation ?
ss7_asp_vty_test(config-cs7)# asp ?
NAME Name of ASP
ss7_asp_vty_test(config-cs7)# asp foo ?
- <0-65535> Remote SCTP port number
+ <0-65535> Remote port number
ss7_asp_vty_test(config-cs7)# asp foo 0 ?
- <0-65535> Local SCTP port number
+ <0-65535> Local port number
ss7_asp_vty_test(config-cs7)# asp foo 0 0 ?
sua SCCP User Adaptation
m3ua MTP3 User Adaptation
ipa IPA Multiplex (SCCP Lite)
+ss7_asp_vty_test(config-cs7)# asp foo 0 0 m3ua ?
+ sctp SCTP (Stream Control Transmission Protocol)
+ tcp TCP (Transmission Control Protocol)
+ <cr>
ss7_asp_vty_test(config-cs7)# as ?
NAME Name of the Application Server