tbf/tests: Add tests for EGPRS TBF establishment

Add a test for EGPRS two phase access based on RA caps.

Add a test for DL TBFs where data block are encoded with each MCS.

Sponsored-by: On-Waves ehf
diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp
index 54269c1..e1be844 100644
--- a/tests/tbf/TbfTest.cpp
+++ b/tests/tbf/TbfTest.cpp
@@ -166,7 +166,7 @@
 }
 
 static gprs_rlcmac_dl_tbf *create_dl_tbf(BTS *the_bts, uint8_t ms_class,
-	uint8_t *trx_no_)
+	uint8_t egprs_ms_class, uint8_t *trx_no_)
 {
 	gprs_rlcmac_bts *bts;
 	int tfi;
@@ -178,7 +178,7 @@
 
 	tfi = the_bts->tfi_find_free(GPRS_RLCMAC_DL_TBF, &trx_no, -1);
 	OSMO_ASSERT(tfi >= 0);
-	dl_tbf = tbf_alloc_dl_tbf(bts, NULL, trx_no, ms_class, 0, 1);
+	dl_tbf = tbf_alloc_dl_tbf(bts, NULL, trx_no, ms_class, egprs_ms_class, 1);
 	check_tbf(dl_tbf);
 
 	/* "Establish" the DL TBF */
@@ -249,7 +249,7 @@
 	gprs_rlcmac_tbf *new_tbf;
 
 	setup_bts(&the_bts, ts_no);
-	dl_tbf = create_dl_tbf(&the_bts, ms_class, &trx_no);
+	dl_tbf = create_dl_tbf(&the_bts, ms_class, 0, &trx_no);
 	dl_tbf->update_ms(tlli, GPRS_RLCMAC_DL_TBF);
 	ms = dl_tbf->ms();
 
@@ -324,7 +324,7 @@
 	setup_bts(&the_bts, ts_no);
 	bts->dl_tbf_idle_msec = 200;
 
-	dl_tbf = create_dl_tbf(&the_bts, ms_class, &trx_no);
+	dl_tbf = create_dl_tbf(&the_bts, ms_class, 0, &trx_no);
 	dl_tbf->update_ms(tlli, GPRS_RLCMAC_DL_TBF);
 
 	for (i = 0; i < sizeof(llc_data); i++)
@@ -389,8 +389,8 @@
 
 	setup_bts(&the_bts, ts_no);
 
-	dl_tbf[0] = create_dl_tbf(&the_bts, ms_class, &trx_no);
-	dl_tbf[1] = create_dl_tbf(&the_bts, ms_class, &trx_no);
+	dl_tbf[0] = create_dl_tbf(&the_bts, ms_class, 0, &trx_no);
+	dl_tbf[1] = create_dl_tbf(&the_bts, ms_class, 0, &trx_no);
 
 	dl_tbf[0]->update_ms(0xf1000001, GPRS_RLCMAC_DL_TBF);
 	dl_tbf[1]->update_ms(0xf1000002, GPRS_RLCMAC_DL_TBF);
@@ -619,7 +619,7 @@
 
 static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase(BTS *the_bts,
 	uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta,
-	uint8_t ms_class)
+	uint8_t ms_class, uint8_t egprs_ms_class)
 {
 	GprsMs *ms;
 	uint32_t rach_fn = *fn - 51;
@@ -660,6 +660,14 @@
 	ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability.
 		MS_RA_capability_value[0].u.Content.Multislot_capability.
 		GPRS_multislot_class = ms_class;
+	if (egprs_ms_class) {
+		ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability.
+			MS_RA_capability_value[0].u.Content.Multislot_capability.
+			Exist_EGPRS_multislot_class = 1;
+		ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability.
+			MS_RA_capability_value[0].u.Content.Multislot_capability.
+			EGPRS_multislot_class = ms_class;
+	}
 
 	send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn);
 
@@ -715,7 +723,8 @@
 	}
 }
 
-static void transmit_dl_data(BTS *the_bts, uint32_t tlli, uint32_t *fn)
+static void transmit_dl_data(BTS *the_bts, uint32_t tlli, uint32_t *fn,
+	uint8_t slots = 0xff)
 {
 	gprs_rlcmac_dl_tbf *dl_tbf;
 	GprsMs *ms;
@@ -728,10 +737,13 @@
 
 	while (dl_tbf->have_data()) {
 		uint8_t bn = fn2bn(*fn);
-		for (ts_no = 0 ; ts_no < 8; ts_no += 1)
+		for (ts_no = 0 ; ts_no < 8; ts_no += 1) {
+			if (!(slots & (1 << ts_no)))
+				continue;
 			gprs_rlcmac_rcv_rts_block(the_bts->bts_data(),
 				dl_tbf->trx->trx_no, ts_no, 0,
 				*fn, bn);
+		}
 		*fn = fn_add_blocks(*fn, 1);
 	}
 }
@@ -778,7 +790,8 @@
 
 	setup_bts(&the_bts, ts_no, 4);
 
-	ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli, &fn, qta, ms_class);
+	ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli, &fn, qta,
+		ms_class, 0);
 
 	ms = ul_tbf->ms();
 	fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta());
@@ -806,7 +819,8 @@
 
 	setup_bts(&the_bts, ts_no, 4);
 
-	ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta, ms_class);
+	ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta,
+		ms_class, 0);
 
 	ms1 = ul_tbf->ms();
 	fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta());
@@ -827,7 +841,8 @@
 	OSMO_ASSERT(ms1->llc_queue()->size() == 0);
 
 	/* Now establish a new TBF for the RA UPDATE COMPLETE (new TLLI) */
-	ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli2, &fn, qta, ms_class);
+	ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli2, &fn, qta,
+		ms_class, 0);
 
 	ms2 = ul_tbf->ms();
 
@@ -872,7 +887,8 @@
 
 	setup_bts(&the_bts, ts_no, 1);
 
-	ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta, ms_class);
+	ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta,
+		ms_class, 0);
 
 	ms1 = ul_tbf->ms();
 	fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta());
@@ -892,7 +908,8 @@
 	OSMO_ASSERT(ms1 == ms);
 
 	/* Now establish a new UL TBF, this will consume one LLC packet */
-	ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta, ms_class);
+	ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta,
+		ms_class, 0);
 
 	ms2 = ul_tbf->ms();
 	fprintf(stderr, "New MS: TLLI = 0x%08x, TA = %d, IMSI = %s, LLC = %d\n",
@@ -931,7 +948,8 @@
 
 	setup_bts(&the_bts, ts_no, 1);
 
-	ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta, ms_class);
+	ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta,
+		ms_class, 0);
 
 	ms1 = ul_tbf->ms();
 	fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta());
@@ -992,7 +1010,8 @@
 
 	setup_bts(&the_bts, ts_no, 1);
 
-	ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta, ms_class);
+	ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli1, &fn, qta,
+		ms_class, 0);
 
 	ms1 = ul_tbf->ms();
 	fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta());
@@ -1160,6 +1179,122 @@
 	gprs_bssgp_destroy();
 }
 
+static void test_tbf_egprs_two_phase()
+{
+	BTS the_bts;
+	int ts_no = 7;
+	uint32_t fn = 2654218;
+	uint16_t qta = 31;
+	uint32_t tlli = 0xf1223344;
+	const char *imsi = "0011223344";
+	uint8_t ms_class = 1;
+	uint8_t egprs_ms_class = 1;
+	gprs_rlcmac_ul_tbf *ul_tbf;
+	GprsMs *ms;
+	uint8_t test_data[256];
+
+	printf("=== start %s ===\n", __func__);
+
+	memset(test_data, 1, sizeof(test_data));
+
+	setup_bts(&the_bts, ts_no, 4);
+	the_bts.bts_data()->initial_mcs_dl = 9;
+	the_bts.bts_data()->egprs_enabled = 1;
+
+	ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli, &fn, qta,
+		ms_class, egprs_ms_class);
+
+	ms = ul_tbf->ms();
+	fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta());
+	fprintf(stderr, "Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta());
+
+	send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data));
+
+	printf("=== end %s ===\n", __func__);
+}
+
+static void establish_and_use_egprs_dl_tbf(BTS *the_bts, int mcs)
+{
+	unsigned i;
+	uint8_t ms_class = 11;
+	uint8_t egprs_ms_class = 11;
+	uint32_t fn = 0;
+	uint8_t trx_no;
+	uint32_t tlli = 0xffeeddcc;
+	uint8_t test_data[512];
+
+	uint8_t rbb[64/8];
+
+	gprs_rlcmac_dl_tbf *dl_tbf;
+
+	printf("Testing MCS-%d\n", mcs);
+
+	memset(test_data, 1, sizeof(test_data));
+	the_bts->bts_data()->initial_mcs_dl = mcs;
+
+	dl_tbf = create_dl_tbf(the_bts, ms_class, egprs_ms_class, &trx_no);
+	dl_tbf->update_ms(tlli, GPRS_RLCMAC_DL_TBF);
+
+	for (i = 0; i < sizeof(llc_data); i++)
+		llc_data[i] = i%256;
+
+	OSMO_ASSERT(dl_tbf->state_is(GPRS_RLCMAC_FLOW));
+
+	/* Schedule a small LLC frame */
+	dl_tbf->append_data(ms_class, 1000, test_data, 10);
+
+	OSMO_ASSERT(dl_tbf->state_is(GPRS_RLCMAC_FLOW));
+
+	/* Drain the queue */
+	while (dl_tbf->have_data())
+		/* Request to send one RLC/MAC block */
+		request_dl_rlc_block(dl_tbf, &fn);
+
+	/* Schedule a large LLC frame */
+	dl_tbf->append_data(ms_class, 1000, test_data, sizeof(test_data));
+
+	OSMO_ASSERT(dl_tbf->state_is(GPRS_RLCMAC_FLOW));
+
+	/* Drain the queue */
+	while (dl_tbf->have_data())
+		/* Request to send one RLC/MAC block */
+		request_dl_rlc_block(dl_tbf, &fn);
+
+	OSMO_ASSERT(dl_tbf->state_is(GPRS_RLCMAC_FLOW));
+
+	/* Receive a final ACK */
+	dl_tbf->rcvd_dl_ack(1, dl_tbf->m_window.v_s(), rbb);
+
+	/* Clean up and ensure tbfs are in the correct state */
+	OSMO_ASSERT(dl_tbf->state_is(GPRS_RLCMAC_WAIT_RELEASE));
+	dl_tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE;
+	check_tbf(dl_tbf);
+	tbf_free(dl_tbf);
+}
+
+static void test_tbf_egprs_dl()
+{
+	BTS the_bts;
+	gprs_rlcmac_bts *bts;
+	uint8_t ts_no = 4;
+	int i;
+
+	printf("=== start %s ===\n", __func__);
+
+	bts = the_bts.bts_data();
+
+	setup_bts(&the_bts, ts_no);
+	bts->dl_tbf_idle_msec = 200;
+	bts->egprs_enabled = 1;
+
+	for (i = 1; i <= 9; i++)
+		establish_and_use_egprs_dl_tbf(&the_bts, i);
+
+	printf("=== end %s ===\n", __func__);
+}
+
+
+
 static const struct log_info_cat default_categories[] = {
         {"DCSN1", "\033[1;31m", "Concrete Syntax Notation One (CSN1)", LOGL_INFO, 0},
         {"DL1IF", "\033[1;32m", "GPRS PCU L1 interface (L1IF)", LOGL_DEBUG, 1},
@@ -1219,6 +1354,8 @@
 	test_tbf_dl_reuse();
 	test_tbf_gprs_egprs();
 	test_tbf_ws();
+	test_tbf_egprs_two_phase();
+	test_tbf_egprs_dl();
 
 	if (getenv("TALLOC_REPORT_FULL"))
 		talloc_report_full(tall_pcu_ctx, stderr);