pespin submitted this change.

View Change

Approvals: Jenkins Builder: Verified laforge: Looks good to me, but someone else must approve osmith: Looks good to me, but someone else must approve pespin: Looks good to me, approved
Submit SCRC Routing Failure indications asynchronously

Submitting CL/CO messages down the stack (SCOC/SCLC -> SCRC) may trigger
a Routing Failure in the opposite direction up the stack.

Until recently, due to missing logic, it was (almost?) impossible to
trigger such a Routing Failure path in our code.

Since recently, though, we can run over them, and so far we are
generating those indications in a synchronously manner, which means upper
layers in libosmo-sigtran and even in user applications we may receive a
callback with such Routing Indication (or derived N-PCSTATE.ind) while
still waiting for return of the initiaring request.

This causes a lot of unexpected trouble and unintended behavior in both
libosmo-sigtran SCOC/SCLC as well as user applications.

Hence, instead, defer the triggering of such Routing Failure indications
SCRC -> SCOC/SCLC so that they are submitted in event loop context later
on, when upper layers are done updating its status.

Related: OS#6790
Change-Id: I17ae7174f7ffee8c9a004435e522803a97d4fb7b
---
M src/sccp_instance.c
M src/sccp_instance.h
M src/sccp_internal.h
M src/sccp_scrc.c
M src/xua_msg.c
M src/xua_msg.h
6 files changed, 91 insertions(+), 12 deletions(-)

diff --git a/src/sccp_instance.c b/src/sccp_instance.c
index 08274a5..1a9e02c 100644
--- a/src/sccp_instance.c
+++ b/src/sccp_instance.c
@@ -207,6 +207,52 @@
return sccp_user_bind_pc(inst, name, prim_cb, ssn, OSMO_SS7_PC_INVALID);
}

+/* Timer cb used to transmit queued Routing Failures asynchronously up the stack */
+static void rout_fail_pending_cb(void *_inst)
+{
+ struct osmo_sccp_instance *inst = _inst;
+ struct sccp_pending_rout_fail *prf;
+
+ while ((prf = llist_first_entry_or_null(&inst->rout_fail_pending.queue, struct sccp_pending_rout_fail, list))) {
+ struct xua_msg *xua = prf->xua;
+ uint32_t cause = prf->cause;
+ bool scoc = prf->scoc;
+ llist_del(&prf->list);
+ talloc_free(prf);
+ if (scoc) /* Routing Failure SCRC -> SCOC */
+ sccp_scoc_rx_scrc_rout_fail(inst, xua, cause);
+ else /* Routing Failure SCRC -> SCLC */
+ sccp_sclc_rx_scrc_rout_fail(inst, xua, cause);
+ xua_msg_free(xua);
+ }
+}
+
+/* Enqueue Routing Failure to submit it asynchronously to upper layers.
+ * xua_msg is copied.
+ * scoc: true if it's for SCOC, false if it's for SCLC. */
+void sccp_rout_fail_enqueue(struct osmo_sccp_instance *inst, const struct xua_msg *xua, uint32_t cause, bool scoc)
+{
+ bool queue_was_empty = llist_empty(&inst->rout_fail_pending.queue);
+ struct sccp_pending_rout_fail *prf;
+
+ LOGPSCI(inst, LOGL_DEBUG, "Enqueuing SCRC Routing Failure (%s) for %s message %s\n",
+ osmo_sccp_return_cause_name(cause),
+ scoc ? "CO" : "CL",
+ xua_hdr_dump(xua, &xua_dialect_sua));
+
+ prf = talloc(inst, struct sccp_pending_rout_fail);
+ OSMO_ASSERT(prf);
+ *prf = (struct sccp_pending_rout_fail){
+ .xua = xua_msg_copy(xua),
+ .cause = cause,
+ .scoc = scoc,
+ };
+ OSMO_ASSERT(prf->xua);
+ llist_add_tail(&prf->list, &inst->rout_fail_pending.queue);
+
+ if (queue_was_empty)
+ osmo_timer_schedule(&inst->rout_fail_pending.timer, 0, 0);
+}

/* prim_cb handed to MTP code for incoming MTP-TRANSFER.ind */
static int mtp_user_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
@@ -268,6 +314,9 @@
sizeof(osmo_sccp_timer_defaults));
osmo_tdefs_reset(inst->tdefs);

+ osmo_timer_setup(&inst->rout_fail_pending.timer, rout_fail_pending_cb, inst);
+ INIT_LLIST_HEAD(&inst->rout_fail_pending.queue);
+
rc = sccp_scmg_init(inst);
if (rc < 0) {
talloc_free(inst);
@@ -297,6 +346,10 @@
osmo_sccp_user_unbind(scu);
}
OSMO_ASSERT(RB_EMPTY_ROOT(&inst->connections)); /* assert is empty */
+
+ osmo_timer_del(&inst->rout_fail_pending.timer);
+ /* Note: All entries in inst->rout_fail_pending.queue are freed by talloc. */
+
llist_del(&inst->list);
talloc_free(inst);
}
diff --git a/src/sccp_instance.h b/src/sccp_instance.h
index a3f6750..2005d7a 100644
--- a/src/sccp_instance.h
+++ b/src/sccp_instance.h
@@ -35,6 +35,14 @@
static inline const char *osmo_sccp_timer_name(enum osmo_sccp_timer val)
{ return get_value_string(osmo_sccp_timer_names, val); }

+struct sccp_pending_rout_fail {
+ /* Item in inst->rout_fail_pending.queue: */
+ struct llist_head list;
+ struct xua_msg *xua;
+ uint32_t cause;
+ bool scoc; /* true if it's for SCOC, false if it's for SCLC. */
+};
+
/* an instance of the SCCP stack */
struct osmo_sccp_instance {
/* entry in global list of ss7 instances */
@@ -55,6 +63,12 @@
struct osmo_tdef *tdefs;

uint32_t max_optional_data;
+
+ /* Queued Routing Failures to transmit asynchronously up the stack: */
+ struct {
+ struct osmo_timer_list timer;
+ struct llist_head queue;
+ } rout_fail_pending;
};

struct osmo_sccp_user *
diff --git a/src/sccp_internal.h b/src/sccp_internal.h
index 8a69e19..045e49b 100644
--- a/src/sccp_internal.h
+++ b/src/sccp_internal.h
@@ -58,6 +58,9 @@
void sccp_sclc_rx_scrc_rout_fail(struct osmo_sccp_instance *inst,
struct xua_msg *xua, uint32_t cause);

+/* Route Failure from SCRX -> SCOC or SCLC */
+void sccp_rout_fail_enqueue(struct osmo_sccp_instance *inst, const struct xua_msg *xua, uint32_t cause, bool scoc);
+
/* SCU -> SCLC */
int sccp_sclc_user_sap_down(struct osmo_sccp_user *scu, struct osmo_prim_hdr *oph);
int sccp_sclc_user_sap_down_nofree(struct osmo_sccp_user *scu, struct osmo_prim_hdr *oph);
diff --git a/src/sccp_scrc.c b/src/sccp_scrc.c
index fdbfd3c..e28e584 100644
--- a/src/sccp_scrc.c
+++ b/src/sccp_scrc.c
@@ -262,16 +262,14 @@
if (!dpc_accessible(inst, called.pc)) {
/* Error: MTP Failure */
/* Routing Failure SCRC -> SCOC */
- sccp_scoc_rx_scrc_rout_fail(inst, xua,
- SCCP_RETURN_CAUSE_MTP_FAILURE);
+ sccp_rout_fail_enqueue(inst, xua, SCCP_RETURN_CAUSE_MTP_FAILURE, true);
return 0;
}
/* Is SCCP available? */
if (!sccp_available(inst, &called)) {
/* Error: SCCP Failure */
/* Routing Failure SCRC -> SCOC */
- sccp_scoc_rx_scrc_rout_fail(inst, xua,
- SCCP_RETURN_CAUSE_SCCP_FAILURE);
+ sccp_rout_fail_enqueue(inst, xua, SCCP_RETURN_CAUSE_SCCP_FAILURE, true);
return 0;
}
return scrc_node_12(inst, xua, &called);
@@ -305,10 +303,10 @@
/* TODO: Routing Failure SCRC -> OMAP */
if (sua_is_connectionless(xua)) {
/* Routing Failure SCRC -> SCLC */
- sccp_sclc_rx_scrc_rout_fail(inst, xua, return_cause);
+ sccp_rout_fail_enqueue(inst, xua, return_cause, false);
} else {
/* Routing Failure SCRC -> SCOC */
- sccp_scoc_rx_scrc_rout_fail(inst, xua, return_cause);
+ sccp_rout_fail_enqueue(inst, xua, return_cause, true);
}
return 0;
}
@@ -335,8 +333,7 @@
LOGPSCI(inst, LOGL_NOTICE, "GT Routing not implemented yet\n");
#if 1
/* Prevent endless recursion, see OS#2666. */
- sccp_sclc_rx_scrc_rout_fail(inst, xua,
- SCCP_RETURN_CAUSE_SUBSYSTEM_FAILURE);
+ sccp_rout_fail_enqueue(inst, xua, SCCP_RETURN_CAUSE_SUBSYSTEM_FAILURE, false);
return 0;
#else
/* Node 7 (Sheet 5) */
@@ -386,12 +383,10 @@
/* TODO: SCRC -> SSPC */
if (sua_is_connectionless(xua)) {
/* Routing Failure SCRC -> SCLC */
- sccp_sclc_rx_scrc_rout_fail(inst, xua,
- SCCP_RETURN_CAUSE_SUBSYSTEM_FAILURE);
+ sccp_rout_fail_enqueue(inst, xua, SCCP_RETURN_CAUSE_SUBSYSTEM_FAILURE, false);
} else {
/* Routing Failure SCRC -> SCOC */
- sccp_scoc_rx_scrc_rout_fail(inst, xua,
- SCCP_RETURN_CAUSE_SUBSYSTEM_FAILURE);
+ sccp_rout_fail_enqueue(inst, xua, SCCP_RETURN_CAUSE_SUBSYSTEM_FAILURE, true);
}
return 0;
}
diff --git a/src/xua_msg.c b/src/xua_msg.c
index bc2a4f7..0652277 100644
--- a/src/xua_msg.c
+++ b/src/xua_msg.c
@@ -58,6 +58,19 @@
talloc_free(msg);
}

+struct xua_msg *xua_msg_copy(const struct xua_msg *xua_in)
+{
+ struct xua_msg_part *part;
+ struct xua_msg *xua_cpy = xua_msg_alloc();
+
+ xua_cpy->hdr = xua_in->hdr;
+ xua_cpy->mtp = xua_in->mtp;
+
+ llist_for_each_entry(part, &xua_in->headers, entry)
+ xua_msg_add_data(xua_cpy, part->tag, part->len, part->dat);
+ return xua_cpy;
+}
+
int xua_msg_add_data(struct xua_msg *msg, uint16_t tag,
uint16_t len, const uint8_t *dat)
{
diff --git a/src/xua_msg.h b/src/xua_msg.h
index 8311d60..f5d5de4 100644
--- a/src/xua_msg.h
+++ b/src/xua_msg.h
@@ -74,6 +74,7 @@

struct xua_msg *xua_msg_alloc(void);
void xua_msg_free(struct xua_msg *msg);
+struct xua_msg *xua_msg_copy(const struct xua_msg *xua_in);

int xua_msg_add_data(struct xua_msg *msg, uint16_t tag, uint16_t len, const uint8_t *dat);
int xua_msg_add_u32_data(struct xua_msg *msg, uint16_t tag, uint16_t len, const uint8_t *dat);

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

Gerrit-MessageType: merged
Gerrit-Project: libosmo-sigtran
Gerrit-Branch: master
Gerrit-Change-Id: I17ae7174f7ffee8c9a004435e522803a97d4fb7b
Gerrit-Change-Number: 40615
Gerrit-PatchSet: 2
Gerrit-Owner: pespin <pespin@sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge@osmocom.org>
Gerrit-Reviewer: osmith <osmith@sysmocom.de>
Gerrit-Reviewer: pespin <pespin@sysmocom.de>