From 22929b1c04538e0f4ad53698874285bbc3395345 Mon Sep 17 00:00:00 2001 From: Vadim Yanitskiy Date: Tue, 27 Feb 2024 00:29:30 +0700 Subject: 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 --- TODO-RELEASE | 5 + include/osmocom/sigtran/osmo_ss7.h | 42 ++++++- src/osmo_ss7.c | 92 +++++++++++++--- src/osmo_ss7_asp.c | 217 +++++++++++++++++++++++++++++++++++-- src/osmo_ss7_vty.c | 191 +++++++++++++++++++++++--------- src/osmo_ss7_xua_srv.c | 75 ++++++++++--- src/sccp_user.c | 30 +++-- src/ss7_internal.h | 6 +- tests/ss7/ss7_test.c | 3 +- tests/vty/ss7_asp_test.vty | 24 +++- 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, ""); - 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, ""); } 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 ? + + +ss7_asp_vty_test# show cs7 m3ua sctp ? + [<0-65534>] Local Port Number + +ss7_asp_vty_test# show cs7 m3ua sctp 2905 ? + 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) + ss7_asp_vty_test(config-cs7)# as ? NAME Name of the Application Server -- cgit v1.2.3