[PATCH] FANR UL and DL flow changes and UT fixes

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/osmocom-net-gprs@lists.osmocom.org/.

Aravind Sirsikar arvind.sirsikar at radisys.com
Thu Mar 10 05:45:14 UTC 2016


FANR enabled TBF allocation for both UL and DL based
on ms capability

This is 5th patch among series of patches for FANR feature

The TbfTest.err and EdgeTest.err updation is not part of this patch
The Ms capability decoding is not part of this patch
---
 src/bts.cpp               |  132 +++++++++-----
 src/bts.h                 |    2 +-
 src/decoding.cpp          |  441 +++++++++++++++++++++++++++++++--------------
 src/decoding.h            |   24 +++
 src/gprs_bssgp_pcu.cpp    |   12 +-
 src/tbf.cpp               |   24 ++-
 src/tbf.h                 |   12 +-
 src/tbf_dl.cpp            |   10 +-
 src/tbf_ul.cpp            |    2 +-
 tests/alloc/AllocTest.cpp |   28 +--
 tests/edge/EdgeTest.cpp   |  235 ++++++++++++++++++++++--
 tests/tbf/TbfTest.cpp     |   16 +-
 12 files changed, 707 insertions(+), 231 deletions(-)

diff --git a/src/bts.cpp b/src/bts.cpp
index ddce6dc..7897d25 100644
--- a/src/bts.cpp
+++ b/src/bts.cpp
@@ -552,7 +552,7 @@ int BTS::rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta)
 		// Create new TBF
 		#warning "Copy and pate with other routines.."
 		/* set class to 0, since we don't know the multislot class yet */
-		tbf = tbf_alloc_ul_tbf(&m_bts, NULL, -1, 0, 0, 1);
+		tbf = tbf_alloc_ul_tbf(&m_bts, NULL, -1, 0, 0, 1, false);
 		if (!tbf) {
 			LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
 			/* FIXME: send reject */
@@ -641,7 +641,7 @@ void BTS::snd_dl_ass(gprs_rlcmac_tbf *tbf, uint8_t poll, const char *imsi)
 }
 
 
-GprsMs *BTS::ms_alloc(uint8_t ms_class, uint8_t egprs_ms_class)
+GprsMs *BTS::ms_alloc(uint8_t ms_class, uint8_t egprs_ms_class, bool is_fanr_capable)
 {
 	GprsMs *ms;
 	ms = ms_store().create_ms();
@@ -649,6 +649,7 @@ GprsMs *BTS::ms_alloc(uint8_t ms_class, uint8_t egprs_ms_class)
 	ms->set_timeout(m_bts.ms_idle_sec);
 	ms->set_ms_class(ms_class);
 	ms->set_egprs_ms_class(egprs_ms_class);
+	ms->set_fanr_capable(is_fanr_capable);
 
 	return ms;
 }
@@ -1037,7 +1038,7 @@ void gprs_rlcmac_pdch::rcv_control_egprs_dl_ack_nack(EGPRS_PD_AckNack_t *ack_nac
 		/* This call will register the new TBF with the MS on success */
 		tbf_alloc_ul(bts_data(), tbf->trx->trx_no,
 			tbf->ms_class(), tbf->ms()->egprs_ms_class(),
-			tbf->tlli(), tbf->ta(), tbf->ms());
+			tbf->tlli(), tbf->ta(), tbf->ms(), tbf->ms()->is_fanr_capable());
 
 		/* schedule uplink assignment */
 		tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
@@ -1097,7 +1098,7 @@ void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_n
 		/* This call will register the new TBF with the MS on success */
 		tbf_alloc_ul(bts_data(), tbf->trx->trx_no,
 			tbf->ms_class(), tbf->ms()->egprs_ms_class(),
-			tbf->tlli(), tbf->ta(), tbf->ms());
+			tbf->tlli(), tbf->ta(), tbf->ms(), tbf->ms()->is_fanr_capable());
 
 		/* schedule uplink assignment */
 		tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
@@ -1119,6 +1120,7 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
 		uint32_t tlli = request->ID.u.TLLI;
 		uint8_t ms_class = 0;
 		uint8_t egprs_ms_class = 0;
+		bool    is_egprs_ms_fanr_capable = 0;
 		uint8_t ta = 0;
 		struct pcu_l1_meas meas;
 
@@ -1174,6 +1176,10 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
 			egprs_ms_class =
 				Decoding::get_egprs_ms_class_by_capability(
 					&request->MS_Radio_Access_capability);
+
+			is_egprs_ms_fanr_capable =
+				Decoding::is_ms_fanr_capable(
+					&request->MS_Radio_Access_capability);
 		}
 		if (!ms_class)
 			LOGP(DRLCMAC, LOGL_NOTICE, "MS does not give us a class.\n");
@@ -1182,7 +1188,7 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
 				"MS supports EGPRS multislot class %d.\n",
 				egprs_ms_class);
 		ul_tbf = tbf_alloc_ul(bts_data(), trx_no(), ms_class,
-			egprs_ms_class, tlli, ta, ms);
+			egprs_ms_class, tlli, ta, ms, is_egprs_ms_fanr_capable);
 		if (!ul_tbf)
 			return;
 
@@ -1193,8 +1199,10 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
 		ul_tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
 
 		/* get capabilities */
-		if (ul_tbf->ms())
+		if (ul_tbf->ms()) {
 			ul_tbf->ms()->set_egprs_ms_class(egprs_ms_class);
+			ul_tbf->ms()->set_fanr_capable(is_egprs_ms_fanr_capable);
+		}
 
 		/* get measurements */
 		if (ul_tbf->ms()) {
@@ -1326,48 +1334,84 @@ int gprs_rlcmac_pdch::rcv_data_data_block(uint8_t *data, uint32_t fn,
 {
         int rc;
         struct gprs_rlc_ul_header_generic rlc_dec;
-        struct gprs_rlcmac_ul_tbf *tbf;
-        unsigned len = cs.maxBytesUL();
+        struct gprs_rlcmac_ul_tbf *tbf = NULL;
+
+	/* These are always data blocks, since EGPRS still uses CS-1 for
+	* control blocks (see 44.060, section 10.3, 1st par.)
+	*/
+	if (cs.isEgprs()) {
+		if (!bts()->bts_data()->egprs_enabled) {
+			LOGP(DRLCMACUL, LOGL_ERROR,
+			"Got %s RLC block but EGPRS is not enabled\n",
+			cs.name());
+			return -EINVAL;
+		}
 
-        /* These are always data blocks, since EGPRS still uses CS-1 for
-         * control blocks (see 44.060, section 10.3, 1st par.)
-         */
-        if (cs.isEgprs()) {
-                if (!bts()->bts_data()->egprs_enabled) {
-                        LOGP(DRLCMACUL, LOGL_ERROR,
-                                "Got %s RLC block but EGPRS is not enabled\n",
-                                cs.name());
-                        return -EINVAL;
-                }
+		uint8_t tfi = ((data[1] & 0x7) << 2)  | ((data[0] & 0xc0) >> 6);
 
-        }
+	        /* find TBF inst from given TFI */
+		tbf = ul_tbf_by_tfi(tfi);
+		if (!tbf) {
+			LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA unknown TFI=%d\n",
+				tfi);
+			return 0;
+		}
 
-        LOGP(DRLCMACUL, LOGL_DEBUG, "  UL data: %s\n", osmo_hexdump(data, len));
+		rc = Decoding::rlc_parse_ul_data_header_egprs(&rlc_dec, data, cs, tbf);
+		if (rc == -ENOTSUP ) {
+			LOGP(DRLCMACUL, LOGL_ERROR,
+				"Got %s RLC block but header parsing has failed\n",
+			cs.name());
+			bts()->decode_error();
+			return rc;
+		}
 
-        rc = Decoding::rlc_parse_ul_data_header(&rlc_dec, data, cs);
-        if (rc == -ENOTSUP ) {
-                LOGP(DRLCMACUL, LOGL_ERROR,
-                        "Got %s RLC block but header parsing has failed\n",
-                        cs.name());
-                bts()->decode_error();
-                return rc;
-        }
+		if (1 == rlc_dec.pani) {
+			if (false == tbf->is_fanr_enabled())
+				LOGP(DRLCMACUL, LOGL_ERROR, "Received PAN field "
+						"but FANR is not activated for TBF\n");
+		}
 
-        LOGP(DRLCMACUL, LOGL_INFO,
-                "Got %s RLC block: "
-                "R=%d, SI=%d, TFI=%d, CPS=%d, RSB=%d\n",
-                cs.name(),
-                rlc_dec.r, rlc_dec.si, rlc_dec.tfi, rlc_dec.cps, rlc_dec.rsb
-                );
-        /* find TBF inst from given TFI */
-        tbf = ul_tbf_by_tfi(rlc_dec.tfi);
-        if (!tbf) {
-                LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA unknown TFI=%d\n",
-                        rlc_dec.tfi);
-                return 0;
-        }
+		struct gprs_rlcmac_bts* bts_info =  bts_data();
+		if (false == bts_info->fanr_enabled) {
+			if (1 == rlc_dec.pani)
+				LOGP(DRLCMACUL, LOGL_ERROR, "PANI shall not be true since bts"
+						" not configured for fanr\n");
+		}
+		LOGP(DRLCMACUL, LOGL_INFO,
+				"Got %s RLC block: "
+				"R=%d, SI=%d, TFI=%d, CPS=%d, RSB=%d\n",
+				cs.name(),
+				rlc_dec.r, rlc_dec.si, rlc_dec.tfi, rlc_dec.cps, rlc_dec.rsb
+		);
+
+		if (tbf->is_fanr_enabled())
+			LOGP(DRLCMACUL, LOGL_INFO,"Pani value=%d \n",rlc_dec.pani);
+	}else{
+		rc = Decoding::rlc_parse_ul_data_header(&rlc_dec, data, cs);
+		if (rc == -ENOTSUP ) {
+			LOGP(DRLCMACUL, LOGL_ERROR,
+				"Got %s RLC block but header parsing has failed\n",
+				cs.name());
+			bts()->decode_error();
+			return rc;
+		}
+		/* find TBF inst from given TFI */
+		tbf = ul_tbf_by_tfi(rlc_dec.tfi);
+		if (!tbf) {
+			LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA unknown TFI=%d\n",
+					rlc_dec.tfi);
+			return 0;
+		}
+		LOGP(DRLCMACUL, LOGL_INFO,
+			"Got %s RLC block: "
+			"R=%d, SI=%d, TFI=%d, CPS=%d, RSB=%d\n",
+			cs.name(),
+			rlc_dec.r, rlc_dec.si, rlc_dec.tfi, rlc_dec.cps, rlc_dec.rsb
+		);
+	}
 
-        return tbf->rcv_data_block_acknowledged(&rlc_dec, data, len, meas);
+	return tbf->rcv_data_block_acknowledged(&rlc_dec, data, meas);
 }
 
 /* received RLC/MAC block from L1 */
@@ -1383,8 +1427,10 @@ int gprs_rlcmac_pdch::rcv_block(uint8_t *data, uint8_t len, uint32_t fn,
         }
                 
         LOGP(DRLCMACUL, LOGL_DEBUG, "Got RLC block, coding scheme: %s, "
-                "length: %d (%d))\n", cs.name(), len, cs.maxBytesUL());
+                "length: %d \n", cs.name(), len);
                         
+        LOGP(DRLCMACUL, LOGL_DEBUG, "UL data: %s\n", osmo_hexdump(data, len));
+
         if (cs.isGprs())
                 return rcv_block_gprs(data, fn, meas, cs);
                 
diff --git a/src/bts.h b/src/bts.h
index 7e3ea80..33a5f7c 100644
--- a/src/bts.h
+++ b/src/bts.h
@@ -303,7 +303,7 @@ public:
 	GprsMsStorage &ms_store();
 	GprsMs *ms_by_tlli(uint32_t tlli, uint32_t old_tlli = 0);
 	GprsMs *ms_by_imsi(const char *imsi);
-	GprsMs *ms_alloc(uint8_t ms_class, uint8_t egprs_ms_class = 0);
+	GprsMs *ms_alloc(uint8_t ms_class, uint8_t egprs_ms_class = 0, bool is_fanr_capable = false);
 
 	/*
 	 * Statistics
diff --git a/src/decoding.cpp b/src/decoding.cpp
index 2a57bed..649f68d 100644
--- a/src/decoding.cpp
+++ b/src/decoding.cpp
@@ -20,7 +20,7 @@
 #include <decoding.h>
 #include <rlc.h>
 #include <gprs_debug.h>
-
+#include "bts.h"
 #include <arpa/inet.h>
 
 #include <errno.h>
@@ -347,6 +347,12 @@ uint8_t Decoding::get_egprs_ms_class_by_capability(MS_Radio_Access_capability_t
 	return 0;
 }
 
+bool Decoding::is_ms_fanr_capable(MS_Radio_Access_capability_t *cap)
+{
+	/*TODO*/
+	return false;
+}
+
 void Decoding::extract_egprs_urbb(uint16_t urbb_length, const uint8_t *urbb, char *show_rbb)
 {
         for (int i = 0; i < urbb_length; i++) {
@@ -376,18 +382,311 @@ void Decoding::extract_rbb(const uint8_t *rbb, char *show_rbb)
 	show_rbb[64] = '\0';
 }
 
-int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_ul_header_generic *rlc,
-	const uint8_t *data, GprsCodingScheme cs)
+int Decoding::decode_ul_data_fanr_type1(struct gprs_rlc_ul_header_generic *rlc,
+		const uint8_t *data, GprsCodingScheme* cs)
 {
-	const struct rlc_ul_header *gprs;
 	unsigned int data_len = 0;
+	data_len = cs->maxDataBlockBytes();
+
+	const struct gprs_rlc_ul_header_egprs_fanr_type1 *egprs1;
+	egprs1 = static_cast<struct gprs_rlc_ul_header_egprs_fanr_type1*>
+		((void *)data);
+	rlc->r      = egprs1->r;
+	rlc->si     = egprs1->si;
+	rlc->tfi    = (egprs1->tfi_a << 0)  | (egprs1->tfi_b << 2);
+	rlc->cps    = egprs1->cps;
+	rlc->rsb    = egprs1->rsb;
+	rlc->cv     = egprs1->cv;
+	rlc->pani     = egprs1->pani;
+
+	rlc->num_data_blocks = 2;
+	rlc->block_info[0].cv  = egprs1->cv;
+	rlc->block_info[0].pi  = egprs1->pi;
+	rlc->block_info[0].bsn =
+		(egprs1->bsn1_a << 0) | (egprs1->bsn1_b << 5);
+
+	rlc->block_info[0].spb = 0;
+
+	rlc->block_info[1].cv  = egprs1->cv;
+	rlc->block_info[1].pi  = egprs1->pi;
+
+	rlc->block_info[1].bsn = rlc->block_info[0].bsn + ((egprs1->bsn2_a << 0) | (egprs1->bsn2_b << 2));
+	rlc->block_info[1].bsn = (rlc->block_info[1].bsn + 2048) % 2047;
+
+	rlc->block_info[0].e   = (data[6] & 0x01);
+	rlc->block_info[0].ti  = (data[6] &  0x02) >> 1;
+	rlc->block_info[1].e   = (data[6 + data_len + 1] & 0x01);
+	rlc->block_info[1].ti  = (data[6 + data_len + 1] &  0x02) >> 1;
+	rlc->block_info[1].spb = 0;
+
+	rlc->block_info[0].data_len = data_len;
+	rlc->block_info[1].data_len = data_len;
+	rlc->data_offs_bytes[0] = 7;
+	rlc->data_offs_bytes[1] = 7 + data_len + 1;
+	return 0;
+}
+
+int Decoding::decode_ul_data_type1(struct gprs_rlc_ul_header_generic *rlc,
+		const uint8_t *data, GprsCodingScheme* cs)
+{
+	unsigned int data_len = 0;
+	data_len = cs->maxDataBlockBytes();
+
+	const struct gprs_rlc_ul_header_egprs_1 *egprs1;
+	egprs1 = static_cast<struct gprs_rlc_ul_header_egprs_1 *>
+		((void *)data);
+	rlc->r      = egprs1->r;
+	rlc->si     = egprs1->si;
+	rlc->tfi    = (egprs1->tfi_a << 0)  | (egprs1->tfi_b << 2);
+	rlc->cps    = egprs1->cps;
+	rlc->rsb    = egprs1->rsb;
+	rlc->cv     = egprs1->cv;
+	rlc->pani     = 0;
+
+	rlc->num_data_blocks = 2;
+	rlc->block_info[0].cv  = egprs1->cv;
+	rlc->block_info[0].pi  = egprs1->pi;
+	rlc->block_info[0].bsn =
+		(egprs1->bsn1_a << 0) | (egprs1->bsn1_b << 5);
+	/* data base initialisation not from received block */
+	rlc->block_info[0].spb = 0;
+
+	rlc->block_info[1].cv  = egprs1->cv;
+	rlc->block_info[1].pi  = egprs1->pi;
+
+	rlc->block_info[1].bsn = rlc->block_info[0].bsn + ((egprs1->bsn2_a << 0) | (egprs1->bsn2_b << 2));
+	rlc->block_info[1].bsn = (rlc->block_info[1].bsn + 2048) % 2047;
+
+	rlc->block_info[0].e   = (data[6] & 0x01);
+	rlc->block_info[0].ti  = (data[6] &  0x02) >> 1;
+	rlc->block_info[1].e   = (data[6 + data_len + 1] & 0x01);
+	rlc->block_info[1].ti  = (data[6 + data_len + 1] &  0x02) >> 1;
+	rlc->block_info[1].spb = 0;
+
+	rlc->block_info[0].data_len = data_len;
+	rlc->block_info[1].data_len = data_len;
+	rlc->data_offs_bytes[0] = 7;
+	rlc->data_offs_bytes[1] = 7 + data_len + 1;
+	return 0;
+}
+
+int Decoding::decode_ul_data_fanr_type2(struct gprs_rlc_ul_header_generic *rlc,
+		const uint8_t *data, GprsCodingScheme* cs)
+{
+	uint8_t   pad_bytes = 6;
+	unsigned int data_len = 0;
+	data_len = cs->maxDataBlockBytes();
+	const struct gprs_rlc_ul_header_egprs_fanr_type2 *egprs2;
+	egprs2 = static_cast<struct gprs_rlc_ul_header_egprs_fanr_type2*>
+		((void *)data);
+	rlc->r      = egprs2->r;
+	rlc->si     = egprs2->si;
+	rlc->tfi    = (egprs2->tfi_a << 0)  | (egprs2->tfi_b << 2);
+	rlc->cps    = (egprs2->cps_a << 0)  | (egprs2->cps_b << 2);
+	rlc->rsb    = egprs2->rsb;
+	rlc->cv     = egprs2->cv;
+	rlc->pani     = egprs2->pani;
+
+	rlc->num_data_blocks = 1;
+	rlc->block_info[0].cv  = egprs2->cv;
+	rlc->block_info[0].pi  = egprs2->pi;
+	rlc->block_info[0].bsn =
+		(egprs2->bsn1_a << 0) | (egprs2->bsn1_b << 5);
+
+	/* data base initialisation not from received block */
+	rlc->block_info[0].spb = 0;
+
+	rlc->block_info[0].e   = (data[5] & 0x01);
+	rlc->block_info[0].ti  = (data[5] &  0x02) >> 1;
+
+	rlc->block_info[0].data_len = data_len;
+	rlc->data_offs_bytes[0] = 6;
+
+	if(*cs == GprsCodingScheme::MCS6){
+		if(rlc->cps == 2 || rlc->cps == 3 ){
+			rlc->block_info[0].data_len -= pad_bytes;
+			rlc->data_offs_bytes[0] += pad_bytes;
+			rlc->block_info[0].e   = (data[5 + pad_bytes] & 0x01);
+			rlc->block_info[0].ti  = (data[5 + pad_bytes] &  0x02) >> 1;
+		}
+	}
+	return 0;
+}
+
+int Decoding::decode_ul_data_type2(struct gprs_rlc_ul_header_generic *rlc,
+		const uint8_t *data, GprsCodingScheme* cs)
+{
+	uint8_t   pad_bytes = 6;
+	unsigned int data_len = 0;
+	data_len = cs->maxDataBlockBytes();
+
+	const struct gprs_rlc_ul_header_egprs_2 *egprs2;
+	egprs2 = static_cast<struct gprs_rlc_ul_header_egprs_2 *>
+		((void *)data);
+	rlc->r      = egprs2->r;
+	rlc->si     = egprs2->si;
+	rlc->tfi    = (egprs2->tfi_a << 0)  | (egprs2->tfi_b << 2);
+	rlc->cps    = (egprs2->cps_a << 0)  | (egprs2->cps_b << 2);
+	rlc->rsb    = egprs2->rsb;
+	rlc->cv     = egprs2->cv;
+	rlc->pani     = 0;
+
+	rlc->num_data_blocks = 1;
+	rlc->block_info[0].cv  = egprs2->cv;
+	rlc->block_info[0].pi  = egprs2->pi;
+	rlc->block_info[0].bsn =
+		(egprs2->bsn1_a << 0) | (egprs2->bsn1_b << 5);
+
+	/* data base initialisation not from received block */
+	rlc->block_info[0].spb = 0;
+
+	rlc->block_info[0].e   = (data[5] & 0x01);
+	rlc->block_info[0].ti  = (data[5] &  0x02) >> 1;
+
+	rlc->block_info[0].data_len = data_len;
+	rlc->data_offs_bytes[0] = 6;
+
+	if(*cs == GprsCodingScheme::MCS6){
+		if(rlc->cps == 2 || rlc->cps == 3 ){
+			rlc->block_info[0].data_len -= pad_bytes;
+			rlc->data_offs_bytes[0] += pad_bytes;
+			rlc->block_info[0].e   = (data[5 + pad_bytes] & 0x01);
+			rlc->block_info[0].ti  = (data[5 + pad_bytes] &  0x02) >> 1;
+		}
+	}
+	return 0;
+}
+
+int Decoding::decode_ul_data_fanr_type3(struct gprs_rlc_ul_header_generic *rlc,
+		const uint8_t *data, GprsCodingScheme* cs)
+{
+	uint8_t   pad_bytes = 6;
+	unsigned int data_len = 0;
+	data_len = cs->maxDataBlockBytes();
+
+	const struct gprs_rlc_ul_header_egprs_fanr_type3 *egprs3;
+	egprs3 = static_cast<struct gprs_rlc_ul_header_egprs_fanr_type3*>
+		((void *)data);
+	rlc->r      = egprs3->r;
+	rlc->si     = egprs3->si;
+	rlc->tfi    = (egprs3->tfi_a << 0)  | (egprs3->tfi_b << 2);
+	rlc->cps    = (egprs3->cps_a << 0)  | (egprs3->cps_b << 2);
+	rlc->rsb    = egprs3->rsb;
+	rlc->cv     = egprs3->cv;
+	rlc->pani     = egprs3->pani;
+
+	rlc->num_data_blocks = 1;
+	rlc->block_info[0].cv  = egprs3->cv;
+	rlc->block_info[0].pi  = egprs3->pi;
+	rlc->block_info[0].spb = egprs3->spb;
+	rlc->block_info[0].bsn =
+		(egprs3->bsn1_a << 0) | (egprs3->bsn1_b << 5);
+
+	rlc->block_info[0].e   = (data[4] & 0x01);
+	rlc->block_info[0].ti  = (data[4] &  0x02) >> 1;
+
+	rlc->block_info[0].data_len = data_len;
+	rlc->data_offs_bytes[0] = 5;
+
+	if(rlc->block_info[0].spb == 2){
+		if(*cs == GprsCodingScheme::MCS3){
+			if(rlc->cps == 6 || rlc->cps == 7 || rlc->cps == 8){
+				rlc->block_info[0].data_len -= pad_bytes;
+				rlc->data_offs_bytes[0] += pad_bytes;
+				rlc->block_info[0].e   = (data[4 + pad_bytes] & 0x01);
+				rlc->block_info[0].ti  = (data[4 + pad_bytes] &  0x02) >> 1;
+			}
+		}
+	}
+	return 0;
+}
+
+int Decoding::decode_ul_data_type3(struct gprs_rlc_ul_header_generic *rlc,
+		const uint8_t *data, GprsCodingScheme* cs)
+{
 	uint8_t   pad_bytes = 6;
+	unsigned int data_len = 0;
+	data_len = cs->maxDataBlockBytes();
+
+	const struct gprs_rlc_ul_header_egprs_3 *egprs3;
+	egprs3 = static_cast<struct gprs_rlc_ul_header_egprs_3 *>
+		((void *)data);
+	rlc->r      = egprs3->r;
+	rlc->si     = egprs3->si;
+	rlc->tfi    = (egprs3->tfi_a << 0)  | (egprs3->tfi_b << 2);
+	rlc->cps    = (egprs3->cps_a << 0)  | (egprs3->cps_b << 2);
+	rlc->rsb    = egprs3->rsb;
+	rlc->cv     = egprs3->cv;
+	rlc->pani     = 0;
+
+	rlc->num_data_blocks = 1;
+	rlc->block_info[0].cv  = egprs3->cv;
+	rlc->block_info[0].pi  = egprs3->pi;
+	rlc->block_info[0].spb = egprs3->spb;
+	rlc->block_info[0].bsn =
+		(egprs3->bsn1_a << 0) | (egprs3->bsn1_b << 5);
+
+	rlc->block_info[0].e   = (data[4] & 0x01);
+	rlc->block_info[0].ti  = (data[4] &  0x02) >> 1;
+
+	rlc->block_info[0].data_len = data_len;
+	rlc->data_offs_bytes[0] = 5;
+
+	if(rlc->block_info[0].spb == 2){
+		if(*cs == GprsCodingScheme::MCS3){
+			if(rlc->cps == 6 || rlc->cps == 7 || rlc->cps == 8){
+				rlc->block_info[0].data_len -= pad_bytes;
+				rlc->data_offs_bytes[0] += pad_bytes;
+				rlc->block_info[0].e   = (data[4 + pad_bytes] & 0x01);
+				rlc->block_info[0].ti  = (data[4 + pad_bytes] &  0x02) >> 1;
+			}
+		}
+	}
+	return 0;
+}
+
+int Decoding::rlc_parse_ul_data_header_egprs(struct gprs_rlc_ul_header_generic *rlc,
+	const uint8_t *data, GprsCodingScheme cs, struct gprs_rlcmac_ul_tbf *tbf)
+{
 	rlc->cs = cs;
+	if (tbf->is_fanr_enabled()) {
+		if (GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3 == cs.headerTypeData()) {
+			decode_ul_data_fanr_type3(rlc,data,&cs);
+		}else if (GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2 == cs.headerTypeData()) {
+			decode_ul_data_fanr_type2(rlc,data,&cs);
+		}else if (GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1 == cs.headerTypeData()) {
+			decode_ul_data_fanr_type1(rlc,data,&cs);
+		}else{
+			LOGP(DRLCMACUL, LOGL_ERROR, "Not a Valid TYPE (%d) for fanr Egprs Type\n",
+					cs.headerTypeData());
+			return -ENOTSUP;
+		}
+	}else{
+		if (GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3 == cs.headerTypeData()) {
+			decode_ul_data_type3(rlc,data,&cs);
+		}else if (GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2 == cs.headerTypeData()) {
+			decode_ul_data_type2(rlc,data,&cs);
+		}else if (GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1 == cs.headerTypeData()) {
+			decode_ul_data_type1(rlc,data,&cs);
+		}else {
+			LOGP(DRLCMACUL, LOGL_ERROR, "Not a Valid TYPE (%d) for Normal Egprs Type\n",
+					cs.headerTypeData());
+			return -ENOTSUP;
+		}
+	}
+	return 0;
+}
 
+
+int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_ul_header_generic *rlc,
+	const uint8_t *data, GprsCodingScheme cs)
+{
+	const struct rlc_ul_header *gprs;
+	rlc->cs = cs;
+	unsigned int data_len = 0;
 	data_len = cs.maxDataBlockBytes();
 
-	switch(cs.headerTypeData()) {
-	case GprsCodingScheme::HEADER_GPRS_DATA:
+	if(GprsCodingScheme::HEADER_GPRS_DATA == cs.headerTypeData()){
 		gprs = static_cast<struct rlc_ul_header *>
 			((void *)data);
 		rlc->r      = gprs->r;
@@ -395,7 +694,7 @@ int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_ul_header_generic *rlc,
 		rlc->tfi    = gprs->tfi;
 		rlc->cps    = 0;
 		rlc->rsb    = 0;
-		rlc->pani= 0;
+		rlc->pani   = 0;
 
 		rlc->num_data_blocks = 1;
 		rlc->block_info[0].cv  = gprs->cv;
@@ -404,133 +703,13 @@ int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_ul_header_generic *rlc,
 		rlc->block_info[0].e   = gprs->e;
 		rlc->block_info[0].ti  = gprs->ti;
 		rlc->block_info[0].spb = 0;
-                rlc->data_offs_bytes[0] = 3;
+		rlc->data_offs_bytes[0] = 3;
 
 		rlc->block_info[0].data_len = data_len;
-
-		break;
-	case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3:
-		const struct gprs_rlc_ul_header_egprs_3 *egprs3;
-		egprs3 = static_cast<struct gprs_rlc_ul_header_egprs_3 *>
-                        ((void *)data);
-                rlc->r      = egprs3->r;
-                rlc->si     = egprs3->si;
-                rlc->tfi    = (egprs3->tfi_a << 0)  | (egprs3->tfi_b << 2);
-                rlc->cps    = (egprs3->cps_a << 0)  | (egprs3->cps_b << 2);
-                rlc->rsb    = egprs3->rsb;
-                rlc->cv     = egprs3->cv;
-                /* pani 0 for fanr inactive */
-		rlc->pani     = 0;
-
-                rlc->num_data_blocks = 1;
-                rlc->block_info[0].cv  = egprs3->cv;
-                rlc->block_info[0].pi  = egprs3->pi;
-                rlc->block_info[0].spb = egprs3->spb;
-                rlc->block_info[0].bsn =
-                        (egprs3->bsn1_a << 0) | (egprs3->bsn1_b << 5);
-
-                rlc->block_info[0].e   = (data[4] & 0x01);
-                rlc->block_info[0].ti  = (data[4] &  0x02) >> 1;
-
-                rlc->block_info[0].data_len = data_len;
-                rlc->data_offs_bytes[0] = 5;
-
-		if(rlc->block_info[0].spb == 2){
-			if(cs == GprsCodingScheme::MCS3){ 
-				if(rlc->cps == 6 || rlc->cps == 7 || rlc->cps == 8){
-        	        		rlc->block_info[0].data_len -= pad_bytes;
-               				rlc->data_offs_bytes[0] += pad_bytes;
-                			rlc->block_info[0].e   = (data[4 + pad_bytes] & 0x01);
-			                rlc->block_info[0].ti  = (data[4 + pad_bytes] &  0x02) >> 1;
-				}
-			}
-		}
-		break;
-
-	case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2:
-		const struct gprs_rlc_ul_header_egprs_2 *egprs2;
-		egprs2 = static_cast<struct gprs_rlc_ul_header_egprs_2 *>
-                        ((void *)data);
-                rlc->r      = egprs2->r;
-                rlc->si     = egprs2->si;
-                rlc->tfi    = (egprs2->tfi_a << 0)  | (egprs2->tfi_b << 2);
-                rlc->cps    = (egprs2->cps_a << 0)  | (egprs2->cps_b << 2);
-                rlc->rsb    = egprs2->rsb;
-                rlc->cv     = egprs2->cv;
-                /* pani 0 for fanr inactive */
-		rlc->pani     = 0;
-
-                rlc->num_data_blocks = 1;
-                rlc->block_info[0].cv  = egprs2->cv;
-                rlc->block_info[0].pi  = egprs2->pi;
-                rlc->block_info[0].bsn =
-                        (egprs2->bsn1_a << 0) | (egprs2->bsn1_b << 5);
-
-		/* data base initialisation not from received block */
-		rlc->block_info[0].spb = 0;
-
-                rlc->block_info[0].e   = (data[5] & 0x01);
-                rlc->block_info[0].ti  = (data[5] &  0x02) >> 1;
-
-                rlc->block_info[0].data_len = data_len;
-                rlc->data_offs_bytes[0] = 6;
-
-		if(cs == GprsCodingScheme::MCS6){ 
-			if(rlc->cps == 2 || rlc->cps == 3 ){
-        	        	rlc->block_info[0].data_len -= pad_bytes;
-               			rlc->data_offs_bytes[0] += pad_bytes;
-                		rlc->block_info[0].e   = (data[5 + pad_bytes] & 0x01);
-			        rlc->block_info[0].ti  = (data[5 + pad_bytes] &  0x02) >> 1;
-			}
-		}
-		break;
-
-	case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1:
-		const struct gprs_rlc_ul_header_egprs_1 *egprs1;
-		egprs1 = static_cast<struct gprs_rlc_ul_header_egprs_1 *>
-                        ((void *)data);
-                rlc->r      = egprs1->r;
-                rlc->si     = egprs1->si;
-                rlc->tfi    = (egprs1->tfi_a << 0)  | (egprs1->tfi_b << 2);
-                rlc->cps    = egprs1->cps;
-                rlc->rsb    = egprs1->rsb;
-                rlc->cv     = egprs1->cv;
-                /* pani 0 for fanr inactive */
-		rlc->pani     = 0;
-
-                rlc->num_data_blocks = 2;
-                rlc->block_info[0].cv  = egprs1->cv;
-                rlc->block_info[0].pi  = egprs1->pi;
-                rlc->block_info[0].bsn =
-                        (egprs1->bsn1_a << 0) | (egprs1->bsn1_b << 5);
-		/* data base initialisation not from received block */
-		rlc->block_info[0].spb = 0;
-
-		rlc->block_info[1].cv  = egprs1->cv;
-                rlc->block_info[1].pi  = egprs1->pi;
-		
-                rlc->block_info[1].bsn = rlc->block_info[0].bsn + ((egprs1->bsn2_a << 0) | (egprs1->bsn2_b << 2));
-                rlc->block_info[1].bsn = (rlc->block_info[1].bsn + 2048) % 2047;
-
-                rlc->block_info[0].e   = (data[6] & 0x01);
-                rlc->block_info[0].ti  = (data[6] &  0x02) >> 1;
-                rlc->block_info[1].e   = (data[6 + data_len + 1] & 0x01);
-                rlc->block_info[1].ti  = (data[6 + data_len + 1] &  0x02) >> 1;
-		rlc->block_info[1].spb = 0;
-
-                rlc->block_info[0].data_len = data_len;
-                rlc->block_info[1].data_len = data_len;
-                rlc->data_offs_bytes[0] = 7;
-                rlc->data_offs_bytes[1] = 7 + data_len + 1;
-
-		break;
-	default:
-		LOGP(DRLCMACDL, LOGL_ERROR,
-			"Decoding of uplink %s data blocks not yet supported.\n",
-			cs.name());
+	}else{
+		LOGP(DRLCMACUL, LOGL_ERROR, "Not a Valid TYPE (%d)\n",cs.headerTypeData());
 		return -ENOTSUP;
-	};
-
+	}
 	return 0;
 }
 
diff --git a/src/decoding.h b/src/decoding.h
index ba0257f..25a9cf9 100644
--- a/src/decoding.h
+++ b/src/decoding.h
@@ -21,6 +21,7 @@
 
 #include <gsm_rlcmac.h>
 #include "gprs_coding_scheme.h"
+#include "tbf.h"
 #include "rlc.h"
 #include <stdint.h>
 
@@ -43,9 +44,32 @@ public:
 	static void extract_rbb(const uint8_t *rbb, char *extracted_rbb);
 	static void extract_egprs_urbb(uint16_t urbb_length, const uint8_t *urbb, char *show_rbb);
 	static uint8_t get_egprs_ms_class_by_capability(MS_Radio_Access_capability_t *cap);
+	static bool is_ms_fanr_capable(MS_Radio_Access_capability_t *cap);
 
 	static int rlc_parse_ul_data_header(struct gprs_rlc_ul_header_generic *rlc,
 		const uint8_t *data, GprsCodingScheme cs);
+
+	static int rlc_parse_ul_data_header_egprs(struct gprs_rlc_ul_header_generic *rlc,
+		const uint8_t *data, GprsCodingScheme cs, struct gprs_rlcmac_ul_tbf *tbf);
+
+	static int decode_ul_data_type3(struct gprs_rlc_ul_header_generic *rlc,
+			const uint8_t *data, GprsCodingScheme* cs);
+
+	static int decode_ul_data_fanr_type3(struct gprs_rlc_ul_header_generic *rlc,
+				const uint8_t *data, GprsCodingScheme* cs);
+
+	static int decode_ul_data_type2(struct gprs_rlc_ul_header_generic *rlc,
+				const uint8_t *data, GprsCodingScheme* cs);
+
+	static int decode_ul_data_fanr_type2(struct gprs_rlc_ul_header_generic *rlc,
+				const uint8_t *data, GprsCodingScheme* cs);
+
+	static int decode_ul_data_type1(struct gprs_rlc_ul_header_generic *rlc,
+				const uint8_t *data, GprsCodingScheme* cs);
+
+	static int decode_ul_data_fanr_type1(struct gprs_rlc_ul_header_generic *rlc,
+				const uint8_t *data, GprsCodingScheme* cs);
+
 	static unsigned int rlc_copy_to_aligned_buffer(
 		const struct gprs_rlc_ul_header_generic *rlc,
 		unsigned int data_block_idx,
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp
index 22ab8a8..cf6f41f 100644
--- a/src/gprs_bssgp_pcu.cpp
+++ b/src/gprs_bssgp_pcu.cpp
@@ -154,6 +154,13 @@ static int parse_egprs_ra_cap_ms_class(struct tlv_parsed *tp)
         bitvec_free(block);
         return egprs_ms_class;
 }
+
+static bool parse_egprs_ra_cap_ms_fanr_capable(struct tlv_parsed *tp)
+{
+	/*TODO*/
+        return false;
+}
+
 static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
 {
 	struct bssgp_ud_hdr *budh;
@@ -192,6 +199,9 @@ static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
 	/* parse egprs  ms radio access capability */
 	uint8_t egprs_ms_class = parse_egprs_ra_cap_ms_class(tp);
 
+	/* parse egprs  ms radio access capability to get fanr capability */
+	bool    is_fanr_capable = parse_egprs_ra_cap_ms_fanr_capable(tp);
+
 	/* get lifetime */
 	uint16_t delay_csec = 0xffff;
 	if (TLVP_PRESENT(tp, BSSGP_IE_PDU_LIFETIME))
@@ -221,7 +231,7 @@ static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
 
 	LOGP(DBSSGP, LOGL_INFO, "LLC [SGSN -> PCU] = TLLI: 0x%08x IMSI: %s len: %d\n", tlli, imsi, len);
 	return gprs_rlcmac_dl_tbf::handle(the_pcu.bts, tlli, tlli_old, imsi,
-			ms_class, egprs_ms_class, delay_csec, data, len);
+			ms_class, egprs_ms_class, delay_csec, data, len, is_fanr_capable);
 }
 
 int gprs_bssgp_pcu_rx_paging_ps(struct msgb *msg, struct tlv_parsed *tp)
diff --git a/src/tbf.cpp b/src/tbf.cpp
index 93dd8c2..05f5c82 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -285,14 +285,14 @@ void gprs_rlcmac_tbf::update_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction di
 
 gprs_rlcmac_ul_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts,
 	int8_t use_trx, uint8_t ms_class, uint8_t egprs_ms_class,
-	uint32_t tlli, uint8_t ta, GprsMs *ms)
+	uint32_t tlli, uint8_t ta, GprsMs *ms, bool is_ms_fanr_capable)
 {
 	struct gprs_rlcmac_ul_tbf *tbf;
 
 #warning "Copy and paste with tbf_new_dl_assignment"
 	/* create new TBF, use same TRX as DL TBF */
 	/* use multislot class of downlink TBF */
-	tbf = tbf_alloc_ul_tbf(bts, ms, use_trx, ms_class, egprs_ms_class, 0);
+	tbf = tbf_alloc_ul_tbf(bts, ms, use_trx, ms_class, egprs_ms_class, 0, is_ms_fanr_capable);
 	if (!tbf) {
 		LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
 		/* FIXME: send reject */
@@ -611,7 +611,8 @@ static int ul_tbf_dtor(struct gprs_rlcmac_ul_tbf *tbf)
 
 struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
 	GprsMs *ms, int8_t use_trx,
-	uint8_t ms_class, uint8_t egprs_ms_class, uint8_t single_slot)
+	uint8_t ms_class, uint8_t egprs_ms_class, uint8_t single_slot,
+	bool is_ms_fanr_capable)
 {
 	struct gprs_rlcmac_ul_tbf *tbf;
 	int rc;
@@ -629,7 +630,7 @@ struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
 	new (tbf) gprs_rlcmac_ul_tbf(bts->bts);
 
 	if (!ms)
-		ms = bts->bts->ms_alloc(ms_class, egprs_ms_class);
+		ms = bts->bts->ms_alloc(ms_class, egprs_ms_class, is_ms_fanr_capable);
 
 	if (egprs_ms_class > 0 && bts->egprs_enabled) {
 		/* TODO: only for 8PSK, otherwise the GPRS MS class has to be used */
@@ -637,6 +638,9 @@ struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
 		tbf->m_window.set_sns(RLC_EGPRS_SNS);
 		tbf->m_window.set_ws(RLC_EGPRS_MIN_WS);
 	}
+	if((true == is_ms_fanr_capable) && bts->egprs_enabled ){
+		tbf->enable_fanr();
+	}
 
 	rc = setup_tbf(tbf, ms, use_trx, ms_class, egprs_ms_class, single_slot);
 	/* if no resource */
@@ -679,7 +683,7 @@ static int dl_tbf_dtor(struct gprs_rlcmac_dl_tbf *tbf)
 
 struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
         GprsMs *ms, int8_t use_trx,
-        uint8_t ms_class, uint8_t egprs_ms_class, uint8_t single_slot)
+        uint8_t ms_class, uint8_t egprs_ms_class, uint8_t single_slot, bool is_fanr_capable)
 {
 	struct gprs_rlcmac_dl_tbf *tbf;
 	int rc = -1;
@@ -703,11 +707,15 @@ struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
                 tbf->m_window.set_ws(RLC_EGPRS_MIN_WS);
         }
 
+	if((true == is_fanr_capable) && (bts->fanr_enabled)){
+		tbf->enable_fanr();
+	}
+
 	if (!ms)
         {
-                ms = bts->bts->ms_alloc(ms_class, egprs_ms_class);
+                ms = bts->bts->ms_alloc(ms_class, egprs_ms_class, is_fanr_capable);
         }
-		rc = setup_tbf(tbf, ms, use_trx, ms_class, egprs_ms_class, single_slot);
+	rc = setup_tbf(tbf, ms, use_trx, ms_class, egprs_ms_class, single_slot);
 	/* if no resource */
 	if (rc < 0) {
 		talloc_free(tbf);
@@ -1038,7 +1046,7 @@ int gprs_rlcmac_tbf::establish_dl_tbf_on_pacch()
 	bts->tbf_reused();
 	new_tbf = tbf_alloc_dl_tbf(bts->bts_data(), ms(),
 		this->trx->trx_no, ms_class(),
-		ms() ?  ms()->egprs_ms_class() : 0, 0);
+		ms() ?  ms()->egprs_ms_class() : 0, 0, 0);
 	if (!new_tbf) {
 		LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
 		return -1;
diff --git a/src/tbf.h b/src/tbf.h
index 6e482c7..a6878d7 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -271,14 +271,16 @@ private:
 
 struct gprs_rlcmac_ul_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts,
 	int8_t use_trx, uint8_t ms_class, uint8_t egprs_ms_class,
-	uint32_t tlli, uint8_t ta, GprsMs *ms);
+	uint32_t tlli, uint8_t ta, GprsMs *ms, bool is_ms_fanr_capable);
 
 struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
 	GprsMs *ms, int8_t use_trx,
-	uint8_t ms_class, uint8_t egprs_ms_class, uint8_t single_slot);
+	uint8_t ms_class, uint8_t egprs_ms_class, uint8_t single_slot,
+	bool is_ms_fanr_capable);
+
 struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
 	GprsMs *ms, int8_t use_trx,
-	uint8_t ms_class, uint8_t egprs_ms_class, uint8_t single_slot);
+	uint8_t ms_class, uint8_t egprs_ms_class, uint8_t single_slot, bool is_fanr_capable);
 
 void tbf_free(struct gprs_rlcmac_tbf *tbf);
 
@@ -365,7 +367,7 @@ struct gprs_rlcmac_dl_tbf : public gprs_rlcmac_tbf {
                 const uint32_t tlli, const uint32_t tlli_old, const char *imsi,
                 const uint8_t ms_class, const uint8_t egprs_ms_class,
                 const uint16_t delay_csec,
-                const uint8_t *data, const uint16_t len);
+                const uint8_t *data, const uint16_t len, bool is_fanr_capable);
 	int append_data(const uint8_t ms_class,
 			const uint16_t pdu_delay_csec,
 			const uint8_t *data, const uint16_t len);
@@ -479,7 +481,7 @@ struct gprs_rlcmac_ul_tbf : public gprs_rlcmac_tbf {
 	/* blocks were acked */
 	int rcv_data_block_acknowledged(
 		const struct gprs_rlc_ul_header_generic *rlc,
-		uint8_t *data, uint8_t len, struct pcu_l1_meas *meas);
+		uint8_t *data,struct pcu_l1_meas *meas);
 	/* In case of re segmentation process the spb values and decides
 		 weather original block is rebuilt 
 	*/
diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp
index a2f6324..a909d9d 100644
--- a/src/tbf_dl.cpp
+++ b/src/tbf_dl.cpp
@@ -137,7 +137,8 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
                                 const uint32_t tlli, const uint32_t tlli_old,
                                 const uint8_t ms_class,
                                 const uint8_t egprs_ms_class,
-                                struct gprs_rlcmac_dl_tbf **tbf)
+                                struct gprs_rlcmac_dl_tbf **tbf,
+				bool   is_fanr_capable)
 {
 	uint8_t ss;
 	int8_t use_trx;
@@ -171,7 +172,7 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
 #warning "Copy and paste with alloc_ul_tbf"
 	/* set number of downlink slots according to multislot class */
 
-        dl_tbf = tbf_alloc_dl_tbf(bts, ms, use_trx, ms_class, egprs_ms_class, ss);
+        dl_tbf = tbf_alloc_dl_tbf(bts, ms, use_trx, ms_class, egprs_ms_class, ss, is_fanr_capable);
 
 	if (!dl_tbf) {
 		LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
@@ -200,7 +201,8 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
 int gprs_rlcmac_dl_tbf::handle(struct gprs_rlcmac_bts *bts,
 		const uint32_t tlli, const uint32_t tlli_old, const char *imsi,
 		const uint8_t ms_class, const uint8_t egprs_ms_class,
-		const uint16_t delay_csec, const uint8_t *data, const uint16_t len)
+		const uint16_t delay_csec, const uint8_t *data, const uint16_t len,
+		bool is_fanr_capable)
 {
 	struct gprs_rlcmac_dl_tbf *dl_tbf = NULL;
 	int rc;
@@ -246,7 +248,7 @@ int gprs_rlcmac_dl_tbf::handle(struct gprs_rlcmac_bts *bts,
 
 	if (!dl_tbf) {
                 rc = tbf_new_dl_assignment(bts, imsi, tlli, tlli_old,
-                        ms_class, egprs_ms_class, &dl_tbf);
+                        ms_class, egprs_ms_class, &dl_tbf, is_fanr_capable);
 		if (rc < 0)
 			return rc;
 	}
diff --git a/src/tbf_ul.cpp b/src/tbf_ul.cpp
index 9de1b6b..e89ac14 100644
--- a/src/tbf_ul.cpp
+++ b/src/tbf_ul.cpp
@@ -209,7 +209,7 @@ egprs_rlc_ul_reseg_bsn_state gprs_rlcmac_ul_tbf::assemble_rlc_block_frm_segmente
 
 int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
 	const struct gprs_rlc_ul_header_generic *rlc,
-	uint8_t *data, uint8_t len, struct pcu_l1_meas *meas)
+	uint8_t *data, struct pcu_l1_meas *meas)
 {
 	int8_t rssi = meas->have_rssi ? meas->rssi : 0;
 
diff --git a/tests/alloc/AllocTest.cpp b/tests/alloc/AllocTest.cpp
index d338b78..e7b1e45 100644
--- a/tests/alloc/AllocTest.cpp
+++ b/tests/alloc/AllocTest.cpp
@@ -43,10 +43,10 @@ static gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_bts *bts,
 {
 	if (dir == GPRS_RLCMAC_UL_TBF)
 		return tbf_alloc_ul_tbf(bts, ms, use_trx,
-			ms_class, egprs_ms_class, single_slot);
+			ms_class, egprs_ms_class, single_slot, false);
 	else
 		return tbf_alloc_dl_tbf(bts, ms, use_trx,
-			ms_class, egprs_ms_class, single_slot);
+			ms_class, egprs_ms_class, single_slot, false);
 }
 
 static void check_tfi_usage(BTS *the_bts)
@@ -202,7 +202,7 @@ static void test_alloc_b(int ms_class)
 		trx->pdch[6].enable();
 		trx->pdch[7].enable();
 
-		ul_tbf = tbf_alloc_ul_tbf(bts, NULL, -1, ms_class, 0, 1);
+		ul_tbf = tbf_alloc_ul_tbf(bts, NULL, -1, ms_class, 0, 1, false);
 		OSMO_ASSERT(ul_tbf);
 		OSMO_ASSERT(ul_tbf->ms());
 		OSMO_ASSERT(ul_tbf->ms()->current_trx());
@@ -210,7 +210,7 @@ static void test_alloc_b(int ms_class)
 		dump_assignment(ul_tbf, "UL");
 
 		/* assume final ack has not been sent */
-		dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf->ms(), trx_no, ms_class, 0, 0);
+		dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf->ms(), trx_no, ms_class, 0, 0, false);
 		OSMO_ASSERT(dl_tbf);
 		dump_assignment(dl_tbf, "DL");
 
@@ -244,7 +244,7 @@ static void test_alloc_b(int ms_class)
 		trx->pdch[6].enable();
 		trx->pdch[7].enable();
 
-		dl_tbf = tbf_alloc_dl_tbf(bts, NULL, -1, ms_class, 0, 1);
+		dl_tbf = tbf_alloc_dl_tbf(bts, NULL, -1, ms_class, 0, 1, false);
 		dl_tbf->update_ms(0x23, GPRS_RLCMAC_DL_TBF);
 		OSMO_ASSERT(dl_tbf);
 		OSMO_ASSERT(dl_tbf->ms());
@@ -252,7 +252,7 @@ static void test_alloc_b(int ms_class)
 		trx_no = dl_tbf->ms()->current_trx()->trx_no;
 		dump_assignment(dl_tbf, "DL");
 
-		ul_tbf = tbf_alloc_ul_tbf(bts, dl_tbf->ms(), trx_no, ms_class, 0, 0);
+		ul_tbf = tbf_alloc_ul_tbf(bts, dl_tbf->ms(), trx_no, ms_class, 0, 0, false);
 		ul_tbf->update_ms(0x23, GPRS_RLCMAC_UL_TBF);
 		ul_tbf->m_contention_resolution_done = 1;
 		OSMO_ASSERT(ul_tbf);
@@ -294,7 +294,7 @@ static void test_alloc_b(int ms_class)
 
 		tfi = the_bts.tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
 		OSMO_ASSERT(tfi >= 0);
-		ul_tbf = tbf_alloc_ul_tbf(bts, NULL, .1, ms_class, 0, 0);
+		ul_tbf = tbf_alloc_ul_tbf(bts, NULL, .1, ms_class, 0, 0, false);
 		OSMO_ASSERT(ul_tbf);
 		OSMO_ASSERT(ul_tbf->ms());
 		OSMO_ASSERT(ul_tbf->ms()->current_trx());
@@ -302,7 +302,7 @@ static void test_alloc_b(int ms_class)
 		dump_assignment(ul_tbf, "UL");
 
 		/* assume final ack has not been sent */
-		dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf->ms(), trx_no, ms_class, 0, 0);
+		dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf->ms(), trx_no, ms_class, 0, 0, false);
 		OSMO_ASSERT(dl_tbf);
 		dump_assignment(dl_tbf, "DL");
 
@@ -357,14 +357,14 @@ static void test_alloc_b(bool ts0, bool ts1, bool ts2, bool ts3, bool ts4, bool
 		ENABLE_PDCH(6, ts6, trx);
 		ENABLE_PDCH(7, ts7, trx);
 
-		ul_tbf = tbf_alloc_ul_tbf(bts, NULL, -1, ms_class, 0, 1);
+		ul_tbf = tbf_alloc_ul_tbf(bts, NULL, -1, ms_class, 0, 1, false);
 		OSMO_ASSERT(ul_tbf->ms());
 		OSMO_ASSERT(ul_tbf->ms()->current_trx());
 		trx_no = ul_tbf->ms()->current_trx()->trx_no;
 		OSMO_ASSERT(ul_tbf);
 
 		/* assume final ack has not been sent */
-		dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf->ms(), trx_no, ms_class, 0, 0);
+		dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf->ms(), trx_no, ms_class, 0, 0, false);
 		OSMO_ASSERT(dl_tbf);
 
 		/* verify that both are on the same ts */
@@ -401,14 +401,14 @@ static void test_alloc_b(bool ts0, bool ts1, bool ts2, bool ts3, bool ts4, bool
 		ENABLE_PDCH(6, ts6, trx);
 		ENABLE_PDCH(7, ts7, trx);
 
-		dl_tbf = tbf_alloc_dl_tbf(bts, NULL, -1, ms_class, 0, 1);
+		dl_tbf = tbf_alloc_dl_tbf(bts, NULL, -1, ms_class, 0, 1, false);
 		OSMO_ASSERT(dl_tbf);
 		OSMO_ASSERT(dl_tbf->ms());
 		OSMO_ASSERT(dl_tbf->ms()->current_trx());
 		trx_no = dl_tbf->ms()->current_trx()->trx_no;
 		dl_tbf->update_ms(0x23, GPRS_RLCMAC_DL_TBF);
 
-		ul_tbf = tbf_alloc_ul_tbf(bts, dl_tbf->ms(), trx_no, ms_class, 0, 0);
+		ul_tbf = tbf_alloc_ul_tbf(bts, dl_tbf->ms(), trx_no, ms_class, 0, 0, false);
 		OSMO_ASSERT(ul_tbf);
 		ul_tbf->update_ms(0x23, GPRS_RLCMAC_UL_TBF);
 		ul_tbf->m_contention_resolution_done = 1;
@@ -497,7 +497,7 @@ static GprsMs *alloc_tbfs(BTS *the_bts, GprsMs *ms, unsigned ms_class,
 	case TEST_MODE_UL_AND_DL:
 		if (ms && ms->ul_tbf())
 			tbf_free(ms->ul_tbf());
-		tbf = tbf_alloc_ul_tbf(bts, ms, trx_no, ms_class, 0, 0);
+		tbf = tbf_alloc_ul_tbf(bts, ms, trx_no, ms_class, 0, 0, false);
 		if (tbf == NULL)
 			return NULL;
 		break;
@@ -506,7 +506,7 @@ static GprsMs *alloc_tbfs(BTS *the_bts, GprsMs *ms, unsigned ms_class,
 	case TEST_MODE_DL_AND_UL:
 		if (ms && ms->dl_tbf())
 			tbf_free(ms->dl_tbf());
-		tbf = tbf_alloc_dl_tbf(bts, ms, trx_no, ms_class, 0, 0);
+		tbf = tbf_alloc_dl_tbf(bts, ms, trx_no, ms_class, 0, 0, false);
 		if (tbf == NULL)
 			return NULL;
 	}
diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp
index 2abcd8f..7177832 100644
--- a/tests/edge/EdgeTest.cpp
+++ b/tests/edge/EdgeTest.cpp
@@ -251,12 +251,12 @@ static void test_rlc_decoder()
 	 */
 	gprs_rlcmac_tbf *dl_tbf = tbf_alloc_dl_tbf(the_bts.bts_data(),
 						NULL,
-						0, 0, 4, 0);
+						0, 0, 4, 0, false);
 	OSMO_ASSERT(dl_tbf != NULL);
 
 	gprs_rlcmac_tbf *ul_tbf = tbf_alloc_ul_tbf(the_bts.bts_data(),
 						dl_tbf->ms(),
-						0, 0, 4, 0);
+						0, 0, 4, 0, false);
 	/*
 	bts.cpp:1156 Got RLC block, coding scheme: CS-4, length : 54 (53))
 bts.cpp:1200   UL data: 3c 02 02 33 0a ed 5d fe d8 00 8f 18 33 2c 16 45 03 c0 68 75 00 00 16 45 00 03 c5 62 29 40 00 45 06 4e b6 c0 a8 00 02 c0 a8 00 01 86 74 1f 91 17 ac 35 ee 33 5e 
@@ -1055,7 +1055,7 @@ void send_dl_data(BTS *the_bts, uint32_t tlli, const char *imsi,
 	ms = the_bts->ms_store().get_ms(tlli, 0, imsi);
 
 	gprs_rlcmac_dl_tbf::handle(the_bts->bts_data(), tlli, 0, imsi, 0, 0,
-		1000, data, data_size);
+		1000, data, data_size, false);
 
 	ms = the_bts->ms_by_imsi(imsi);
 	OSMO_ASSERT(ms != NULL);
@@ -1079,7 +1079,7 @@ static gprs_rlcmac_dl_tbf *create_dl_tbf(BTS *the_bts, uint8_t ms_class,
 
 	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, ms_class, 1);
+	dl_tbf = tbf_alloc_dl_tbf(bts, NULL, trx_no, ms_class, ms_class, 1, false);
 	check_tbf(dl_tbf);
 
 	/* "Establish" the DL TBF */
@@ -1093,7 +1093,7 @@ static gprs_rlcmac_dl_tbf *create_dl_tbf(BTS *the_bts, uint8_t ms_class,
 	return dl_tbf;
 }
 
-static void setup_bts(BTS *the_bts, uint8_t ts_no, uint8_t cs = 1)
+static void setup_bts(BTS *the_bts, uint8_t ts_no, uint8_t cs = 1, bool fanr_enable = false)
 {
 	gprs_rlcmac_bts *bts;
 	gprs_rlcmac_trx *trx;
@@ -1103,6 +1103,7 @@ static void setup_bts(BTS *the_bts, uint8_t ts_no, uint8_t cs = 1)
 	bts->alloc_algorithm = alloc_algorithm_a;
 	bts->initial_cs_dl = cs;
 	bts->initial_cs_ul = cs;
+	bts->fanr_enabled = fanr_enable;
 	trx = &bts->trx[0];
 
 	trx->pdch[ts_no].enable();
@@ -1260,11 +1261,11 @@ static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase(BTS *the_bts,
 	ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability.
 		MS_RA_capability_value[0].u.Content.Multislot_capability.
 		GPRS_multislot_class = 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;
@@ -1285,22 +1286,228 @@ static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase(BTS *the_bts,
 
 	check_tbf(ul_tbf);
 
-	uint8_t data_msg[27] = {0};
+	uint8_t data_msg[200] = {0};
 	/* send fake data */
-	data_msg[0] = 0x00 | 0xf << 2; 
+	data_msg[0] = 0x00 | 0xf << 2;
 	data_msg[1] = uint8_t(0 | (tfi << 1));
 	data_msg[2] = uint8_t(0);/* BSN:7, E:1 */
 	data_msg[3] =uint8_t(0); /* BSN:7, E:1 */
 	data_msg[4] = uint8_t(1); /* E: 1 */
 
 	pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no];
-	pdch->rcv_block(&data_msg[0], sizeof(data_msg), *fn, &meas);
-	
+	pdch->rcv_block(&data_msg[0], 27, *fn, &meas);
+
+	ms = the_bts->ms_by_tlli(tlli);
+	OSMO_ASSERT(ms != NULL);
+	OSMO_ASSERT(ms->ta() == qta/4);
+	OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
+
+	ul_tbf->enable_fanr();
+	/* send fake data */
+	data_msg[0] = 0x00 | 0xf << 2;
+	data_msg[1] = uint8_t(0 | (tfi << 1));
+	data_msg[2] = uint8_t(0);/* BSN:7, E:1 */
+	data_msg[3] =uint8_t(1 << 6); /* BSN:7, E:1 */
+	data_msg[4] = uint8_t(1); /* E: 1 */
+
+	pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no];
+	pdch->rcv_block(&data_msg[0], 31, *fn, &meas);
+
+	ms = the_bts->ms_by_tlli(tlli);
+	OSMO_ASSERT(ms != NULL);
+	OSMO_ASSERT(ms->ta() == qta/4);
+	OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
+
+	/* send fake data */
+	data_msg[0] = 0x00 | 0xf << 2;
+	data_msg[1] = uint8_t(0 | (tfi << 1));
+	data_msg[2] = uint8_t(0);/* BSN:7, E:1 */
+	data_msg[3] =uint8_t(0 << 6); /* BSN:7, E:1 */
+	data_msg[4] = uint8_t(1); /* E: 1 */
+
+	pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no];
+	pdch->rcv_block(&data_msg[0], 31, *fn, &meas);
+
+	ms = the_bts->ms_by_tlli(tlli);
+	OSMO_ASSERT(ms != NULL);
+	OSMO_ASSERT(ms->ta() == qta/4);
+	OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
+
+	/* send fake data */
+	data_msg[0] = 0x00 | 0xf << 2;
+	data_msg[1] = uint8_t(0 | (tfi << 1));
+	data_msg[2] = uint8_t(0);/* BSN:7, E:1 */
+	data_msg[3] =uint8_t(1 << 6); /* BSN:7, E:1 */
+	data_msg[4] = uint8_t(1); /* E: 1 */
+
+	pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no];
+	pdch->rcv_block(&data_msg[0], 37, *fn, &meas);
+
 	ms = the_bts->ms_by_tlli(tlli);
 	OSMO_ASSERT(ms != NULL);
 	OSMO_ASSERT(ms->ta() == qta/4);
 	OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
+	/* send fake data */
+	data_msg[0] = 0x00 | 0xf << 2;
+	data_msg[1] = uint8_t(0 | (tfi << 1));
+	data_msg[2] = uint8_t(0);/* BSN:7, E:1 */
+	data_msg[3] =uint8_t(0 << 6); /* BSN:7, E:1 */
+	data_msg[4] = uint8_t(1); /* E: 1 */
+
+	pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no];
+	pdch->rcv_block(&data_msg[0], 37, *fn, &meas);
+
+	ms = the_bts->ms_by_tlli(tlli);
+	OSMO_ASSERT(ms != NULL);
+	OSMO_ASSERT(ms->ta() == qta/4);
+	OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
+	/* send fake data */
+	data_msg[0] = 0x00 | 0xf << 2;
+	data_msg[1] = uint8_t(0 | (tfi << 1));
+	data_msg[2] = uint8_t(0);/* BSN:7, E:1 */
+	data_msg[3] =uint8_t(1 << 6); /* BSN:7, E:1 */
+	data_msg[4] = uint8_t(1); /* E: 1 */
+
+	pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no];
+	pdch->rcv_block(&data_msg[0], 46, *fn, &meas);
+
+	ms = the_bts->ms_by_tlli(tlli);
+	OSMO_ASSERT(ms != NULL);
+	OSMO_ASSERT(ms->ta() == qta/4);
+	OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
+	/* send fake data */
+	data_msg[0] = 0x00 | 0xf << 2;
+	data_msg[1] = uint8_t(0 | (tfi << 1));
+	data_msg[2] = uint8_t(0);/* BSN:7, E:1 */
+	data_msg[3] =uint8_t(0 << 6); /* BSN:7, E:1 */
+	data_msg[4] = uint8_t(1); /* E: 1 */
 
+	pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no];
+	pdch->rcv_block(&data_msg[0], 46, *fn, &meas);
+
+	ms = the_bts->ms_by_tlli(tlli);
+	OSMO_ASSERT(ms != NULL);
+	OSMO_ASSERT(ms->ta() == qta/4);
+	OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
+
+	/* send fake data */
+	data_msg[0] = 0x00 | 0xf << 2;
+	data_msg[1] = uint8_t(0 | (tfi << 1));
+	data_msg[2] = uint8_t(0);/* BSN:7, E:1 */
+	data_msg[3] =uint8_t(1 << 3); /* BSN:7, E:1 */
+	data_msg[4] = uint8_t(1); /* E: 1 */
+
+	pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no];
+	pdch->rcv_block(&data_msg[0], 66, *fn, &meas);
+
+	ms = the_bts->ms_by_tlli(tlli);
+	OSMO_ASSERT(ms != NULL);
+	OSMO_ASSERT(ms->ta() == qta/4);
+	OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
+
+	/* send fake data */
+	data_msg[0] = 0x00 | 0xf << 2;
+	data_msg[1] = uint8_t(0 | (tfi << 1));
+	data_msg[2] = uint8_t(0);/* BSN:7, E:1 */
+	data_msg[3] =uint8_t(0 << 3); /* BSN:7, E:1 */
+	data_msg[4] = uint8_t(1); /* E: 1 */
+
+	pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no];
+	pdch->rcv_block(&data_msg[0], 66, *fn, &meas);
+
+	ms = the_bts->ms_by_tlli(tlli);
+	OSMO_ASSERT(ms != NULL);
+	OSMO_ASSERT(ms->ta() == qta/4);
+	OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
+
+	/* send fake data */
+	data_msg[0] = 0x00 | 0xf << 2;
+	data_msg[1] = uint8_t(0 | (tfi << 1));
+	data_msg[2] = uint8_t(0);/* BSN:7, E:1 */
+	data_msg[3] =uint8_t(1 << 3); /* BSN:7, E:1 */
+	data_msg[4] = uint8_t(1); /* E: 1 */
+
+	pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no];
+	pdch->rcv_block(&data_msg[0], 84, *fn, &meas);
+
+	ms = the_bts->ms_by_tlli(tlli);
+	OSMO_ASSERT(ms != NULL);
+	OSMO_ASSERT(ms->ta() == qta/4);
+	OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
+	/* send fake data */
+	data_msg[0] = 0x00 | 0xf << 2;
+	data_msg[1] = uint8_t(0 | (tfi << 1));
+	data_msg[2] = uint8_t(0);/* BSN:7, E:1 */
+	data_msg[3] =uint8_t(0 << 3); /* BSN:7, E:1 */
+	data_msg[4] = uint8_t(1); /* E: 1 */
+
+	pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no];
+	pdch->rcv_block(&data_msg[0], 84, *fn, &meas);
+
+	ms = the_bts->ms_by_tlli(tlli);
+	OSMO_ASSERT(ms != NULL);
+	OSMO_ASSERT(ms->ta() == qta/4);
+	OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
+
+	/* send fake data */
+	data_msg[0] = 0x00 | 0xf << 2;
+	data_msg[1] = uint8_t(0 | (tfi << 1));
+	data_msg[2] = uint8_t(0);/* BSN:7, E:1 */
+	data_msg[4] =uint8_t(1 << 7); /* BSN:7, E:1 */
+	data_msg[5] = uint8_t(1); /* E: 1 */
+
+	pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no];
+	pdch->rcv_block(&data_msg[0],124, *fn, &meas);
+
+	ms = the_bts->ms_by_tlli(tlli);
+	OSMO_ASSERT(ms != NULL);
+	OSMO_ASSERT(ms->ta() == qta/4);
+	OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
+
+	/* send fake data */
+	data_msg[0] = 0x00 | 0xf << 2;
+	data_msg[1] = uint8_t(0 | (tfi << 1));
+	data_msg[2] = uint8_t(0);/* BSN:7, E:1 */
+	data_msg[4] =uint8_t(0 << 7); /* BSN:7, E:1 */
+	data_msg[5] = uint8_t(1); /* E: 1 */
+
+	pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no];
+	pdch->rcv_block(&data_msg[0],124, *fn, &meas);
+
+	ms = the_bts->ms_by_tlli(tlli);
+	OSMO_ASSERT(ms != NULL);
+	OSMO_ASSERT(ms->ta() == qta/4);
+	OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
+
+	/* send fake data */
+	data_msg[0] = 0x00 | 0xf << 2;
+	data_msg[1] = uint8_t(0 | (tfi << 1));
+	data_msg[2] = uint8_t(0);/* BSN:7, E:1 */
+	data_msg[4] =uint8_t(1 << 7); /* BSN:7, E:1 */
+	data_msg[5] = uint8_t(1); /* E: 1 */
+
+	pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no];
+	pdch->rcv_block(&data_msg[0],148, *fn, &meas);
+
+	ms = the_bts->ms_by_tlli(tlli);
+	OSMO_ASSERT(ms != NULL);
+	OSMO_ASSERT(ms->ta() == qta/4);
+	OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
+
+	/* send fake data */
+	data_msg[0] = 0x00 | 0xf << 2;
+	data_msg[1] = uint8_t(0 | (tfi << 1));
+	data_msg[2] = uint8_t(0);/* BSN:7, E:1 */
+	data_msg[4] =uint8_t(0 << 7); /* BSN:7, E:1 */
+	data_msg[5] = uint8_t(1); /* E: 1 */
+
+	pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no];
+	pdch->rcv_block(&data_msg[0],148, *fn, &meas);
+
+	ms = the_bts->ms_by_tlli(tlli);
+	OSMO_ASSERT(ms != NULL);
+	OSMO_ASSERT(ms->ta() == qta/4);
+	OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
 	return ul_tbf;
 }
 
@@ -1449,7 +1656,7 @@ void test_tbf_two_phase()
 
 	printf("=== start %s ===\n", __func__);
 
-	setup_bts(&the_bts, ts_no, 9);
+	setup_bts(&the_bts, ts_no, 9, true);
 
 	ul_tbf = establish_ul_tbf_two_phase(&the_bts, ts_no, tlli, &fn, qta, ms_class);
 
@@ -2507,14 +2714,12 @@ void test_spb_handling()
         uint32_t tlli = 0xf1223344;
         const char *imsi = "0011223344";
         uint8_t ms_class = 1;
-        gprs_rlcmac_ul_tbf *ul_tbf;
-        GprsMs *ms;
 
         printf("=== start %s ===\n", __func__);
 
         setup_bts(&the_bts, ts_no, 7);
 
-        ul_tbf = spb_handler(&the_bts, ts_no, tlli, &fn, qta, ms_class);
+        spb_handler(&the_bts, ts_no, tlli, &fn, qta, ms_class);
 
 }
 
diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp
index 8bf735a..26e09e6 100644
--- a/tests/tbf/TbfTest.cpp
+++ b/tests/tbf/TbfTest.cpp
@@ -90,14 +90,14 @@ static void test_tbf_tlli_update()
 	 */
 	gprs_rlcmac_tbf *dl_tbf = tbf_alloc_dl_tbf(the_bts.bts_data(),
 						NULL,
-						0, 0, 0, 0);
+						0, 0, 0, 0, false);
 	OSMO_ASSERT(dl_tbf != NULL);
 	dl_tbf->update_ms(0x2342, GPRS_RLCMAC_DL_TBF);
 	dl_tbf->set_ta(4);
 
 	gprs_rlcmac_tbf *ul_tbf = tbf_alloc_ul_tbf(the_bts.bts_data(),
 						dl_tbf->ms(),
-						0, 0, 0, 0);
+						0, 0, 0, 0, false);
 	OSMO_ASSERT(ul_tbf != NULL);
 	ul_tbf->update_ms(0x2342, GPRS_RLCMAC_UL_TBF);
 
@@ -175,7 +175,7 @@ static gprs_rlcmac_dl_tbf *create_dl_tbf(BTS *the_bts, uint8_t ms_class,
 
 	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, 0, 1, false);
 	check_tbf(dl_tbf);
 
 	/* "Establish" the DL TBF */
@@ -452,7 +452,7 @@ static void test_tbf_exhaustion()
 		snprintf(imsi, sizeof(imsi), "001001%09d", i);
 
 		rc = gprs_rlcmac_dl_tbf::handle(bts, tlli, 0, imsi, ms_class, 0,
-			delay_csec, buf, sizeof(buf));
+			delay_csec, buf, sizeof(buf), false);
 
 		if (rc < 0)
 			break;
@@ -490,7 +490,7 @@ static void test_tbf_dl_llc_loss()
 	/* Handle LLC frame 1 */
 	memset(buf, 1, sizeof(buf));
 	rc = gprs_rlcmac_dl_tbf::handle(bts, tlli, 0, imsi, ms_class, 0,
-		delay_csec, buf, sizeof(buf));
+		delay_csec, buf, sizeof(buf), false);
 	OSMO_ASSERT(rc >= 0);
 
 	ms = the_bts.ms_store().get_ms(0, 0, imsi);
@@ -500,7 +500,7 @@ static void test_tbf_dl_llc_loss()
 	/* Handle LLC frame 2 */
 	memset(buf, 2, sizeof(buf));
 	rc = gprs_rlcmac_dl_tbf::handle(bts, tlli, 0, imsi, ms_class, 0,
-		delay_csec, buf, sizeof(buf));
+		delay_csec, buf, sizeof(buf), false);
 	OSMO_ASSERT(rc >= 0);
 
 	/* TBF establishment fails (timeout) */
@@ -509,7 +509,7 @@ static void test_tbf_dl_llc_loss()
 	/* Handle LLC frame 3 */
 	memset(buf, 3, sizeof(buf));
 	rc = gprs_rlcmac_dl_tbf::handle(bts, tlli, 0, imsi, ms_class, 0,
-		delay_csec, buf, sizeof(buf));
+		delay_csec, buf, sizeof(buf), false);
 	OSMO_ASSERT(rc >= 0);
 
 	OSMO_ASSERT(ms->dl_tbf() != NULL);
@@ -695,7 +695,7 @@ static void send_dl_data(BTS *the_bts, uint32_t tlli, const char *imsi,
 	ms = the_bts->ms_store().get_ms(tlli, 0, imsi);
 
 	gprs_rlcmac_dl_tbf::handle(the_bts->bts_data(), tlli, 0, imsi, 0, 0,
-		1000, data, data_size);
+		1000, data, data_size, false);
 
 	ms = the_bts->ms_by_imsi(imsi);
 	OSMO_ASSERT(ms != NULL);
-- 
1.7.9.5





More information about the osmocom-net-gprs mailing list