pespin has submitted this change. (
https://gerrit.osmocom.org/c/libosmo-sigtran/+/40615?usp=email )
Change subject: Submit SCRC Routing Failure indications asynchronously
......................................................................
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(-)
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
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
https://gerrit.osmocom.org/c/libosmo-sigtran/+/40615?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
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(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>