diff options
author | Harald Welte <laforge@osmocom.org> | 2021-02-08 17:46:08 +0100 |
---|---|---|
committer | Harald Welte <laforge@osmocom.org> | 2021-02-10 19:58:38 +0100 |
commit | afbcc5d532fe9ccfd82d15423796ca1a39a37393 (patch) | |
tree | f9b5de76d19c99c5cc891a8ddbfa9af3fec012d8 | |
parent | 7daae9bd67215888c7d5e201ea2261fb6c8fbb2b (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.h | 15 | ||||
-rw-r--r-- | src/m3ua.c | 40 | ||||
-rw-r--r-- | src/osmo_ss7.c | 7 | ||||
-rw-r--r-- | src/sccp_internal.h | 2 | ||||
-rw-r--r-- | src/sccp_scmg.c | 33 | ||||
-rw-r--r-- | src/sua.c | 39 | ||||
-rw-r--r-- | src/xua_internal.h | 5 | ||||
-rw-r--r-- | src/xua_snm.c | 82 |
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); +} @@ -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)" }, @@ -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); +} |