pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-hnbgw/+/38581?usp=email )
Change subject: Fix SCCP RLSD not sent upon rx RUA Disconnect due to error condition ......................................................................
Fix SCCP RLSD not sent upon rx RUA Disconnect due to error condition
Scenario: HNB tears down the RUA/Iu conn by first sending RUA_DATA[RANAP IuReleaseReq], followed shortly by a RUA Disconnect with no RANAP and Cause!=Normal. HNBGW should release the SCCP connection through RLSD since it's impossible to terminate the Iu connection in a normal condition.
Validated with TTCN-3 HNBGW_Tests.TC_cs_iu_release_req_rua_disconnect.
Related: osmo-ttcn3-hacks.git Change-Id I6782920c4a86d3311eb54239ab13a18e393c1ec0 Related: SYS#6602 Change-Id: I1b7f72034eaf40bfa60d552d434847467ac4e97a --- M include/osmocom/hnbgw/context_map.h M src/osmo-hnbgw/context_map_rua.c M src/osmo-hnbgw/context_map_sccp.c 3 files changed, 62 insertions(+), 20 deletions(-)
Approvals: laforge: Looks good to me, but someone else must approve pespin: Looks good to me, approved Jenkins Builder: Verified
diff --git a/include/osmocom/hnbgw/context_map.h b/include/osmocom/hnbgw/context_map.h index 1e23777..8fe478c 100644 --- a/include/osmocom/hnbgw/context_map.h +++ b/include/osmocom/hnbgw/context_map.h @@ -55,9 +55,18 @@ MAP_SCCP_EV_RX_DATA_INDICATION, /* RUA has received some data from HNB to forward via SCCP to CN. */ MAP_SCCP_EV_TX_DATA_REQUEST, - /* The RAN side received a Disconnect, that means we are going to expect SCCP to disconnect too. - * CN should have received an Iu-ReleaseComplete with or before this, give CN a chance to send an SCCP RLSD; - * after a timeout we will send a non-standard RLSD to the CN instead. */ + /* 3GPP TS 25.468 9.1.5: The RAN side received a RUA Disconnect. + * - Under normal conditions (cause=Normal) the RUA Disconnect contains a RANAP Iu-ReleaseComplete. + * On SCCP, the Iu-ReleaseComplete should still be forwarded as N-Data SCCP Data Form 1), + * and we will expect the CN to send an SCCP RLSD soon. Hence, give CN a chance to send an SCCP RLSD; + * after a timeout we will send a non-standard RLSD to the CN instead. + * - Under error conditions, cause!=Normal and there's no RANAP message. + * In that case, we need to tear down the associated SCCP link towards CN with an RLSD, + * which in turn will tear down the upper layer Iu conn. + * + * Parameter: bool rua_disconnect_err_condition, whether the disconnect + * happened under error or normal conditions, as per the above. + */ MAP_SCCP_EV_RAN_DISC, /* The RAN released ungracefully. We will directly disconnect the SCCP connection, too. */ MAP_SCCP_EV_RAN_LINK_LOST, @@ -127,6 +136,16 @@ /* FSM handling the RUA state for rua_ctx_id. */ struct osmo_fsm_inst *rua_fi;
+ /* State context related to field rua_fi above: */ + struct { + /* Whether RUA Disconnect received from HNB happened as a normal condition or an error/abnormal condition. + * This is known based on cause and/or RANAP message included in the RUA + * Disconnect message, and tells us whether we should immediately + * terminate the related SCCP session or wait for CN to finish it. + * Defaults to false, only set to true explicitly when needed. */ + bool rua_disconnect_err_condition; + } rua_fi_ctx; + /* Pointer to CN, to transceive SCCP. */ struct hnbgw_cnlink *cnlink; /* SCCP User SAP connection ID used in SCCP messages to/from the cn_link. */ diff --git a/src/osmo-hnbgw/context_map_rua.c b/src/osmo-hnbgw/context_map_rua.c index 7286906..2d9fd8d 100644 --- a/src/osmo-hnbgw/context_map_rua.c +++ b/src/osmo-hnbgw/context_map_rua.c @@ -287,15 +287,21 @@ return;
case MAP_RUA_EV_RX_DISCONNECT: - /* received Disconnect from RUA. forward any payload to SCCP, and change state. */ - if (!map_sccp_is_active(map)) { - /* If, unlikely, the SCCP is already gone, changing to MAP_RUA_ST_DISCONNECTED frees the - * hnbgw_context_map. Avoid a use-after-free. */ - map_rua_fsm_state_chg(MAP_RUA_ST_DISCONNECTED); - return; + /* 3GPP TS 25.468 9.1.5: RUA has disconnected. + * - Under normal conditions (cause=Normal) the RUA Disconnect contains a RANAP Iu-ReleaseComplete. + * On SCCP, the Iu-ReleaseComplete should still be forwarded as N-Data SCCP Data Form 1), + * and we will expect the CN to send an SCCP RLSD soon. + * - Under error conditions, cause!=Normal and there's no RANAP message. + * In that case, we need to tear down the associated SCCP link towards CN, + * which in turn will tear down the upper layer Iu conn. + */ + if (msg_has_l2_data(ranap_msg)) { + /* Forward any payload to SCCP before Disconnect. */ + handle_rx_rua(fi, ranap_msg); + } else { + map->rua_fi_ctx.rua_disconnect_err_condition = true; } map_rua_fsm_state_chg(MAP_RUA_ST_DISCONNECTED); - handle_rx_rua(fi, ranap_msg); return;
case MAP_RUA_EV_HNB_LINK_LOST: @@ -315,13 +321,13 @@ } }
-static void map_rua_free_if_done(struct hnbgw_context_map *map, uint32_t sccp_event) +static void map_rua_free_if_done(struct hnbgw_context_map *map, uint32_t sccp_event, void *ev_data) { /* From RUA's POV, we can now free the hnbgw_context_map. * If SCCP is still active, tell it to disconnect -- in that case the SCCP side will call context_map_free(). * If SCCP is no longer active, free this map. */ if (map_sccp_is_active(map)) - map_sccp_dispatch(map, sccp_event, NULL); + map_sccp_dispatch(map, sccp_event, ev_data); else context_map_free(map); } @@ -329,7 +335,7 @@ static void map_rua_disconnected_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) { struct hnbgw_context_map *map = fi->priv; - map_rua_free_if_done(map, MAP_SCCP_EV_RAN_DISC); + map_rua_free_if_done(map, MAP_SCCP_EV_RAN_DISC, (void *)map->rua_fi_ctx.rua_disconnect_err_condition); }
static void map_rua_disconnected_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) @@ -343,7 +349,7 @@ static void map_rua_disrupted_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) { struct hnbgw_context_map *map = fi->priv; - map_rua_free_if_done(map, MAP_SCCP_EV_RAN_LINK_LOST); + map_rua_free_if_done(map, MAP_SCCP_EV_RAN_LINK_LOST, NULL); }
void map_rua_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause) diff --git a/src/osmo-hnbgw/context_map_sccp.c b/src/osmo-hnbgw/context_map_sccp.c index 511577c..b79dc39 100644 --- a/src/osmo-hnbgw/context_map_sccp.c +++ b/src/osmo-hnbgw/context_map_sccp.c @@ -349,26 +349,40 @@
static void map_sccp_connected_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) { - struct msgb *ranap_msg = data; + struct msgb *ranap_msg; + bool rua_disconnect_err_condition;
switch (event) {
case MAP_SCCP_EV_RX_DATA_INDICATION: + ranap_msg = data; /* forward RANAP from SCCP to RUA */ handle_rx_sccp(fi, ranap_msg); return;
case MAP_SCCP_EV_TX_DATA_REQUEST: + ranap_msg = data; /* Someone (usually the RUA side) wants us to send a RANAP payload to CN via SCCP */ tx_sccp_df1(fi, ranap_msg); return;
case MAP_SCCP_EV_RAN_DISC: - /* RUA has disconnected, and usually has sent an Iu-ReleaseComplete along with its RUA Disconnect. On - * SCCP, the Iu-ReleaseComplete should still be forwarded as N-Data (SCCP Data Form 1), and we will - * expect the CN to send an SCCP RLSD soon. */ - map_sccp_fsm_state_chg(MAP_SCCP_ST_WAIT_RLSD); - tx_sccp_df1(fi, ranap_msg); + rua_disconnect_err_condition = !!data; + /* 3GPP TS 25.468 9.1.5: RUA has disconnected. + * - Under normal conditions (cause=Normal) the RUA Disconnect + * contained a RANAP Iu-ReleaseComplete which we already + * handled here through MAP_SCCP_EV_TX_DATA_REQUEST. + * On SCCP, We will expect the CN to send an SCCP RLSD soon. + * - Under error conditions, cause!=Normal and there was no RANAP message. + * In that case, we need to tear down the associated SCCP link towards CN, + * which in turn will tear down the upper layer Iu conn. + */ + if (rua_disconnect_err_condition) { + tx_sccp_rlsd(fi); + map_sccp_fsm_state_chg(MAP_SCCP_ST_DISCONNECTED); + } else { + map_sccp_fsm_state_chg(MAP_SCCP_ST_WAIT_RLSD); + } return;
case MAP_SCCP_EV_RAN_LINK_LOST: @@ -377,6 +391,7 @@ case MAP_SCCP_EV_USER_ABORT: /* The user is asking for disconnection, so there is no Iu Release in progress. Disconnect now. */ case MAP_SCCP_EV_CN_LINK_LOST: + ranap_msg = data; /* The CN peer has sent a RANAP RESET, so the old link that this map ran on is lost */
/* There won't be any ranap_msg, but if a caller wants to dispatch a msg, forward it before @@ -387,6 +402,7 @@ return;
case MAP_SCCP_EV_RX_RELEASED: + ranap_msg = data; /* The CN sends an N-Disconnect (SCCP Released) out of the usual sequence. Not what we expected, but * handle it. */ LOGPFSML(fi, LOGL_ERROR, "CN sends SCCP Released sooner than expected\n"); @@ -395,6 +411,7 @@ return;
case MAP_SCCP_EV_RX_CONNECTION_CONFIRM: + ranap_msg = data; /* Already connected. Unusual, but if there is data just forward it. */ LOGPFSML(fi, LOGL_ERROR, "Already connected, but received SCCP CC again\n"); handle_rx_sccp(fi, ranap_msg);