Adding single block allocation

It is mandatory to support it because MS may request a single block.
In this case the network must assign a single block.

It is possible to force single block allocation for all uplink requests
on RACH. (VTY option)
diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp
index 956d52f..1aeb9b1 100644
--- a/src/gprs_rlcmac.cpp
+++ b/src/gprs_rlcmac.cpp
@@ -879,6 +879,67 @@
 	}
 }
 
+/* starting time for assigning single slot
+ * This offset must be a multiple of 13. */
+#define AGCH_START_OFFSET 52
+
+LLIST_HEAD(gprs_rlcmac_sbas);
+
+int sba_alloc(uint8_t *_trx, uint8_t *_ts, uint32_t *_fn, uint8_t ta)
+{
+
+	struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
+	struct gprs_rlcmac_pdch *pdch;
+	struct gprs_rlcmac_sba *sba;
+	uint8_t trx, ts;
+	uint32_t fn;
+
+	sba = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_sba);
+	if (!sba)
+		return -ENOMEM;
+
+	for (trx = 0; trx < 8; trx++) {
+		for (ts = 0; ts < 8; ts++) {
+			pdch = &bts->trx[trx].pdch[ts];
+			if (!pdch->enable)
+				continue;
+			break;
+		}
+		if (ts < 8)
+			break;
+	}
+	if (trx == 8) {
+		LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH available.\n");
+		return -EINVAL;
+	}
+
+	fn = (pdch->last_rts_fn + AGCH_START_OFFSET) % 2715648;
+
+	sba->trx = trx;
+	sba->ts = ts;
+	sba->fn = fn;
+	sba->ta = ta;
+
+	llist_add(&sba->list, &gprs_rlcmac_sbas);
+
+	*_trx = trx;
+	*_ts = ts;
+	*_fn = fn;
+	return 0;
+}
+
+struct gprs_rlcmac_sba *sba_find(uint8_t trx, uint8_t ts, uint32_t fn)
+{
+	struct gprs_rlcmac_sba *sba;
+
+	llist_for_each_entry(sba, &gprs_rlcmac_sbas, list) {
+		if (sba->trx == trx && sba->ts == ts && sba->fn == fn)
+			return sba;
+	}
+
+	return NULL;
+}
+
 #if 0
 static void tbf_gsm_timer_cb(void *_tbf)
 {
@@ -1129,9 +1190,9 @@
 
 // GSM 04.08 9.1.18 Immediate assignment
 int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
-	uint32_t fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc,
+	uint32_t ref_fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc,
 	uint8_t tfi, uint8_t usf, uint32_t tlli,
-	uint8_t polling, uint32_t poll_fn)
+	uint8_t polling, uint32_t fn, uint8_t single_block)
 {
 	unsigned wp = 0;
 	uint8_t plen;
@@ -1157,9 +1218,9 @@
 
 	//10.5.2.30 Request Reference
 	bitvec_write_field(dest, wp,ra,8);                    // RA
-	bitvec_write_field(dest, wp,(fn / (26 * 51)) % 32,5); // T1'
-	bitvec_write_field(dest, wp,fn % 51,6);               // T3
-	bitvec_write_field(dest, wp,fn % 26,5);               // T2
+	bitvec_write_field(dest, wp,(ref_fn / (26 * 51)) % 32,5); // T1'
+	bitvec_write_field(dest, wp,ref_fn % 51,6);               // T3
+	bitvec_write_field(dest, wp,ref_fn % 26,5);               // T2
 
 	// 10.5.2.40 Timing Advance
 	bitvec_write_field(dest, wp,0x0,2); // spare
@@ -1193,9 +1254,9 @@
 		bitvec_write_field(dest, wp,0x0,4);   // TIMING_ADVANCE_INDEX
 		if (polling) {
 			bitvec_write_field(dest, wp,0x1,1);   // TBF Starting TIME present
-			bitvec_write_field(dest, wp,(poll_fn / (26 * 51)) % 32,5); // T1'
-			bitvec_write_field(dest, wp,poll_fn % 51,6);               // T3
-			bitvec_write_field(dest, wp,poll_fn % 26,5);               // T2
+			bitvec_write_field(dest, wp,(fn / (26 * 51)) % 32,5); // T1'
+			bitvec_write_field(dest, wp,fn % 51,6);               // T3
+			bitvec_write_field(dest, wp,fn % 26,5);               // T2
 		} else {
 			bitvec_write_field(dest, wp,0x0,1);   // TBF Starting TIME present
 		}
@@ -1209,20 +1270,32 @@
 		// GMS 04.08 10.5.2.37b 10.5.2.16
 		bitvec_write_field(dest, wp, 3, 2);    // "HH"
 		bitvec_write_field(dest, wp, 0, 2);    // "0" Packet Uplink Assignment
-		bitvec_write_field(dest, wp, 1, 1);    // Block Allocation : Not Single Block Allocation
-		bitvec_write_field(dest, wp, tfi, 5);  // TFI_ASSIGNMENT Temporary Flow Identity
-		bitvec_write_field(dest, wp, 0, 1);    // POLLING
-		bitvec_write_field(dest, wp, 0, 1);    // ALLOCATION_TYPE: dynamic
-		bitvec_write_field(dest, wp, usf, 3);    // USF
-		bitvec_write_field(dest, wp, 0, 1);    // USF_GRANULARITY
-		bitvec_write_field(dest, wp, 0 , 1);   // "0" power control: Not Present
-		bitvec_write_field(dest, wp, bts->initial_cs-1, 2);    // CHANNEL_CODING_COMMAND 
-		bitvec_write_field(dest, wp, 1, 1);    // TLLI_BLOCK_CHANNEL_CODING
-		bitvec_write_field(dest, wp, 1 , 1);   // "1" Alpha : Present
-		bitvec_write_field(dest, wp, 0, 4);    // Alpha
-		bitvec_write_field(dest, wp, 0, 5);    // Gamma
-		bitvec_write_field(dest, wp, 0, 1);    // TIMING_ADVANCE_INDEX_FLAG
-		bitvec_write_field(dest, wp, 0, 1);    // TBF_STARTING_TIME_FLAG
+		if (single_block) {
+			bitvec_write_field(dest, wp, 0, 1);    // Block Allocation : Single Block Allocation
+			bitvec_write_field(dest, wp, 1, 1);   // "1" Alpha : Present
+			bitvec_write_field(dest, wp, 0, 4);    // Alpha
+			bitvec_write_field(dest, wp, 0, 5);    // Gamma
+			bitvec_write_field(dest, wp, 0, 1);    // TIMING_ADVANCE_INDEX_FLAG
+			bitvec_write_field(dest, wp, 1, 1);    // TBF_STARTING_TIME_FLAG
+			bitvec_write_field(dest, wp,(fn / (26 * 51)) % 32,5); // T1'
+			bitvec_write_field(dest, wp,fn % 51,6);               // T3
+			bitvec_write_field(dest, wp,fn % 26,5);               // T2
+		} else {
+			bitvec_write_field(dest, wp, 1, 1);    // Block Allocation : Not Single Block Allocation
+			bitvec_write_field(dest, wp, tfi, 5);  // TFI_ASSIGNMENT Temporary Flow Identity
+			bitvec_write_field(dest, wp, 0, 1);    // POLLING
+			bitvec_write_field(dest, wp, 0, 1);    // ALLOCATION_TYPE: dynamic
+			bitvec_write_field(dest, wp, usf, 3);    // USF
+			bitvec_write_field(dest, wp, 0, 1);    // USF_GRANULARITY
+			bitvec_write_field(dest, wp, 0, 1);   // "0" power control: Not Present
+			bitvec_write_field(dest, wp, bts->initial_cs-1, 2);    // CHANNEL_CODING_COMMAND 
+			bitvec_write_field(dest, wp, 1, 1);    // TLLI_BLOCK_CHANNEL_CODING
+			bitvec_write_field(dest, wp, 1, 1);   // "1" Alpha : Present
+			bitvec_write_field(dest, wp, 0, 4);    // Alpha
+			bitvec_write_field(dest, wp, 0, 5);    // Gamma
+			bitvec_write_field(dest, wp, 0, 1);    // TIMING_ADVANCE_INDEX_FLAG
+			bitvec_write_field(dest, wp, 0, 1);    // TBF_STARTING_TIME_FLAG
+		}
 	}
 
 	return plen;
diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h
index e1c8343..5890bf0 100644
--- a/src/gprs_rlcmac.h
+++ b/src/gprs_rlcmac.h
@@ -79,6 +79,7 @@
 	int (*alloc_algorithm)(struct gprs_rlcmac_tbf *old_tbf,
 		struct gprs_rlcmac_tbf *tbf, uint32_t cust);
 	uint32_t alloc_algorithm_curst; /* options to customize algorithm */
+	uint8_t force_two_phase;
 };
 
 extern struct gprs_rlcmac_bts *gprs_rlcmac_bts;
@@ -219,6 +220,7 @@
 
 extern struct llist_head gprs_rlcmac_ul_tbfs; /* list of uplink TBFs */
 extern struct llist_head gprs_rlcmac_dl_tbfs; /* list of downlink TBFs */
+extern struct llist_head gprs_rlcmac_sbas; /* list of single block allocs */
 
 /*
  * paging entry
@@ -229,6 +231,21 @@
 	uint8_t identity_lv[9];
 };
 
+/*
+ * single block allocation entry
+ */
+struct gprs_rlcmac_sba {
+	struct llist_head list;
+	uint8_t trx;
+	uint8_t ts;
+	uint32_t fn;
+	uint8_t ta;
+};
+
+int sba_alloc(uint8_t *_trx, uint8_t *_ts, uint32_t *_fn, uint8_t ta);
+
+struct gprs_rlcmac_sba *sba_find(uint8_t trx, uint8_t ts, uint32_t fn);
+
 int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, uint8_t *_ts,
 	int8_t use_trx, int8_t first_ts);
 
@@ -270,9 +287,9 @@
 	uint32_t fn);
 
 int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, 
-        uint32_t fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc, 
+        uint32_t ref_fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc, 
         uint8_t tfi, uint8_t usf, uint32_t tlli, uint8_t polling,
-	uint32_t poll_fn);
+	uint32_t fn, uint8_t single_block);
 
 void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi,
 	uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli, 
diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp
index a1bed3c..98ce1b4 100644
--- a/src/gprs_rlcmac_data.cpp
+++ b/src/gprs_rlcmac_data.cpp
@@ -185,11 +185,61 @@
 	return 0;
 }
 
+static uint8_t get_ms_class_by_capability(MS_Radio_Access_capability_t *cap)
+{
+	int i;
+
+	for (i = 0; i < cap->Count_MS_RA_capability_value; i++) {
+		if (!cap->MS_RA_capability_value[i].u.Content.Exist_Multislot_capability)
+			continue;
+		if (!cap->MS_RA_capability_value[i].u.Content.Multislot_capability.Exist_GPRS_multislot_class)
+			continue;
+		return cap->MS_RA_capability_value[i].u.Content.Multislot_capability.GPRS_multislot_class;
+	}
+
+	return 0;
+}
+
+static struct gprs_rlcmac_tbf *alloc_ul_tbf(int8_t use_trx, int8_t first_ts,
+	uint8_t ms_class, uint32_t tlli, uint8_t ta,
+	struct gprs_rlcmac_tbf *dl_tbf)
+{
+	struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
+	uint8_t trx, ts;
+	struct gprs_rlcmac_tbf *tbf;
+	uint8_t tfi;
+
+	/* create new TBF, use sme TRX as DL TBF */
+	tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, use_trx, first_ts);
+	if (tfi < 0) {
+		LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
+		/* FIXME: send reject */
+		return NULL;
+	}
+	/* use multislot class of downlink TBF */
+	tbf = tbf_alloc(dl_tbf, GPRS_RLCMAC_UL_TBF, tfi, trx, ts, ms_class, 0);
+	if (!tbf) {
+		LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
+		/* FIXME: send reject */
+		return NULL;
+	}
+	tbf->tlli = tlli;
+	tbf->tlli_valid = 1; /* no contention resolution */
+	tbf->dir.ul.contention_resolution_done = 1;
+	tbf->ta = ta; /* use current TA */
+	tbf_new_state(tbf, GPRS_RLCMAC_ASSIGN);
+	tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH);
+	tbf_timer_start(tbf, 3169, bts->t3169, 0);
+
+	return tbf;
+}
+
+
+
 /* Received Uplink RLC control block. */
 int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
 	uint32_t fn)
 {
-	struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
 	int8_t tfi = 0; /* must be signed */
 	uint32_t tlli = 0;
 	struct gprs_rlcmac_tbf *tbf;
@@ -318,34 +368,10 @@
 		}
 		/* check for channel request */
 		if (ul_control_block->u.Packet_Downlink_Ack_Nack.Exist_Channel_Request_Description) {
-			uint8_t trx, ts;
-			struct gprs_rlcmac_tbf *ul_tbf;
-
 			LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack "
 				"message, so we provide one:\n");
-uplink_request:
-			/* create new TBF, use sme TRX as DL TBF */
-			tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, tbf->trx, tbf->first_ts);
-			if (tfi < 0) {
-				LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
-				/* FIXME: send reject */
-				break;
-			}
-			/* use multislot class of downlink TBF */
-			ul_tbf = tbf_alloc(tbf, GPRS_RLCMAC_UL_TBF, tfi, trx,
-				ts, tbf->ms_class, 0);
-			if (!ul_tbf) {
-				LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
-				/* FIXME: send reject */
-				break;
-			}
-			ul_tbf->tlli = tbf->tlli;
-			ul_tbf->tlli_valid = 1; /* no contention resolution */
-			ul_tbf->dir.ul.contention_resolution_done = 1;
-			ul_tbf->ta = tbf->ta; /* use current TA */
-			tbf_new_state(ul_tbf, GPRS_RLCMAC_ASSIGN);
-			ul_tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH);
-			tbf_timer_start(ul_tbf, 3169, bts->t3169, 0);
+
+			alloc_ul_tbf(tbf->trx, tbf->first_ts, tbf->ms_class, tbf->tlli, tbf->ta, tbf);
 			/* schedule uplink assignment */
 			tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
 		}
@@ -355,7 +381,23 @@
 			tlli = ul_control_block->u.Packet_Resource_Request.ID.u.TLLI;
 			tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF);
 			if (!tbf) {
-				LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESSOURCE REQ unknown uplink TLLI=0x%08x\n", tlli);
+				uint8_t ms_class = 0;
+				LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF "
+					"in packet ressource request of single "
+					"block, so we provide one:\n");
+				if (ul_control_block->u.Packet_Resource_Request.Exist_MS_Radio_Access_capability)
+					ms_class = get_ms_class_by_capability(&ul_control_block->u.Packet_Resource_Request.MS_Radio_Access_capability);
+				if (!ms_class)
+					LOGP(DRLCMAC, LOGL_NOTICE, "MS does not give us a class.\n");
+				tbf = alloc_ul_tbf(trx, ts, ms_class, tlli, 0, NULL);
+#warning FIXME TA!!!
+				if (!tbf)
+					break;
+				/* set control ts to current MS's TS, until assignment complete */
+				LOGP(DRLCMAC, LOGL_DEBUG, "Change control TS to %d until assinment is complete.\n", ts);
+				tbf->control_ts = ts;
+				/* schedule uplink assignment */
+				tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
 				break;
 			}
 			tfi = tbf->tfi;
@@ -658,11 +700,18 @@
 	int final = (tbf->state == GPRS_RLCMAC_FINISHED);
 	struct msgb *msg;
 
-	if (final && tbf->poll_state != GPRS_RLCMAC_POLL_NONE) {
-		LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
-			"sheduled for TBF=%d, so we must wait for final uplink "
-			"ack...\n", tbf->tfi);
+	if (final) {
+		if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE) {
+			LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
+				"sheduled for TBF=%d, so we must wait for "
+				"final uplink ack...\n", tbf->tfi);
 			return NULL;
+		}
+		if (sba_find(tbf->trx, tbf->control_ts, (fn + 13) % 2715648)) {
+			LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
+				"scheduled for single block allocation...\n");
+			return NULL;
+		}
 	}
 
 	msg = msgb_alloc(23, "rlcmac_ul_ack");
@@ -907,6 +956,11 @@
 			"assignment...\n", tbf->tfi);
 			return NULL;
 	}
+	if (sba_find(tbf->trx, tbf->control_ts, (fn + 13) % 2715648)) {
+		LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already scheduled for "
+			"single block allocation...\n");
+			return NULL;
+	}
 #endif
 
 	/* on down TBF we get the uplink TBF to be assigned. */
@@ -935,8 +989,8 @@
 	bitvec_unhex(ass_vec,
 		"2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
 	write_packet_uplink_assignment(ass_vec, tbf->tfi,
-		(tbf->direction == GPRS_RLCMAC_DL_TBF), 0, 0, new_tbf,
-		POLLING_ASSIGNMENT_UL);
+		(tbf->direction == GPRS_RLCMAC_DL_TBF), tbf->tlli,
+		tbf->tlli_valid, new_tbf, POLLING_ASSIGNMENT_UL);
 	bitvec_pack(ass_vec, msgb_put(msg, 23));
 	RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
 	LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++\n");
@@ -965,37 +1019,73 @@
 	struct gprs_rlcmac_tbf *tbf;
 	uint8_t trx, ts;
 	int8_t tfi; /* must be signed */
+	uint8_t sb = 0;
+	uint32_t sb_fn = 0;
+	int rc;
+	uint8_t plen;
 
 	LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF on RACH, so we provide "
 		"one:\n");
-	// Create new TBF
-	tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, -1, -1);
-	if (tfi < 0) {
-		LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
-		/* FIXME: send reject */
-		return -EBUSY;
-	}
-	/* set class to 0, since we don't know the multislot class yet */
-	tbf = tbf_alloc(NULL, GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 0, 1);
-	if (!tbf) {
-		LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
-		/* FIXME: send reject */
-		return -EBUSY;
+	if ((ra & 0xf8) == 0x70) {
+		LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single block "
+			"allocation\n");
+		sb = 1;
+	} else if (bts->force_two_phase) {
+		LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single phase access, "
+			"but we force two phase access\n");
+		sb = 1;
 	}
 	if (qta < 0)
 		qta = 0;
 	if (qta > 252)
 		qta = 252;
-	tbf->ta = qta >> 2;
-	tbf_new_state(tbf, GPRS_RLCMAC_FLOW);
-	tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_CCCH);
-	tbf_timer_start(tbf, 3169, bts->t3169, 0);
-	LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [UPLINK] START TFI: %u\n", tbf->tfi);
-	LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] TFI: %u RACH qbit-ta=%d ra=%d, Fn=%d (%d,%d,%d)\n", tbf->tfi, qta, ra, Fn, (Fn / (26 * 51)) % 32, Fn % 51, Fn % 26);
-	LOGP(DRLCMAC, LOGL_INFO, "TX: START TFI: %u Immediate Assignment Uplink (AGCH)\n", tbf->tfi);
+	if (sb) {
+		rc = sba_alloc(&trx, &ts, &sb_fn, qta >> 2);
+		if (rc < 0)
+			return rc;
+		LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] RACH qbit-ta=%d "
+			"ra=0x%02x, Fn=%d (%d,%d,%d)\n", qta, ra, Fn,
+			(Fn / (26 * 51)) % 32, Fn % 51, Fn % 26);
+		LOGP(DRLCMAC, LOGL_INFO, "TX: Immediate Assignment Uplink "
+			"(AGCH)\n");
+	} else {
+		// Create new TBF
+		tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, -1, -1);
+		if (tfi < 0) {
+			LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
+			/* FIXME: send reject */
+			return -EBUSY;
+		}
+		/* set class to 0, since we don't know the multislot class yet */
+		tbf = tbf_alloc(NULL, GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 0, 1);
+		if (!tbf) {
+			LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
+			/* FIXME: send reject */
+			return -EBUSY;
+		}
+		tbf->ta = qta >> 2;
+		tbf_new_state(tbf, GPRS_RLCMAC_FLOW);
+		tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_CCCH);
+		tbf_timer_start(tbf, 3169, bts->t3169, 0);
+		LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [UPLINK] START TFI: %u\n",
+			tbf->tfi);
+		LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] TFI: %u RACH "
+			"qbit-ta=%d ra=0x%02x, Fn=%d (%d,%d,%d)\n", tbf->tfi,
+			qta, ra, Fn, (Fn / (26 * 51)) % 32, Fn % 51, Fn % 26);
+		LOGP(DRLCMAC, LOGL_INFO, "TX: START TFI: %u Immediate "
+			"Assignment Uplink (AGCH)\n", tbf->tfi);
+	}
 	bitvec *immediate_assignment = bitvec_alloc(22) /* without plen */;
-	bitvec_unhex(immediate_assignment, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
-	int plen = write_immediate_assignment(immediate_assignment, 0, ra, Fn, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc, tbf->tfi, tbf->dir.ul.usf[tbf->first_ts], 0, 0, 0);
+	bitvec_unhex(immediate_assignment,
+		"2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
+	if (sb)
+		plen = write_immediate_assignment(immediate_assignment, 0, ra,
+			Fn, qta >> 2, bts->trx[trx].arfcn, ts,
+			bts->trx[trx].pdch[ts].tsc, 0, 0, 0, 0, sb_fn, 1);
+	else
+		plen = write_immediate_assignment(immediate_assignment, 0, ra,
+			Fn, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc,
+			tbf->tfi, tbf->dir.ul.usf[tbf->first_ts], 0, 0, 0, 0);
 	pcu_l1if_tx_agch(immediate_assignment, plen);
 	bitvec_free(immediate_assignment);
 
@@ -1355,6 +1445,10 @@
 			LOGP(DRLCMAC, LOGL_DEBUG, "Polling cannot be "
 				"sheduled in this TS %d, waiting for "
 				"TS %d\n", ts, tbf->control_ts);
+		else if (sba_find(tbf->trx, ts, (fn + 13) % 2715648))
+			LOGP(DRLCMAC, LOGL_DEBUG, "Polling cannot be "
+				"sheduled, because single block alllocation "
+				"already exists\n");
 		else  {
 			LOGP(DRLCMAC, LOGL_DEBUG, "Polling sheduled in this "
 				"TS %d\n", ts);
@@ -1534,6 +1628,11 @@
 				"assignment...\n", tbf->tfi);
 				return NULL;
 		}
+		if (sba_find(tbf->trx, tbf->control_ts, (fn + 13) % 2715648)) {
+			LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
+				"scheduled for single block allocation...\n");
+			return NULL;
+		}
 	}
 
 	/* on uplink TBF we get the downlink TBF to be assigned. */
@@ -1604,7 +1703,7 @@
 	bitvec_unhex(immediate_assignment, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
 	/* use request reference that has maximum distance to current time,
 	 * so the assignment will not conflict with possible RACH requests. */
-	int plen = write_immediate_assignment(immediate_assignment, 1, 125, (tbf->pdch[tbf->first_ts]->last_rts_fn + 21216) % 2715648, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc, tbf->tfi, 0, tbf->tlli, poll, tbf->poll_fn);
+	int plen = write_immediate_assignment(immediate_assignment, 1, 125, (tbf->pdch[tbf->first_ts]->last_rts_fn + 21216) % 2715648, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc, tbf->tfi, 0, tbf->tlli, poll, tbf->poll_fn, 0);
 	pcu_l1if_tx_pch(immediate_assignment, plen, imsi);
 	bitvec_free(immediate_assignment);
 }
diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp
index 9ffdfb6..b5deeb0 100644
--- a/src/gprs_rlcmac_sched.cpp
+++ b/src/gprs_rlcmac_sched.cpp
@@ -67,6 +67,26 @@
 	return poll_fn;
 }
 
+uint32_t sched_sba(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr)
+{
+	uint32_t sba_fn;
+	struct gprs_rlcmac_sba *sba;
+
+	/* check special TBF for events */
+	sba_fn = fn + 4;
+	if ((block_nr % 3) == 2)
+		sba_fn ++;
+	sba_fn = sba_fn % 2715648;
+	sba = sba_find(trx, ts, sba_fn);
+	if (sba) {
+		llist_del(&sba->list);
+		talloc_free(sba);
+		return sba_fn;
+	}
+
+	return 0xffffffff;
+}
+
 uint8_t sched_select_uplink(uint8_t trx, uint8_t ts, uint32_t fn,
 	uint8_t block_nr, struct gprs_rlcmac_pdch *pdch)
 {
@@ -135,14 +155,15 @@
 		return msg;
 	}
 	/* schedule PACKET PAGING REQUEST */
-	if (llist_empty(&pdch->paging_list))
-		return NULL;
-	msg = gprs_rlcmac_send_packet_paging_request(pdch);
-	if (msg)
+	if (!llist_empty(&pdch->paging_list))
+		msg = gprs_rlcmac_send_packet_paging_request(pdch);
+	if (msg) {
 		LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling paging request "
 			"message at RTS for (TRX=%d, TS=%d)\n", trx, ts);
+		return msg;
+	}
 
-	return msg;
+	return NULL;
 }
 
 struct msgb *sched_select_downlink(uint8_t trx, uint8_t ts, uint32_t fn,
@@ -208,7 +229,7 @@
 		*ul_ass_tbf = NULL, *ul_ack_tbf = NULL;
 	uint8_t usf = 0x7;
 	struct msgb *msg = NULL;
-	uint32_t poll_fn;
+	uint32_t poll_fn, sba_fn;
 
 	if (trx >= 8 || ts >= 8)
 		return -EINVAL;
@@ -234,6 +255,13 @@
 			(poll_tbf->direction == GPRS_RLCMAC_UL_TBF)
 				? "UL" : "DL", poll_tbf->tfi);
 		/* use free USF */
+	/* else. check for sba */
+	else if ((sba_fn = sched_sba(trx, ts, fn, block_nr) != 0xffffffff))
+		LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d "
+			"TS=%d FN=%d block_nr=%d scheduling free USF for "
+			"single block allocation at FN=%d\n", trx, ts, fn,
+			block_nr, sba_fn);
+		/* use free USF */
 	/* else, we search for uplink ressource */
 	else
 		usf = sched_select_uplink(trx, ts, fn, block_nr, pdch);
diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp
index e5fbad9..2ed023a 100644
--- a/src/pcu_l1_if.cpp
+++ b/src/pcu_l1_if.cpp
@@ -247,11 +247,12 @@
 	return rc;
 }
 
-int flush_pdch(struct gprs_rlcmac_pdch *pdch)
+int flush_pdch(struct gprs_rlcmac_pdch *pdch, uint8_t trx, uint8_t ts)
 {
 	uint8_t tfi;
 	struct gprs_rlcmac_tbf *tbf;
 	struct gprs_rlcmac_paging *pag;
+	struct gprs_rlcmac_sba *sba, *sba2;
 
 	/* kick all TBF on slot */
 	for (tfi = 0; tfi < 32; tfi++) {
@@ -266,6 +267,13 @@
 	while ((pag = gprs_rlcmac_dequeue_paging(pdch)))
 		talloc_free(pag);
 
+	llist_for_each_entry_safe(sba, sba2, &gprs_rlcmac_sbas, list) {
+		if (sba->trx == trx && sba->ts == ts) {
+			llist_del(&sba->list);
+			talloc_free(sba);
+		}
+	}
+
 	return 0;
 }
 
@@ -294,7 +302,8 @@
 			bts->trx[trx].arfcn = info_ind->trx[trx].arfcn;
 			for (ts = 0; ts < 8; ts++) {
 				if (bts->trx[trx].pdch[ts].enable)
-					flush_pdch(&bts->trx[trx].pdch[ts]);
+					flush_pdch(&bts->trx[trx].pdch[ts],
+						trx, ts);
 			}
 		}
 		gprs_bssgp_destroy();
@@ -399,7 +408,7 @@
 				if (pdch->enable) {
 					pcu_tx_act_req(trx, ts, 0);
 					pdch->enable = 0;
-					flush_pdch(pdch);
+					flush_pdch(pdch, trx, ts);
 				}
 			}
 		}
diff --git a/src/pcu_vty.c b/src/pcu_vty.c
index e5d3765..39a1b72 100644
--- a/src/pcu_vty.c
+++ b/src/pcu_vty.c
@@ -90,6 +90,8 @@
 		vty_out(vty, " alloc-algorithm a%s", VTY_NEWLINE);
 	if (bts->alloc_algorithm == alloc_algorithm_b)
 		vty_out(vty, " alloc-algorithm b%s", VTY_NEWLINE);
+	if (bts->force_two_phase)
+		vty_out(vty, " two-phase-access%s", VTY_NEWLINE);
 
 }
 
@@ -193,6 +195,30 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_pcu_two_phase,
+      cfg_pcu_two_phase_cmd,
+      "two-phase-access",
+      "Force two phase access when MS requests single phase access\n")
+{
+	struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
+
+	bts->force_two_phase = 1;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_pcu_no_two_phase,
+      cfg_pcu_no_two_phase_cmd,
+      "no two-phase-access",
+      NO_STR "Only use two phase access when requested my MS\n")
+{
+	struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
+
+	bts->force_two_phase = 0;
+
+	return CMD_SUCCESS;
+}
+
 static const char pcu_copyright[] =
 	"Copyright (C) 2012 by ...\r\n"
 	"License GNU GPL version 2 or later\r\n"
@@ -222,6 +248,8 @@
 	install_element(PCU_NODE, &cfg_pcu_queue_lifetime_inf_cmd);
 	install_element(PCU_NODE, &cfg_pcu_no_queue_lifetime_cmd);
 	install_element(PCU_NODE, &cfg_pcu_alloc_cmd);
+	install_element(PCU_NODE, &cfg_pcu_two_phase_cmd);
+	install_element(PCU_NODE, &cfg_pcu_no_two_phase_cmd);
 	install_element(PCU_NODE, &ournode_end_cmd);
 
 	return 0;