From 64623e18484d52a9d6eb5f0fa7166c78d8605422 Mon Sep 17 00:00:00 2001 From: Vadim Yanitskiy Date: Wed, 28 Nov 2018 23:05:51 +0700 Subject: [PATCH] libmsc/gsm_09_11.c: implement guard timer for NCSS sessions It may happen that either the MS or an EUSE would become unresponsive during a call independent SS session, e.g. due to a bug, or a dropped message. In such cases, the corresponding transaction would remain unfreed forever. This change introduces a guard timer, that prevents keeping 'stalled' NCSS sessions forever. As soon as it expires, both sides (i.e. MS and EUSE) are getting notified, and the transaction is being released. By default, the timer expires after 30 seconds. As soon as either the MS, or an EUSE initiates any activity, the watchdog timer is rescheduled. The timeout value can be configured from the VTY: msc ... ! Use 0 to disable this timer ncss guard-timeout 30 Please note that changing the timeout value at run-time doesn't affect the existing NCSS sessions, excepting the case when the timer is disabled at run-time. This change makes TC_lu_and_ss_session_timeout pass. Change-Id: Icf4d87c45e90324764073e8230e0fb9cb96dd9cb Related Change-Id: (TTCN) I3e1791773d56617172ae27a46889a1ae4d400e2f Related: OS#3655 --- include/osmocom/msc/gsm_data.h | 2 + include/osmocom/msc/transaction.h | 2 + src/libmsc/gsm_09_11.c | 62 +++++++++++++++++++++++++++++++ src/libmsc/msc_vty.c | 15 ++++++++ src/libmsc/osmo_msc.c | 1 + tests/test_nodes.vty | 8 ++++ 6 files changed, 90 insertions(+) diff --git a/include/osmocom/msc/gsm_data.h b/include/osmocom/msc/gsm_data.h index dab082d82..7d3a1e71b 100644 --- a/include/osmocom/msc/gsm_data.h +++ b/include/osmocom/msc/gsm_data.h @@ -192,6 +192,8 @@ struct gsm_network { /* Global MNCC guard timer value */ int mncc_guard_timeout; + /* Global guard timer value for NCSS sessions */ + int ncss_guard_timeout; struct { struct mgcp_client_conf conf; diff --git a/include/osmocom/msc/transaction.h b/include/osmocom/msc/transaction.h index 39b09aeaa..830328bca 100644 --- a/include/osmocom/msc/transaction.h +++ b/include/osmocom/msc/transaction.h @@ -87,6 +87,8 @@ struct gsm_trans { * a subscriber after successful Paging Response */ struct msgb *msg; + /* Inactivity timer, triggers transaction release */ + struct osmo_timer_list timer_guard; } ss; }; diff --git a/src/libmsc/gsm_09_11.c b/src/libmsc/gsm_09_11.c index d2ad0b7a6..c133656dd 100644 --- a/src/libmsc/gsm_09_11.c +++ b/src/libmsc/gsm_09_11.c @@ -51,6 +51,39 @@ /* FIXME: choose a proper range */ static uint32_t new_callref = 0x20000001; +static void ncss_session_timeout_handler(void *_trans) +{ + struct gsm_trans *trans = (struct gsm_trans *) _trans; + struct osmo_gsup_message gsup_msg = { 0 }; + + /* The timeout might be disabled from the VTY */ + if (trans->net->ncss_guard_timeout == 0) + return; + + LOGP(DMM, LOGL_NOTICE, "SS/USSD session timeout, releasing " + "transaction (trans=%p, callref=%x)\n", trans, trans->callref); + + /* Indicate connection release to subscriber (if active) */ + if (trans->conn != NULL) { + /* This pair of cause location and value is used by commercial networks */ + msc_send_ussd_release_complete_cause(trans->conn, trans->transaction_id, + GSM48_CAUSE_LOC_PUN_S_LU, GSM48_CC_CAUSE_NORMAL_UNSPEC); + } + + /* Terminate GSUP session with EUSE */ + gsup_msg.message_type = OSMO_GSUP_MSGT_PROC_SS_ERROR; + OSMO_STRLCPY_ARRAY(gsup_msg.imsi, trans->vsub->imsi); + + gsup_msg.session_state = OSMO_GSUP_SESSION_STATE_END; + gsup_msg.session_id = trans->callref; + gsup_msg.cause = GMM_CAUSE_NET_FAIL; + + osmo_gsup_client_enc_send(trans->net->vlr->gsup_client, &gsup_msg); + + /* Finally, release this transaction */ + trans_free(trans); +} + /* Entry point for call independent MO SS messages */ int gsm0911_rcv_nc_ss(struct ran_conn *conn, struct msgb *msg) { @@ -108,6 +141,10 @@ int gsm0911_rcv_nc_ss(struct ran_conn *conn, struct msgb *msg) return -ENOMEM; } + /* Init inactivity timer */ + osmo_timer_setup(&trans->ss.timer_guard, + ncss_session_timeout_handler, trans); + /* Count active NC SS/USSD sessions */ osmo_counter_inc(conn->network->active_nc_ss); @@ -116,6 +153,12 @@ int gsm0911_rcv_nc_ss(struct ran_conn *conn, struct msgb *msg) cm_service_request_concludes(conn, msg); } + /* (Re)schedule the inactivity timer */ + if (conn->network->ncss_guard_timeout > 0) { + osmo_timer_schedule(&trans->ss.timer_guard, + conn->network->ncss_guard_timeout, 0); + } + /* Attempt to extract Facility IE */ rc = gsm0480_extract_ie_by_tag(gh, msgb_l3len(msg), &facility_ie, &facility_ie_len, GSM0480_IE_FACILITY); @@ -233,6 +276,12 @@ static int handle_paging_event(unsigned int hooknum, unsigned int event, transt->conn = ran_conn_get(conn, RAN_CONN_USE_TRANS_NC_SS); transt->paging_request = NULL; + /* (Re)schedule the inactivity timer */ + if (conn->network->ncss_guard_timeout > 0) { + osmo_timer_schedule(&transt->ss.timer_guard, + conn->network->ncss_guard_timeout, 0); + } + /* Send stored message */ ss_msg = transt->ss.msg; gh = (struct gsm48_hdr *) msgb_push(ss_msg, sizeof(*gh)); @@ -317,6 +366,10 @@ static struct gsm_trans *establish_nc_ss_trans(struct gsm_network *net, } trans->transaction_id = tid; + /* Init inactivity timer */ + osmo_timer_setup(&trans->ss.timer_guard, + ncss_session_timeout_handler, trans); + /* Attempt to find connection */ conn = connection_for_subscr(vsub); if (conn) { @@ -371,6 +424,9 @@ void _gsm911_nc_ss_trans_free(struct gsm_trans *trans) if (trans->ss.msg != NULL) msgb_free(trans->ss.msg); + /* Stop inactivity timer */ + osmo_timer_del(&trans->ss.timer_guard); + /* One session less */ osmo_counter_dec(trans->net->active_nc_ss); } @@ -420,6 +476,12 @@ int gsm0911_gsup_handler(struct vlr_subscr *vsub, return 0; } + /* (Re)schedule the inactivity timer */ + if (net->ncss_guard_timeout > 0) { + osmo_timer_schedule(&trans->ss.timer_guard, + net->ncss_guard_timeout, 0); + } + /* Allocate and prepare a new MT message */ ss_msg = gsm48_msgb_alloc_name("GSM 04.08 SS/USSD"); gh = (struct gsm48_hdr *) msgb_push(ss_msg, sizeof(*gh)); diff --git a/src/libmsc/msc_vty.c b/src/libmsc/msc_vty.c index 078b83aea..5aa533b1f 100644 --- a/src/libmsc/msc_vty.c +++ b/src/libmsc/msc_vty.c @@ -375,6 +375,18 @@ ALIAS_DEPRECATED(cfg_msc_mncc_guard_timeout, "mncc-guard-timeout <0-255>", MNCC_GUARD_TIMEOUT_STR MNCC_GUARD_TIMEOUT_VALUE_STR); +#define NCSS_STR "Configure call independent Supplementary Services\n" + +DEFUN(cfg_msc_ncss_guard_timeout, + cfg_msc_ncss_guard_timeout_cmd, + "ncss guard-timeout <0-255>", + NCSS_STR "Set guard timer for session activity\n" + "guard timer value (sec.), or 0 to disable\n") +{ + gsmnet->ncss_guard_timeout = atoi(argv[0]); + return CMD_SUCCESS; +} + DEFUN(cfg_msc_assign_tmsi, cfg_msc_assign_tmsi_cmd, "assign-tmsi", "Assign TMSI during Location Updating.\n") @@ -496,6 +508,8 @@ static int config_write_msc(struct vty *vty) vty_out(vty, " mncc external %s%s", gsmnet->mncc_sock_path, VTY_NEWLINE); vty_out(vty, " mncc guard-timeout %i%s", gsmnet->mncc_guard_timeout, VTY_NEWLINE); + vty_out(vty, " ncss guard-timeout %i%s", + gsmnet->ncss_guard_timeout, VTY_NEWLINE); vty_out(vty, " %sassign-tmsi%s", gsmnet->vlr->cfg.assign_tmsi? "" : "no ", VTY_NEWLINE); @@ -1588,6 +1602,7 @@ void msc_vty_init(struct gsm_network *msc_network) install_element(MSC_NODE, &cfg_msc_mncc_external_cmd); install_element(MSC_NODE, &cfg_msc_mncc_guard_timeout_cmd); install_element(MSC_NODE, &cfg_msc_deprecated_mncc_guard_timeout_cmd); + install_element(MSC_NODE, &cfg_msc_ncss_guard_timeout_cmd); install_element(MSC_NODE, &cfg_msc_no_assign_tmsi_cmd); install_element(MSC_NODE, &cfg_msc_auth_tuple_max_reuse_count_cmd); install_element(MSC_NODE, &cfg_msc_auth_tuple_reuse_on_error_cmd); diff --git a/src/libmsc/osmo_msc.c b/src/libmsc/osmo_msc.c index 9828da164..5c6f0aa2e 100644 --- a/src/libmsc/osmo_msc.c +++ b/src/libmsc/osmo_msc.c @@ -54,6 +54,7 @@ struct gsm_network *gsm_network_init(void *ctx, mncc_recv_cb_t mncc_recv) net->t3212 = 5; net->mncc_guard_timeout = 180; + net->ncss_guard_timeout = 30; net->paging_response_timer = MSC_PAGING_RESPONSE_TIMER_DEFAULT; diff --git a/tests/test_nodes.vty b/tests/test_nodes.vty index f2312d144..fb9e5f051 100644 --- a/tests/test_nodes.vty +++ b/tests/test_nodes.vty @@ -34,6 +34,7 @@ OsmoMSC(config-msc)# list mncc internal mncc external MNCC_SOCKET_PATH mncc guard-timeout <0-255> + ncss guard-timeout <0-255> no assign-tmsi auth-tuple-max-reuse-count <-1-2147483647> auth-tuple-reuse-on-error (0|1) @@ -50,6 +51,12 @@ OsmoMSC(config-msc)# list mgw remote-port <0-65535> ... +OsmoMSC(config-msc)# ncss? + ncss Configure call independent Supplementary Services + +OsmoMSC(config-msc)# ncss ? + guard-timeout Set guard timer for session activity + OsmoMSC(config-msc)# mncc? mncc Configure Mobile Network Call Control @@ -123,6 +130,7 @@ network periodic location update 30 msc mncc guard-timeout 180 + ncss guard-timeout 30 assign-tmsi cs7-instance-a 0 ...