tbf_fsm: Introduce new event to act upon contention resolution success

This is a preparation towards fixing MS not recreating a DL-TBF (being
assigned on CCCH) when MS starts an UL-TBF and finishes contention
resolution.

A counter is removed which was counting contention resolution (MS) on
the wrong place.

Change-Id: I8b9555864d3615ce0a024b641c67921f82273a8d
diff --git a/src/tbf_fsm.c b/src/tbf_fsm.c
index 9ddbd69..6fe2a7a 100644
--- a/src/tbf_fsm.c
+++ b/src/tbf_fsm.c
@@ -45,6 +45,7 @@
 	{ TBF_EV_ASSIGN_READY_CCCH, "ASSIGN_READY_CCCH" },
 	{ TBF_EV_ASSIGN_PCUIF_CNF, "ASSIGN_PCUIF_CNF" },
 	{ TBF_EV_FIRST_UL_DATA_RECVD, "FIRST_UL_DATA_RECVD" },
+	{ TBF_EV_CONTENTION_RESOLUTION_MS_SUCCESS, "CONTENTION_RESOLUTION_MS_SUCCESS" },
 	{ TBF_EV_DL_ACKNACK_MISS, "DL_ACKNACK_MISS" },
 	{ TBF_EV_LAST_DL_DATA_SENT, "LAST_DL_DATA_SENT" },
 	{ TBF_EV_LAST_UL_DATA_RECVD, "LAST_UL_DATA_RECVD" },
@@ -230,6 +231,10 @@
 			dl_tbf = NULL;
 		}
 		break;
+	case TBF_EV_CONTENTION_RESOLUTION_MS_SUCCESS:
+		OSMO_ASSERT(tbf_direction(ctx->tbf) == GPRS_RLCMAC_UL_TBF);
+		ul_tbf_contention_resolution_success(tbf_as_ul_tbf(ctx->tbf));
+		break;
 	case TBF_EV_DL_ACKNACK_MISS:
 		OSMO_ASSERT(tbf_direction(ctx->tbf) == GPRS_RLCMAC_DL_TBF);
 		/* DL TBF: we missed a DL ACK/NACK. If we started assignment
@@ -279,6 +284,12 @@
 	bool new_ul_tbf_requested;
 
 	switch (event) {
+	case TBF_EV_CONTENTION_RESOLUTION_MS_SUCCESS:
+		OSMO_ASSERT(tbf_direction(ctx->tbf) == GPRS_RLCMAC_UL_TBF);
+		/* UL TBF: If MS only sends 1 RLCMAC UL block, it can be that we
+		 * end up in FINISHED state before sending the first UL ACK/NACK */
+		ul_tbf_contention_resolution_success(tbf_as_ul_tbf(ctx->tbf));
+		break;
 	case TBF_EV_DL_ACKNACK_MISS:
 		OSMO_ASSERT(tbf_direction(ctx->tbf) == GPRS_RLCMAC_DL_TBF);
 		break;
@@ -480,6 +491,7 @@
 	[TBF_ST_FLOW] = {
 		.in_event_mask =
 			X(TBF_EV_FIRST_UL_DATA_RECVD) |
+			X(TBF_EV_CONTENTION_RESOLUTION_MS_SUCCESS) |
 			X(TBF_EV_DL_ACKNACK_MISS) |
 			X(TBF_EV_LAST_DL_DATA_SENT) |
 			X(TBF_EV_LAST_UL_DATA_RECVD) |
@@ -496,6 +508,7 @@
 	},
 	[TBF_ST_FINISHED] = {
 		.in_event_mask =
+			X(TBF_EV_CONTENTION_RESOLUTION_MS_SUCCESS) |
 			X(TBF_EV_DL_ACKNACK_MISS) |
 			X(TBF_EV_FINAL_ACK_RECVD) |
 			X(TBF_EV_FINAL_UL_ACK_CONFIRMED) |
diff --git a/src/tbf_fsm.h b/src/tbf_fsm.h
index 903bcd7..0acd4e5 100644
--- a/src/tbf_fsm.h
+++ b/src/tbf_fsm.h
@@ -29,6 +29,7 @@
 	TBF_EV_ASSIGN_READY_CCCH, /* TBF Start Time timer triggered */
 	TBF_EV_ASSIGN_PCUIF_CNF, /* Transmission of IMM.ASS for DL TBF to the MS confirmed by BTS over PCUIF */
 	TBF_EV_FIRST_UL_DATA_RECVD, /* UL TBF: Received first UL data from MS. Equals to Contention Resolution completed on the network side */
+	TBF_EV_CONTENTION_RESOLUTION_MS_SUCCESS, /* UL TBF: Contention resolution success at the mobile station side (first UL_ACK_NACK confirming TLLI is received at the MS) */
 	TBF_EV_DL_ACKNACK_MISS, /* DL TBF: We polled for DL ACK/NACK but we received none (POLL timeout) */
 	TBF_EV_LAST_DL_DATA_SENT, /* DL TBF sends RLCMAC block containing last DL avilable data buffered */
 	TBF_EV_LAST_UL_DATA_RECVD, /* UL TBF sends RLCMAC block containing last UL data (cv=0) */
diff --git a/src/tbf_ul.cpp b/src/tbf_ul.cpp
index 40129ec..bd885b6 100644
--- a/src/tbf_ul.cpp
+++ b/src/tbf_ul.cpp
@@ -257,6 +257,7 @@
 	return 0;
 }
 
+/* 3GPP TS 44.060 sec 7a.2.1 Contention Resolution */
 void gprs_rlcmac_ul_tbf::contention_resolution_start()
 {
 	/* 3GPP TS 44.018 sec 11.1.2 Timers on the network side: "This timer is
@@ -274,20 +275,17 @@
 }
 void gprs_rlcmac_ul_tbf::contention_resolution_success()
 {
-	if (m_contention_resolution_done)
-		return;
+	/* now we must set this flag, so we are allowed to assign downlink
+	 * TBF on PACCH. it is only allowed when TLLI is acknowledged
+	 * (3GPP TS 44.060 sec 7.1.3.1). */
+	m_contention_resolution_done = true;
 
-	/* 3GPP TS 44.060 sec 7a.2.1 Contention Resolution */
 	/* 3GPP TS 44.018 3.5.2.1.4 Packet access completion: The one phase
 	   packet access procedure is completed at a successful contention
 	   resolution. The mobile station has entered the packet transfer mode.
 	   Timer T3141 is stopped on the network side */
 	t_stop(T3141, "Contention resolution success (UL-TBF, CCCH)");
 
-	/* now we must set this flag, so we are allowed to assign downlink
-	 * TBF on PACCH. it is only allowed when TLLI is acknowledged. */
-	m_contention_resolution_done = true;
-
 	bts_do_rate_ctr_inc(bts, CTR_IMMEDIATE_ASSIGN_UL_TBF_CONTENTION_RESOLUTION_SUCCESS);
 }
 
diff --git a/src/tbf_ul_ack_fsm.c b/src/tbf_ul_ack_fsm.c
index b0506d1..f6e7a0d 100644
--- a/src/tbf_ul_ack_fsm.c
+++ b/src/tbf_ul_ack_fsm.c
@@ -89,8 +89,8 @@
 	 * on the mobile station side when the mobile station receives a
 	 * PACKET UPLINK ACK/NACK"
 	 */
-	if (ms_tlli(ms) != GSM_RESERVED_TMSI)
-		ul_tbf_contention_resolution_success(ctx->tbf);
+	if (ms_tlli(ms) != GSM_RESERVED_TMSI && !ul_tbf_contention_resolution_done(ctx->tbf))
+		osmo_fsm_inst_dispatch(tbf_state_fi(ul_tbf_as_tbf(ctx->tbf)), TBF_EV_CONTENTION_RESOLUTION_MS_SUCCESS, NULL);
 
 	if (final) {
 		tbf_set_polling(ul_tbf_as_tbf(tbf), new_poll_fn, d->ts, PDCH_ULC_POLL_UL_ACK);
diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err
index 1124462..31e2a4c 100644
--- a/tests/tbf/TbfTest.err
+++ b/tests/tbf/TbfTest.err
@@ -1912,6 +1912,7 @@
 Got MS: TLLI = 0xf1223344, TA = 7
 UL_ACK_TBF(UL-TFI_0){SCHED_UL_ACK}: Received Event CREATE_RLCMAC_MSG
 PDCH(bts=0,trx=0,ts=7) POLL scheduled at FN 2654167 + 17 = 2654184
+TBF(UL-TFI_0){FINISHED}: Received Event CONTENTION_RESOLUTION_MS_SUCCESS
 TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FINISHED) stopping timer T3141 [Contention resolution success (UL-TBF, CCCH)]
 TBF(TFI=0 TLLI=0xf1223344 DIR=UL STATE=FINISHED) Scheduled UL Acknowledgement polling on PACCH (FN=2654184, TS=7)
 UL_ACK_TBF(UL-TFI_0){SCHED_UL_ACK}: state_chg to WAIT_ACK