pespin has uploaded this change for review.

View Change

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;

To view, visit change 40630. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-MessageType: newchange
Gerrit-Project: osmo-msc
Gerrit-Branch: master
Gerrit-Change-Id: Ice1b2c163b1b0d134fcaa1c8bf543038a35fabdf
Gerrit-Change-Number: 40630
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin@sysmocom.de>