libmsc: add timer X36 for delaying LU connections

The idea is to allow re-using the radio channel that was used for
Location Updating to deliver MT SMS over GSUP.  This is achieved
by delaying release of a BSSAP/RANAP connection and thus delaying
the release of the radio channel.  The delay can be configured
using new timer X36 (default 0 ms), separately for GERAN and UTRAN.

Change-Id: Ic519cab55d65e47b2636124427dab1a1d80fab78
Related: osmo-ttcn3-hacks.git I74fa174ea649adb2112c8e471c0e339a2197a08d
Related: SYS#6913
diff --git a/include/osmocom/msc/msc_a.h b/include/osmocom/msc/msc_a.h
index 4099d4c..a5b624c 100644
--- a/include/osmocom/msc/msc_a.h
+++ b/include/osmocom/msc/msc_a.h
@@ -144,6 +144,9 @@
 	struct osmo_use_count use_count;
 	struct osmo_use_count_entry use_count_buf[8];
 	int32_t max_total_use_count;
+
+	/* Used for scheduling X36 (additional delay for LU connections) */
+	struct osmo_timer_list lu_delay_timer;
 };
 
 osmo_static_assert(offsetof(struct msc_a, c) == 0, msc_role_common_first_member_of_msc_a);
diff --git a/src/libmsc/msc_a.c b/src/libmsc/msc_a.c
index db1d998..bff5e67 100644
--- a/src/libmsc/msc_a.c
+++ b/src/libmsc/msc_a.c
@@ -155,6 +155,44 @@
 	}
 }
 
+static void lu_delay_timer_cb(void *data)
+{
+	struct msc_a *msc_a = (struct msc_a *)data;
+	msc_a_put(msc_a, MSC_A_USE_LOCATION_UPDATING);
+}
+
+static void msc_a_put_lu_deferred(struct msc_a *msc_a)
+{
+	unsigned long Tval;
+
+	/* The idea behind timer X36 is to allow re-using the radio channel that was used for
+	 * Location Updating to deliver MT SMS over GSUP.  This is achieved by delaying
+	 * release of a BSSAP/RANAP connection and thus delaying the release of the radio
+	 * channel.  The delay can be configured separately for GERAN and UTRAN. */
+	switch (msc_a->c.ran->type) {
+	case OSMO_RAT_GERAN_A:
+		Tval = osmo_tdef_get(msc_tdefs_geran, -36, OSMO_TDEF_MS, 0);
+		break;
+	case OSMO_RAT_UTRAN_IU:
+		Tval = osmo_tdef_get(msc_tdefs_utran, -36, OSMO_TDEF_MS, 0);
+		break;
+	default:
+		Tval = 0;
+		break;
+	}
+
+	if (Tval == 0) {
+		/* no delay, put LU token immediately */
+		msc_a_put(msc_a, MSC_A_USE_LOCATION_UPDATING);
+		return;
+	}
+
+	LOG_MSC_A(msc_a, LOGL_INFO, "Keeping LU token for +%lu ms\n", Tval);
+	osmo_timer_schedule(&msc_a->lu_delay_timer,
+			    Tval / 1000, /* seconds */
+			    Tval % 1000 * 1000); /* microseconds */
+}
+
 static void evaluate_acceptance_outcome(struct osmo_fsm_inst *fi, bool conn_accepted)
 {
 	struct msc_a *msc_a = fi->priv;
@@ -180,7 +218,7 @@
 		osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_ATTACHED, msc_a_vsub(msc_a));
 
 	if (msc_a->complete_layer3_type == COMPLETE_LAYER3_LU)
-		msc_a_put(msc_a, MSC_A_USE_LOCATION_UPDATING);
+		msc_a_put_lu_deferred(msc_a);
 
 	if (conn_accepted && msc_a->complete_layer3_type == COMPLETE_LAYER3_CM_RE_ESTABLISH_REQ) {
 		/* Trigger new Assignment to recommence the voice call. A little dance here because normally we verify
@@ -1011,6 +1049,8 @@
 	/* Invalidate the active conn in VLR subscriber state, if any. */
 	if (vsub && vsub->msc_conn_ref == msc_a)
 		vsub->msc_conn_ref = NULL;
+
+	osmo_timer_del(&msc_a->lu_delay_timer);
 }
 
 const struct value_string msc_a_fsm_event_names[] = {
@@ -1225,6 +1265,7 @@
 	osmo_use_count_make_static_entries(&msc_a->use_count, msc_a->use_count_buf, ARRAY_SIZE(msc_a->use_count_buf));
 	/* Start timeout for first state */
 	msc_a_state_chg_always(msc_a, MSC_A_ST_VALIDATE_L3);
+	osmo_timer_setup(&msc_a->lu_delay_timer, &lu_delay_timer_cb, msc_a);
 	return msc_a;
 }
 
diff --git a/src/libmsc/ran_infra.c b/src/libmsc/ran_infra.c
index 6a17840..79de7d2 100644
--- a/src/libmsc/ran_infra.c
+++ b/src/libmsc/ran_infra.c
@@ -44,6 +44,9 @@
 	{ .T = -2, .default_val = 30, .desc = "RAN connection release sanity timeout" }, \
 	{ .T = -3, .default_val = 10, .desc = "Timeout to find a target BSS after Handover Required" }, \
 	{ .T = -4, .default_val = 10, .desc = "Paging response timeout" }, \
+	{ .T = -36, .default_val = 0, .unit = OSMO_TDEF_MS, \
+	  .desc = "Delay connection release after LU.  Useful to optimize an SMSC to dispatch " \
+		  "pending messages within the initial connection." }, \
 
 struct osmo_tdef msc_tdefs_geran[] = {
 	RAN_TDEFS