pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-msc/+/40630?usp=email )
Change subject: msc: Initial implementation of N-PCSTATE.ind ......................................................................
msc: Initial implementation of N-PCSTATE.ind
Change-Id: Ice1b2c163b1b0d134fcaa1c8bf543038a35fabdf --- M include/osmocom/msc/ran_peer.h M src/libmsc/ran_peer.c M src/libmsc/sccp_ran.c 3 files changed, 127 insertions(+), 2 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-msc refs/changes/30/40630/1
diff --git a/include/osmocom/msc/ran_peer.h b/include/osmocom/msc/ran_peer.h index c936d5c..211dd44 100644 --- a/include/osmocom/msc/ran_peer.h +++ b/include/osmocom/msc/ran_peer.h @@ -91,7 +91,7 @@ };
struct ran_peer *ran_peer_find_or_create(struct sccp_ran_inst *sri, const struct osmo_sccp_addr *peer_addr); -struct ran_peer *ran_peer_find_by_addr(struct sccp_ran_inst *sri, const struct osmo_sccp_addr *peer_addr); +struct ran_peer *ran_peer_find_by_addr(const struct sccp_ran_inst *sri, const struct osmo_sccp_addr *peer_addr);
void ran_peer_cells_seen_add(struct ran_peer *ran_peer, const struct gsm0808_cell_id *id);
@@ -104,5 +104,8 @@ int ran_peer_down_paging(struct ran_peer *rp, const struct gsm0808_cell_id *page_id, struct vlr_subscr *vsub, enum paging_cause cause);
+void ran_peer_reset(struct ran_peer *rp); +void ran_peer_becomes_unreachable(struct ran_peer *rp); + struct ran_peer *ran_peer_find_by_cell_id(struct sccp_ran_inst *sri, const struct gsm0808_cell_id *cid, bool expecting_single_match); diff --git a/src/libmsc/ran_peer.c b/src/libmsc/ran_peer.c index 09e57eb..bef753a 100644 --- a/src/libmsc/ran_peer.c +++ b/src/libmsc/ran_peer.c @@ -87,7 +87,7 @@ return ran_peer_alloc(sri, peer_addr); }
-struct ran_peer *ran_peer_find_by_addr(struct sccp_ran_inst *sri, const struct osmo_sccp_addr *peer_addr) +struct ran_peer *ran_peer_find_by_addr(const struct sccp_ran_inst *sri, const struct osmo_sccp_addr *peer_addr) { struct ran_peer *rp; llist_for_each_entry(rp, &sri->ran_peers, entry) { @@ -128,6 +128,13 @@ } }
+/* N-PCSTATE.ind informs us the peer went down and is no longer reachable: */ +void ran_peer_becomes_unreachable(struct ran_peer *rp) +{ + ran_peer_discard_all_conns(rp); + ran_peer_state_chg(rp, RAN_PEER_ST_WAIT_RX_RESET); +} + static void ran_peer_update_osmux_support(struct ran_peer *rp, int supports_osmux) { bool old_value = rp->remote_supports_osmux; diff --git a/src/libmsc/sccp_ran.c b/src/libmsc/sccp_ran.c index 9907f20..3a1bfd5 100644 --- a/src/libmsc/sccp_ran.c +++ b/src/libmsc/sccp_ran.c @@ -29,6 +29,7 @@ #include <osmocom/msc/debug.h> #include <osmocom/msc/sccp_ran.h> #include <osmocom/msc/ran_infra.h> +#include <osmocom/msc/ran_peer.h>
struct osmo_tdef g_sccp_tdefs[] = { {} @@ -59,6 +60,107 @@ return sri; }
+/* Find an ran_peer (BSC/RNC) by its remote SCCP address */ +static struct ran_peer *get_ran_peer_by_pc(const struct sccp_ran_inst *sri, uint32_t pc) +{ + struct ran_peer *rp; + struct osmo_ss7_instance *cs7 = osmo_sccp_get_ss7(sri->sccp); + struct osmo_sccp_addr rem_addr; + + osmo_sccp_make_addr_pc_ssn(&rem_addr, pc, sri->ran->ssn); + rp = ran_peer_find_by_addr(sri, &rem_addr); + if (rp) + return rp; + LOGP(DMSC, LOGL_DEBUG, "Nofind ran_peer found under remote address: %s\n", osmo_sccp_addr_name(cs7, &rem_addr)); + return NULL; +} + +static void handle_pcstate_ind(struct sccp_ran_inst *sri, const struct osmo_scu_pcstate_param *pcst) +{ + struct ran_peer *rp; + bool connected; + bool disconnected; + + LOGP(DMSC, LOGL_DEBUG, "N-PCSTATE ind: affected_pc=%u sp_status=%s remote_sccp_status=%s\n", + pcst->affected_pc, osmo_sccp_sp_status_name(pcst->sp_status), + osmo_sccp_rem_sccp_status_name(pcst->remote_sccp_status)); + + /* If we don't care about that point-code, ignore PCSTATE. */ + rp = get_ran_peer_by_pc(sri, pcst->affected_pc); + if (!rp) + return; + + /* See if this marks the point code to have become available, or to have been lost. + * + * I want to detect two events: + * - connection event (both indicators say PC is reachable). + * - disconnection event (at least one indicator says the PC is not reachable). + * + * There are two separate incoming indicators with various possible values -- the incoming events can be: + * + * - neither connection nor disconnection indicated -- just indicating congestion + * connected == false, disconnected == false --> do nothing. + * - both incoming values indicate that we are connected + * --> trigger connected + * - both indicate we are disconnected + * --> trigger disconnected + * - one value indicates 'connected', the other indicates 'disconnected' + * --> trigger disconnected + * + * Congestion could imply that we're connected, but it does not indicate that a PC's reachability changed, so no need to + * trigger on that. + */ + connected = false; + disconnected = false; + + switch (pcst->sp_status) { + case OSMO_SCCP_SP_S_ACCESSIBLE: + connected = true; + break; + case OSMO_SCCP_SP_S_INACCESSIBLE: + disconnected = true; + break; + default: + case OSMO_SCCP_SP_S_CONGESTED: + /* Neither connecting nor disconnecting */ + break; + } + + switch (pcst->remote_sccp_status) { + case OSMO_SCCP_REM_SCCP_S_AVAILABLE: + if (!disconnected) + connected = true; + break; + case OSMO_SCCP_REM_SCCP_S_UNAVAILABLE_UNKNOWN: + case OSMO_SCCP_REM_SCCP_S_UNEQUIPPED: + case OSMO_SCCP_REM_SCCP_S_INACCESSIBLE: + disconnected = true; + connected = false; + break; + default: + case OSMO_SCCP_REM_SCCP_S_CONGESTED: + /* Neither connecting nor disconnecting */ + break; + } + + if (disconnected && rp->fi && rp->fi->state == RAN_PEER_ST_READY) { + LOG_RAN_PEER(rp, LOGL_NOTICE, + "now unreachable: N-PCSTATE ind: pc=%u sp_status=%s remote_sccp_status=%s\n", + pcst->affected_pc, + osmo_sccp_sp_status_name(pcst->sp_status), + osmo_sccp_rem_sccp_status_name(pcst->remote_sccp_status)); + ran_peer_becomes_unreachable(rp); + /* TODO: need to change state?! */ + } else if (connected && rp->fi && rp->fi->state != RAN_PEER_ST_READY) { + LOG_RAN_PEER(rp, LOGL_NOTICE, + "now available: N-PCSTATE ind: pc=%u sp_status=%s remote_sccp_status=%s\n", + pcst->affected_pc, + osmo_sccp_sp_status_name(pcst->sp_status), + osmo_sccp_rem_sccp_status_name(pcst->remote_sccp_status)); + ran_peer_reset(rp); + } +} + static int sccp_ran_sap_up(struct osmo_prim_hdr *oph, void *_scu) { struct osmo_sccp_user *scu = _scu; @@ -141,6 +243,19 @@ rc = sri->ran->sccp_ran_ops.up_l2(sri, peer_addr, false, 0, oph->msg); break;
+ case OSMO_PRIM(OSMO_SCU_PRIM_N_PCSTATE, PRIM_OP_INDICATION): + handle_pcstate_ind(sri, &prim->u.pcstate); + rc = 0; + break; + + case OSMO_PRIM(OSMO_SCU_PRIM_N_STATE, PRIM_OP_INDICATION): + LOG_SCCP_RAN_CL(sri, NULL, LOGL_INFO, + "SCCP-User-SAP: Ignoring %s.%s\n", + osmo_scu_prim_type_name(oph->primitive), + get_value_string(osmo_prim_op_names, oph->operation)); + rc = 0; + break; + default: LOG_SCCP_RAN_CL(sri, NULL, LOGL_DEBUG, "%s(%s)\n", __func__, osmo_scu_prim_name(oph)); rc = -1;