Iu: implement a user inactivity timer

The user inactivity timer is similiar to the Gb READY timer and reduces
the resources taken by an idle UE.

Change-Id: I66c2ac0350cb074aefd9a22c5121acf723f239d3
diff --git a/src/sgsn/gprs_mm_state_iu_fsm.c b/src/sgsn/gprs_mm_state_iu_fsm.c
index b098f20..e6b80d7 100644
--- a/src/sgsn/gprs_mm_state_iu_fsm.c
+++ b/src/sgsn/gprs_mm_state_iu_fsm.c
@@ -12,7 +12,8 @@
 
 static const struct osmo_tdef_state_timeout mm_state_iu_fsm_timeouts[32] = {
 	[ST_PMM_DETACHED] = { },
-	[ST_PMM_CONNECTED] = { },
+	/* non-spec -T3314 (User inactivity timer) */
+	[ST_PMM_CONNECTED] = { .T=-3314 },
 	[ST_PMM_IDLE] = { },
 };
 
@@ -47,6 +48,10 @@
 static void st_pmm_connected(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 {
 	struct sgsn_mm_ctx *ctx = fi->priv;
+	const struct RANAP_Cause user_inactive_cause = {
+		.present = RANAP_Cause_PR_radioNetwork,
+		.choice.radioNetwork = RANAP_CauseRadioNetwork_user_inactivity,
+	};
 
 	switch(event) {
 	case E_PMM_PS_CONN_RELEASE:
@@ -57,6 +62,10 @@
 		sgsn_ranap_iu_release_free(ctx, NULL);
 		mm_state_iu_fsm_state_chg(fi, ST_PMM_DETACHED);
 		break;
+	case E_PMM_USER_INACTIVITY:
+		sgsn_ranap_iu_release_free(ctx, &user_inactive_cause);
+		mm_state_iu_fsm_state_chg(fi, ST_PMM_DETACHED);
+		break;
 	case E_PMM_RA_UPDATE:
 		break;
 	}
@@ -81,6 +90,18 @@
 	}
 }
 
+static int pmm_state_fsm_timer_cb(struct osmo_fsm_inst *fi)
+{
+	switch(fi->state) {
+	case ST_PMM_CONNECTED:
+		/* timer for pmm state. state=CONNECTED: -T3314 (User inactivity timer) */
+		osmo_fsm_inst_dispatch(fi, E_PMM_USER_INACTIVITY, NULL);
+		break;
+	}
+
+	return 0;
+}
+
 static struct osmo_fsm_state mm_state_iu_fsm_states[] = {
 	[ST_PMM_DETACHED] = {
 		.in_event_mask = X(E_PMM_PS_ATTACH) | X(E_PMM_IMPLICIT_DETACH),
@@ -89,7 +110,8 @@
 		.action = st_pmm_detached,
 	},
 	[ST_PMM_CONNECTED] = {
-		.in_event_mask = X(E_PMM_PS_CONN_RELEASE) | X(E_PMM_RA_UPDATE) | X(E_PMM_IMPLICIT_DETACH),
+		.in_event_mask = X(E_PMM_PS_CONN_RELEASE) | X(E_PMM_RA_UPDATE)
+			| X(E_PMM_IMPLICIT_DETACH) | X(E_PMM_USER_INACTIVITY),
 		.out_state_mask = X(ST_PMM_DETACHED) | X(ST_PMM_IDLE),
 		.name = "Connected",
 		.action = st_pmm_connected,
@@ -109,6 +131,7 @@
 	OSMO_VALUE_STRING(E_PMM_PS_CONN_ESTABLISH),
 	OSMO_VALUE_STRING(E_PMM_IMPLICIT_DETACH),
 	OSMO_VALUE_STRING(E_PMM_RA_UPDATE),
+	OSMO_VALUE_STRING(E_PMM_USER_INACTIVITY),
 	{ 0, NULL }
 };