pespin has uploaded this change for review. ( 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, 85 insertions(+), 12 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmo-sigtran refs/changes/15/40615/1
diff --git a/src/sccp_instance.c b/src/sccp_instance.c index 08274a5..1f5ec58 100644 --- a/src/sccp_instance.c +++ b/src/sccp_instance.c @@ -207,6 +207,46 @@ 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 = talloc(inst, struct sccp_pending_rout_fail); + *prf = (struct sccp_pending_rout_fail){ + .xua = xua_msg_copy(xua), + .cause = cause, + .scoc = scoc, + }; + llist_add_tail(&prf->list, &inst->rout_fail_pending.queue); + if (queue_was_empty) + osmo_timer_schedule(&inst->rout_fail_pending.timer, 0, 0); + 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(prf->xua, &xua_dialect_sua)); +}
/* 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 +308,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 +340,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 d32d824..691c215 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 80d4c79..9630d41 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);