aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2021-02-08 17:46:08 +0100
committerHarald Welte <laforge@osmocom.org>2021-02-10 19:58:38 +0100
commitafbcc5d532fe9ccfd82d15423796ca1a39a37393 (patch)
treef9b5de76d19c99c5cc891a8ddbfa9af3fec012d8
parent7daae9bd67215888c7d5e201ea2261fb6c8fbb2b (diff)
xua_snm: Implement handling of DUPU messages
A DUPU message in SUA and M3UA indicates the unavailability of a (MTP-level) user, i.e. the entire SCCP, ISUP, ... is not available. If we receive a DUPU (destination user part unavailable) message in ASP role, then we must * distribute it to any other ASPs for which we operate in SG mode * pass it as MTP-STATUS.ind to SCCP, which can then generates N-PCSTATE.ind to the SCCP User Change-Id: I1559ed0f761a8495b222df48c6bd43798e220471
-rw-r--r--include/osmocom/sigtran/protocol/mtp.h15
-rw-r--r--src/m3ua.c40
-rw-r--r--src/osmo_ss7.c7
-rw-r--r--src/sccp_internal.h2
-rw-r--r--src/sccp_scmg.c33
-rw-r--r--src/sua.c39
-rw-r--r--src/xua_internal.h5
-rw-r--r--src/xua_snm.c82
8 files changed, 222 insertions, 1 deletions
diff --git a/include/osmocom/sigtran/protocol/mtp.h b/include/osmocom/sigtran/protocol/mtp.h
index 8b990c0..2f0c7ac 100644
--- a/include/osmocom/sigtran/protocol/mtp.h
+++ b/include/osmocom/sigtran/protocol/mtp.h
@@ -22,3 +22,18 @@ enum mtp_si_ni00 {
};
extern const struct value_string mtp_si_vals[];
+
+
+/* Chapter 15.17.5 of Q.705 */
+enum mtp_unavail_cause {
+ MTP_UNAVAIL_C_UNKNOWN = 0x0,
+ MTP_UNAVAIL_C_UNEQUIP_REM_USER = 0x1,
+ MTP_UNAVAIL_C_INACC_REM_USER = 0x2,
+ /* reserved */
+};
+
+extern const struct value_string mtp_unavail_cause_vals[];
+
+static inline const char *mtp_unavail_cause_str(enum mtp_unavail_cause cs) {
+ return get_value_string(mtp_unavail_cause_vals, cs);
+}
diff --git a/src/m3ua.c b/src/m3ua.c
index 6639c28..77326e0 100644
--- a/src/m3ua.c
+++ b/src/m3ua.c
@@ -812,8 +812,29 @@ static struct xua_msg *m3ua_encode_daud(const uint32_t *rctx, unsigned int num_r
}
#endif
+/* 3.4.5 Destination User Part Unavailable (DUPU) */
+static struct xua_msg *m3ua_encode_dupu(const uint32_t *rctx, unsigned int num_rctx,
+ uint32_t dpc, uint16_t user, uint16_t cause,
+ const char *info_string)
+{
+ struct xua_msg *xua = xua_msg_alloc();
+ uint32_t user_cause = (user << 16) | cause;
+
+ xua->hdr = XUA_HDR(M3UA_MSGC_SNM, M3UA_SNM_DUNA);
+ xua->hdr.version = M3UA_VERSION;
+ if (rctx)
+ xua_msg_add_data(xua, M3UA_IEI_ROUTE_CTX, num_rctx * sizeof(*rctx), (const uint8_t *)rctx);
+
+ xua_msg_add_u32(xua, M3UA_IEI_AFFECTED_PC, dpc);
+ xua_msg_add_u32(xua, M3UA_IEI_USER_CAUSE, user_cause);
-/* TODO: 3.4.5 Destination User Part Unavailable (DUPU) */
+ if (info_string) {
+ xua_msg_add_data(xua, M3UA_IEI_INFO_STRING,
+ strlen(info_string)+1,
+ (const uint8_t *) info_string);
+ }
+ return xua;
+}
/*! Transmit SSNM DUNA/DAVA message indicating [un]availability of certain point code[s]
* \param[in] asp ASP through which to transmit message. Must be ACTIVE.
@@ -837,6 +858,21 @@ void m3ua_tx_snm_available(struct osmo_ss7_asp *asp, const uint32_t *rctx, unsig
m3ua_tx_xua_asp(asp, xua);
}
+/*! Transmit SSNM DUPU message indicating user unavailability.
+ * \param[in] asp ASP through which to transmit message. Must be ACTIVE.
+ * \param[in] rctx array of Routing Contexts in network byte order.
+ * \param[in] num_rctx number of rctx
+ * \param[in] dpc affected point code
+ * \param[in] user the user (SI) that is unavailable
+ * \param[in] cause the cause of the user unavailability
+ * \param[in] info_string optional information string (can be NULL). */
+void m3ua_tx_dupu(struct osmo_ss7_asp *asp, const uint32_t *rctx, unsigned int num_rctx,
+ uint32_t dpc, uint16_t user, uint16_t cause, const char *info_str)
+{
+ struct xua_msg *xua = m3ua_encode_dupu(rctx, num_rctx, dpc, user, cause, info_str);
+ m3ua_tx_xua_asp(asp, xua);
+}
+
/* received SNM message on ASP side */
static int m3ua_rx_snm_asp(struct osmo_ss7_asp *asp, struct xua_msg *xua)
{
@@ -857,6 +893,8 @@ static int m3ua_rx_snm_asp(struct osmo_ss7_asp *asp, struct xua_msg *xua)
xua_snm_rx_dava(asp, as, xua);
break;
case M3UA_SNM_DUPU:
+ xua_snm_rx_dupu(asp, as, xua);
+ break;
case M3UA_SNM_SCON:
case M3UA_SNM_DRST:
LOGPASP(asp, DLM3UA, LOGL_NOTICE, "Received unsupported M3UA SNM message type %u\n",
diff --git a/src/osmo_ss7.c b/src/osmo_ss7.c
index e549708..a801cc9 100644
--- a/src/osmo_ss7.c
+++ b/src/osmo_ss7.c
@@ -59,6 +59,13 @@ LLIST_HEAD(osmo_ss7_instances);
static int32_t next_rctx = 1;
static int32_t next_l_rk_id = 1;
+const struct value_string mtp_unavail_cause_vals[] = {
+ { MTP_UNAVAIL_C_UNKNOWN, "unknown" },
+ { MTP_UNAVAIL_C_UNEQUIP_REM_USER, "unequipped-remote-user" },
+ { MTP_UNAVAIL_C_INACC_REM_USER, "inaccessible-remote-user" },
+ { 0, NULL }
+};
+
struct value_string osmo_ss7_as_traffic_mode_vals[] = {
{ OSMO_SS7_AS_TMOD_BCAST, "broadcast" },
{ OSMO_SS7_AS_TMOD_LOADSHARE, "loadshare" },
diff --git a/src/sccp_internal.h b/src/sccp_internal.h
index a95b07d..23b3ef3 100644
--- a/src/sccp_internal.h
+++ b/src/sccp_internal.h
@@ -4,6 +4,7 @@
#include <osmocom/core/prim.h>
#include <osmocom/sigtran/sccp_sap.h>
#include <osmocom/sigtran/osmo_ss7.h>
+#include <osmocom/sigtran/protocol/mtp.h>
#define SCCP_STR "Signalling Connection Control Part\n"
@@ -141,4 +142,5 @@ void sccp_scmg_rx_ssn_allowed(struct osmo_sccp_instance *inst, uint32_t dpc, uin
void sccp_scmg_rx_ssn_prohibited(struct osmo_sccp_instance *inst, uint32_t dpc, uint32_t ssn, uint32_t smi);
void sccp_scmg_rx_mtp_pause(struct osmo_sccp_instance *inst, uint32_t dpc);
void sccp_scmg_rx_mtp_resume(struct osmo_sccp_instance *inst, uint32_t dpc);
+void sccp_scmg_rx_mtp_status(struct osmo_sccp_instance *inst, uint32_t dpc, enum mtp_unavail_cause cause);
int sccp_scmg_init(struct osmo_sccp_instance *inst);
diff --git a/src/sccp_scmg.c b/src/sccp_scmg.c
index 49e09ca..a5d6226 100644
--- a/src/sccp_scmg.c
+++ b/src/sccp_scmg.c
@@ -122,6 +122,39 @@ void sccp_scmg_rx_mtp_resume(struct osmo_sccp_instance *inst, uint32_t dpc)
* [this would require us to track SSNs at each PC, which we don't] */
}
+void sccp_scmg_rx_mtp_status(struct osmo_sccp_instance *inst, uint32_t dpc, enum mtp_unavail_cause cause)
+{
+ struct osmo_scu_pcstate_param pcstate;
+ /* 1) Informs the translation function to update the translation tables. */
+ /* 2) In the case where the SCCP has received an MTP-STATUS indication primitive relating to
+ Mark the status of the SCCP and each SSN for the relevant destination to "prohibited"
+ and initiates a subsystem status test with SSN = 1. If the cause in the MTP-STATUS
+ indication primitive indicates "unequipped user", then no subsystem status test is
+ initiated. */
+ /* 3) Discontinues all subsystem status tests (including SSN = 1) if an MTP-STATUS
+ indication primitive is received with a cause of "unequipped SCCP". The SCCP
+ discontinues all subsystem status tests, except for SSN = 1, if an MTP-STATUS
+ indication primitive is received with a cause of either "unknown" or "inaccessible" */
+ switch (cause) {
+ case MTP_UNAVAIL_C_UNKNOWN:
+ case MTP_UNAVAIL_C_UNEQUIP_REM_USER:
+ case MTP_UNAVAIL_C_INACC_REM_USER:
+ break;
+ }
+
+ /* 4) local broadcast of "user-out-of-service" for each SSN at that dest
+ * [this would require us to track SSNs at each PC, which we don't] */
+
+ /* 6) local broadcast of "remote SCCP unavailable" */
+ pcstate = (struct osmo_scu_pcstate_param) {
+ .affected_pc = dpc,
+ .restricted_importance_level = 0,
+ .sp_status = OSMO_SCCP_SP_S_ACCESSIBLE,
+ .remote_sccp_status = OSMO_SCCP_REM_SCCP_S_UNAVAILABLE_UNKNOWN,
+ };
+ sccp_lbcs_local_bcast_pcstate(inst, &pcstate);
+}
+
const struct value_string sccp_scmg_msgt_names[] = {
{ SCCP_SCMG_MSGT_SSA, "SSA (Subsystem Allowed)" },
{ SCCP_SCMG_MSGT_SSP, "SSP (Subsystem Prohibited)" },
diff --git a/src/sua.c b/src/sua.c
index c9e880f..2ff5a9a 100644
--- a/src/sua.c
+++ b/src/sua.c
@@ -823,6 +823,28 @@ static struct xua_msg *sua_encode_daud(const uint32_t *rctx, unsigned int num_rc
}
#endif
+/* 3.4.5 Destination User Part Unavailable (DUPU) */
+static struct xua_msg *sua_encode_dupu(const uint32_t *rctx, unsigned int num_rctx,
+ uint32_t dpc, uint16_t user, uint16_t cause,
+ const char *info_string)
+{
+ struct xua_msg *xua = xua_msg_alloc();
+ uint32_t user_cause = (user << 16) | cause;
+
+ xua->hdr = XUA_HDR(SUA_MSGC_SNM, SUA_SNM_DUNA);
+ xua->hdr.version = SUA_VERSION;
+ if (rctx)
+ xua_msg_add_data(xua, SUA_IEI_ROUTE_CTX, num_rctx * sizeof(*rctx), (const uint8_t *)rctx);
+
+ xua_msg_add_u32(xua, SUA_IEI_AFFECTED_PC, dpc);
+ xua_msg_add_u32(xua, SUA_IEI_USER_CAUSE, user_cause);
+
+ if (info_string) {
+ xua_msg_add_data(xua, SUA_IEI_INFO_STRING, strlen(info_string)+1,
+ (const uint8_t *) info_string);
+ }
+ return xua;
+}
/*! Transmit SSNM DUNA/DAVA message indicating [un]availability of certain point code[s]
* \param[in] asp ASP through whihc to transmit message. Must be ACTIVE.
@@ -848,6 +870,21 @@ void sua_tx_snm_available(struct osmo_ss7_asp *asp, const uint32_t *rctx, unsign
sua_tx_xua_asp(asp, xua);
}
+/*! Transmit SSNM DUPU message indicating user unavailability.
+ * \param[in] asp ASP through which to transmit message. Must be ACTIVE.
+ * \param[in] rctx array of Routing Contexts in network byte order.
+ * \param[in] num_rctx number of rctx
+ * \param[in] dpc affected point code
+ * \param[in] user the user (SI) that is unavailable
+ * \param[in] cause the cause of the user unavailability
+ * \param[in] info_string optional information string (can be NULL). */
+void sua_tx_dupu(struct osmo_ss7_asp *asp, const uint32_t *rctx, unsigned int num_rctx,
+ uint32_t dpc, uint16_t user, uint16_t cause, const char *info_str)
+{
+ struct xua_msg *xua = sua_encode_dupu(rctx, num_rctx, dpc, user, cause, info_str);
+ sua_tx_xua_asp(asp, xua);
+}
+
/* received SNM message on ASP side */
static int sua_rx_snm_asp(struct osmo_ss7_asp *asp, struct xua_msg *xua)
{
@@ -867,6 +904,8 @@ static int sua_rx_snm_asp(struct osmo_ss7_asp *asp, struct xua_msg *xua)
xua_snm_rx_dava(asp, as, xua);
break;
case SUA_SNM_DUPU:
+ xua_snm_rx_dupu(asp, as, xua);
+ break;
case SUA_SNM_SCON:
case SUA_SNM_DRST:
LOGPASP(asp, DLSUA, LOGL_NOTICE, "Received unsupported SUA SNM message type %u\n",
diff --git a/src/xua_internal.h b/src/xua_internal.h
index e76fddf..4c6bb29 100644
--- a/src/xua_internal.h
+++ b/src/xua_internal.h
@@ -21,6 +21,8 @@ int sua_tx_xua_as(struct osmo_ss7_as *as, struct xua_msg *xua);
void sua_tx_snm_available(struct osmo_ss7_asp *asp, const uint32_t *rctx, unsigned int num_rctx,
const uint32_t *aff_pc, unsigned int num_aff_pc, const uint32_t *aff_ssn,
const uint32_t *smi, const char *info_string, bool available);
+void sua_tx_dupu(struct osmo_ss7_asp *asp, const uint32_t *rctx, unsigned int num_rctx,
+ uint32_t dpc, uint16_t user, uint16_t cause, const char *info_str);
struct osmo_mtp_prim *m3ua_to_xfer_ind(struct xua_msg *xua);
int m3ua_hmdc_rx_from_l2(struct osmo_ss7_instance *inst, struct xua_msg *xua);
@@ -28,9 +30,12 @@ int m3ua_tx_xua_as(struct osmo_ss7_as *as, struct xua_msg *xua);
void m3ua_tx_snm_available(struct osmo_ss7_asp *asp, const uint32_t *rctx, unsigned int num_rctx,
const uint32_t *aff_pc, unsigned int num_aff_pc,
const char *info_string, bool available);
+void m3ua_tx_dupu(struct osmo_ss7_asp *asp, const uint32_t *rctx, unsigned int num_rctx,
+ uint32_t dpc, uint16_t user, uint16_t cause, const char *info_str);
void xua_snm_rx_daud(struct osmo_ss7_asp *asp, struct xua_msg *xua);
void xua_snm_rx_duna(struct osmo_ss7_asp *asp, struct osmo_ss7_as *as, struct xua_msg *xua);
void xua_snm_rx_dava(struct osmo_ss7_asp *asp, struct osmo_ss7_as *as, struct xua_msg *xua);
+void xua_snm_rx_dupu(struct osmo_ss7_asp *asp, struct osmo_ss7_as *as, struct xua_msg *xua);
int m3ua_rx_msg(struct osmo_ss7_asp *asp, struct msgb *msg);
struct msgb *m3ua_msgb_alloc(const char *name);
diff --git a/src/xua_snm.c b/src/xua_snm.c
index 2a383c7..0c14964 100644
--- a/src/xua_snm.c
+++ b/src/xua_snm.c
@@ -29,6 +29,7 @@
#include <osmocom/sigtran/osmo_ss7.h>
#include <osmocom/sigtran/protocol/m3ua.h>
#include <osmocom/sigtran/protocol/sua.h>
+#include <osmocom/sigtran/protocol/mtp.h>
#include "xua_internal.h"
#include "sccp_internal.h"
@@ -99,6 +100,22 @@ static void xua_tx_snm_available(struct osmo_ss7_asp *asp, const uint32_t *rctx,
}
}
+static void xua_tx_upu(struct osmo_ss7_asp *asp, const uint32_t *rctx, unsigned int num_rctx,
+ uint32_t dpc, uint16_t user, uint16_t cause, const char *info_str)
+{
+ switch (asp->cfg.proto) {
+ case OSMO_SS7_ASP_PROT_M3UA:
+ m3ua_tx_dupu(asp, rctx, num_rctx, dpc, user, cause, info_str);
+ break;
+ case OSMO_SS7_ASP_PROT_SUA:
+ sua_tx_dupu(asp, rctx, num_rctx, dpc, user, cause, info_str);
+ break;
+ default:
+ break;
+ }
+}
+
+
/* generate MTP-PAUSE / MTP-RESUME towards local SCCP users */
static void xua_snm_pc_available_to_sccp(struct osmo_sccp_instance *sccp,
const uint32_t *aff_pc, unsigned int num_aff_pc,
@@ -208,6 +225,37 @@ static void sua_snm_ssn_available(struct osmo_ss7_as *as, uint32_t aff_pc, uint3
}
}
+static void xua_snm_upu(struct osmo_ss7_as *as, uint32_t dpc, uint16_t user, uint16_t cause,
+ const char *info_str)
+{
+ struct osmo_ss7_instance *s7i = as->inst;
+ struct osmo_ss7_asp *asp;
+ uint32_t rctx[32];
+ unsigned int num_rctx;
+
+ /* Translate to MTP-STATUS.ind towards SCCP (will create N-PCSTATE.ind to SCU) */
+ if (s7i->sccp && user == MTP_SI_SCCP)
+ sccp_scmg_rx_mtp_status(s7i->sccp, dpc, cause);
+
+ /* inform remote ASPs via DUPU */
+ llist_for_each_entry(asp, &s7i->asp_list, list) {
+ /* SSNM is only permitted for ASPs in ACTIVE state */
+ if (!osmo_ss7_asp_active(asp))
+ continue;
+
+ /* only send DAVA/DUNA if we locally are the SG and the remote is ASP */
+ if (asp->cfg.role != OSMO_SS7_ASP_ROLE_SG)
+ continue;
+
+ num_rctx = get_all_rctx_for_asp(rctx, ARRAY_SIZE(rctx), asp, as);
+ /* this can happen if the given ASP is only in the AS that reports the change,
+ * which shall be excluded */
+ if (num_rctx == 0)
+ continue;
+
+ xua_tx_upu(asp, rctx, num_rctx, dpc, user, cause, info_str);
+ }
+}
/* receive DAUD from ASP; pc is 'affected PC' IE with mask in network byte order! */
void xua_snm_rx_daud(struct osmo_ss7_asp *asp, struct xua_msg *xua)
@@ -323,3 +371,37 @@ void xua_snm_rx_dava(struct osmo_ss7_asp *asp, struct osmo_ss7_as *as, struct xu
ie_aff_pc->len / sizeof(uint32_t), info_str, true);
}
}
+
+/* an incoming SUA/M3UA DUPU was received from a remote SG */
+void xua_snm_rx_dupu(struct osmo_ss7_asp *asp, struct osmo_ss7_as *as, struct xua_msg *xua)
+{
+ uint32_t aff_pc = xua_msg_get_u32(xua, SUA_IEI_AFFECTED_PC);
+ const char *info_str = xua_msg_get_str(xua, SUA_IEI_INFO_STRING);
+ /* TODO: should our processing depend on the RCTX included? I somehow don't think so */
+ //struct xua_msg_part *ie_rctx = xua_msg_find_tag(xua, SUA_IEI_ROUTE_CTX);
+ int log_ss = osmo_ss7_asp_get_log_subsys(asp);
+ uint32_t cause_user;
+ uint16_t cause, user;
+
+ if (asp->cfg.role != OSMO_SS7_ASP_ROLE_ASP)
+ return;
+
+ switch (asp->cfg.proto) {
+ case OSMO_SS7_ASP_PROT_M3UA:
+ cause_user = xua_msg_get_u32(xua, M3UA_IEI_USER_CAUSE);
+ break;
+ case OSMO_SS7_ASP_PROT_SUA:
+ cause_user = xua_msg_get_u32(xua, SUA_IEI_USER_CAUSE);
+ break;
+ default:
+ return;
+ }
+
+ cause = cause_user >> 16;
+ user = cause_user & 0xffff;
+ LOGPASP(asp, log_ss, LOGL_NOTICE, "Rx DUPU(%s) for %s User %s, cause %u\n",
+ info_str ? info_str : "", osmo_ss7_pointcode_print(asp->inst, aff_pc),
+ get_value_string(mtp_si_vals, user), cause);
+
+ xua_snm_upu(as, aff_pc, user, cause, info_str);
+}