fixeria has submitted this change. ( 
https://gerrit.osmocom.org/c/libosmo-sccp/+/35796?usp=email )

Change subject: Implement M3UA-over-TCP (in addition to SCTP)
......................................................................

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
---
M TODO-RELEASE
M include/osmocom/sigtran/osmo_ss7.h
M src/osmo_ss7.c
M src/osmo_ss7_asp.c
M src/osmo_ss7_vty.c
M src/osmo_ss7_xua_srv.c
M src/sccp_user.c
M src/ss7_internal.h
M tests/ss7/ss7_test.c
M tests/vty/ss7_asp_test.vty
10 files changed, 597 insertions(+), 115 deletions(-)

Approvals:
  laforge: Looks good to me, approved
  Jenkins Builder: Verified
  pespin: Looks good to me, but someone else must approve




diff --git a/TODO-RELEASE b/TODO-RELEASE
index 25eeb6e..7785711 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -12,3 +12,8 @@
 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 @@
                        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 @@
 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 @@
 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 @@
                        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 @@
 }

 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 @@
        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(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)
+                       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, 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)
 {
-       struct osmo_ss7_asp *asp;
+       const int trans_proto = ss7_default_trans_proto_for_asp_proto(proto);

-       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)
-                       return NULL;
-               return asp;
-       }
-
-       return ss7_asp_alloc(inst, name, remote_port, local_port, 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 @@
        { 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 @@

 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 @@
        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 @@

 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 @@
                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 @@
        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 @@
         * 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 @@
        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 @@
        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 @@
  * 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 @@
 };

 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(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 @@
 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 @@
                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 @@
                                                            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 @@
           "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 @@
        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 @@
        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 @@

        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(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 @@
                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(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 @@
                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 @@
            && !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 @@

        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 @@
        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 @@
        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 @@
                        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 @@
         * 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 @@
 }

 /*! \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 @@

        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_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 @@
        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 @@
        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 @@
                        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 @@
                        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 @@
 {
        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 @@
                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 @@
        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 @@
        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_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 @@
        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 @@
 ... !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 @@
 ... !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 @@
   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 @@
   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)# 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

--
To view, visit https://gerrit.osmocom.org/c/libosmo-sccp/+/35796?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: libosmo-sccp
Gerrit-Branch: master
Gerrit-Change-Id: I8c76d271472befacbeb998a93bbdc9e8660d9b5d
Gerrit-Change-Number: 35796
Gerrit-PatchSet: 9
Gerrit-Owner: fixeria <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <[email protected]>
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: pespin <[email protected]>
Gerrit-CC: jolly <[email protected]>
Gerrit-MessageType: merged

Reply via email to