Move resource allocation outside of tbf allocation

This patch finally decouples TBF allocation from resource allocation.
This will allow in the future reserving resources without having to
require a TBF object to exist.

Change-Id: I2856c946cb62d6e5372a1099b60e5f3456eb8fd4
diff --git a/src/gprs_ms.c b/src/gprs_ms.c
index 0018252..739bbcd 100644
--- a/src/gprs_ms.c
+++ b/src/gprs_ms.c
@@ -24,6 +24,7 @@
 #include "pcu_utils.h"
 #include "nacc_fsm.h"
 #include "tbf_ul_ack_fsm.h"
+#include "alloc_algo.h"
 
 #include <time.h>
 
@@ -1119,15 +1120,46 @@
  */
 struct gprs_rlcmac_ul_tbf *ms_new_ul_tbf_assigned_pacch(struct GprsMs *ms, int8_t use_trx)
 {
-	const bool single_slot = false;
 	struct gprs_rlcmac_ul_tbf *ul_tbf;
+	const struct alloc_resources_req req = {
+		.bts = ms->bts,
+		.ms = ms,
+		.direction = GPRS_RLCMAC_UL_TBF,
+		.single = false,
+		.use_trx = use_trx,
+	};
+	struct alloc_resources_res res = {};
+	int rc;
 
-	ul_tbf = ul_tbf_alloc(ms->bts, ms, use_trx, single_slot);
+	rc = the_pcu->alloc_algorithm(&req, &res);
+	if (rc < 0) {
+		LOGPMS(ms, DTBF, LOGL_NOTICE,
+			"Timeslot Allocation failed: trx = %d, single_slot = %d\n",
+			req.use_trx, req.single);
+		bts_do_rate_ctr_inc(ms->bts, CTR_TBF_ALLOC_FAIL);
+		return NULL;
+	}
+
+	ul_tbf = ul_tbf_alloc(ms->bts, ms);
 	if (!ul_tbf) {
-		LOGPMS(ms, DTBF, LOGL_NOTICE, "No PDCH resource\n");
+		LOGPMS(ms, DTBF, LOGL_NOTICE, "ul_tbf_alloc() failed\n");
 		/* Caller will most probably send a Imm Ass Reject after return */
 		return NULL;
 	}
+
+	/* Update MS, really allocate the resources */
+	if (res.reserved_ul_slots != ms_reserved_ul_slots(ms) ||
+	    res.reserved_dl_slots != ms_reserved_dl_slots(ms)) {
+		/* The reserved slots have changed, update the MS */
+		ms_set_reserved_slots(ms, res.trx, res.reserved_ul_slots, res.reserved_dl_slots);
+	}
+	ms_set_first_common_ts(ms, res.first_common_ts);
+
+	/* Apply allocated resources to TBF: */
+	ul_tbf_apply_allocated_resources(ul_tbf, &res);
+
+	ms_attach_tbf(ms, ul_tbf_as_tbf(ul_tbf));
+
 	osmo_fsm_inst_dispatch(tbf_state_fi(ul_tbf_as_tbf(ul_tbf)), TBF_EV_ASSIGN_ADD_PACCH, NULL);
 	/* Contention resolution is considered to be done since TLLI is known in MS */
 	return ul_tbf;
@@ -1137,30 +1169,79 @@
  * packet access", where MS requested only 1 PDCH TS (TS 44.018 Table 9.1.8.1). */
 struct gprs_rlcmac_ul_tbf *ms_new_ul_tbf_assigned_agch(struct GprsMs *ms)
 {
-	const int8_t trx_no = -1;
-	const bool single_slot = true;
 	struct gprs_rlcmac_ul_tbf *ul_tbf;
+	const struct alloc_resources_req req = {
+		.bts = ms->bts,
+		.ms = ms,
+		.direction = GPRS_RLCMAC_UL_TBF,
+		.single = true,
+		.use_trx = -1,
+	};
+	struct alloc_resources_res res = {};
+	int rc;
 
-	ul_tbf = ul_tbf_alloc(ms->bts, ms, trx_no, single_slot);
+	rc = the_pcu->alloc_algorithm(&req, &res);
+	if (rc < 0) {
+		LOGPMS(ms, DTBF, LOGL_NOTICE,
+			"Timeslot Allocation failed: trx = %d, single_slot = %d\n",
+			req.use_trx, req.single);
+		bts_do_rate_ctr_inc(ms->bts, CTR_TBF_ALLOC_FAIL);
+		return NULL;
+	}
+
+	ul_tbf = ul_tbf_alloc(ms->bts, ms);
 	if (!ul_tbf) {
-		LOGP(DTBF, LOGL_NOTICE, "No PDCH resource for Uplink TBF\n");
+		LOGPMS(ms, DTBF, LOGL_NOTICE, "ul_tbf_alloc() failed\n");
 		/* Caller will most probably send a Imm Ass Reject after return */
 		return NULL;
 	}
+
+	/* Update MS, really allocate the resources */
+	if (res.reserved_ul_slots != ms_reserved_ul_slots(ms) ||
+	    res.reserved_dl_slots != ms_reserved_dl_slots(ms)) {
+		/* The reserved slots have changed, update the MS */
+		ms_set_reserved_slots(ms, res.trx, res.reserved_ul_slots, res.reserved_dl_slots);
+	}
+	ms_set_first_common_ts(ms, res.first_common_ts);
+
+	/* Apply allocated resources to TBF: */
+	ul_tbf_apply_allocated_resources(ul_tbf, &res);
+
+	ms_attach_tbf(ms, ul_tbf_as_tbf(ul_tbf));
+
 	osmo_fsm_inst_dispatch(tbf_state_fi(ul_tbf_as_tbf(ul_tbf)), TBF_EV_ASSIGN_ADD_CCCH, NULL);
 	return ul_tbf;
 }
 
 /* Create a temporary dummy TBF to Tx a ImmAssReject if allocating a new one during
  * packet resource Request failed. This is similar as ul_tbf_alloc() but without
- * calling tbf->setup() (in charge of TFI/USF allocation), and reusing resources
+ * calling alloc_algo (in charge of TFI/USF allocation), and reusing resources
  * from Packet Resource Request we received. See TS 44.060 sec 7.1.3.2.1  */
 struct gprs_rlcmac_ul_tbf *ms_new_ul_tbf_rejected_pacch(struct GprsMs *ms, struct gprs_rlcmac_pdch *pdch)
 {
 	struct gprs_rlcmac_ul_tbf *ul_tbf;
-	ul_tbf = ul_tbf_alloc_rejected(ms->bts, ms, pdch);
+	struct alloc_resources_res fake_res = {
+		.trx = pdch->trx,
+		.first_common_ts = pdch,
+		.reserved_ul_slots = 0,
+		.reserved_dl_slots = 0,
+		.ass_slots_mask = 0,
+		.upgrade_to_multislot = false,
+		.tfi = TBF_TFI_UNSET,
+		.usf = {0},
+	};
+	ul_tbf = ul_tbf_alloc(ms->bts, ms);
 	if (!ul_tbf)
 		return NULL;
+
+	/* The only one TS is the common, control TS */
+	ms_set_first_common_ts(ms, pdch);
+
+	/* Apply fake resources to TBF, to attach it to the proper TRX/PDCH: */
+	ul_tbf_apply_allocated_resources(ul_tbf, &fake_res);
+
+	ms_attach_tbf(ms, ul_tbf_as_tbf(ul_tbf));
+
 	osmo_fsm_inst_dispatch(tbf_state_fi(ul_tbf_as_tbf(ul_tbf)), TBF_EV_ASSIGN_ADD_PACCH, NULL);
 	osmo_fsm_inst_dispatch(tbf_ul_ass_fi(ul_tbf_as_tbf(ul_tbf)), TBF_UL_ASS_EV_SCHED_ASS_REJ, NULL);
 
@@ -1174,16 +1255,45 @@
 int ms_new_dl_tbf_assigned_on_pacch(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf)
 {
 	OSMO_ASSERT(tbf);
-	const int8_t trx_no = tbf_get_trx(tbf)->trx_no;
-	const bool single_slot = false;
 	struct gprs_rlcmac_dl_tbf *dl_tbf;
+	const struct alloc_resources_req req = {
+		.bts = ms->bts,
+		.ms = ms,
+		.direction = GPRS_RLCMAC_DL_TBF,
+		.single = false,
+		.use_trx = tbf_get_trx(tbf)->trx_no,
+	};
+	struct alloc_resources_res res = {};
+	int rc;
 
-	dl_tbf = dl_tbf_alloc(ms->bts, ms, trx_no, single_slot);
-	if (!dl_tbf) {
-		LOGPMS(ms, DTBF, LOGL_NOTICE, "No PDCH resource\n");
+	rc = the_pcu->alloc_algorithm(&req, &res);
+	if (rc < 0) {
+		LOGPMS(ms, DTBF, LOGL_NOTICE,
+			"Timeslot Allocation failed: trx = %d, single_slot = %d\n",
+			req.use_trx, req.single);
+		bts_do_rate_ctr_inc(ms->bts, CTR_TBF_ALLOC_FAIL);
 		return -EBUSY;
 	}
 
+	dl_tbf = dl_tbf_alloc(ms->bts, ms);
+	if (!dl_tbf) {
+		LOGPMS(ms, DTBF, LOGL_NOTICE, "dl_tbf_alloc() failed\n");
+		return -1;
+	}
+
+	/* Update MS, really allocate the resources */
+	if (res.reserved_ul_slots != ms_reserved_ul_slots(ms) ||
+	    res.reserved_dl_slots != ms_reserved_dl_slots(ms)) {
+		/* The reserved slots have changed, update the MS */
+		ms_set_reserved_slots(ms, res.trx, res.reserved_ul_slots, res.reserved_dl_slots);
+	}
+	ms_set_first_common_ts(ms, res.first_common_ts);
+
+	/* Apply allocated resources to TBF: */
+	dl_tbf_apply_allocated_resources(dl_tbf, &res);
+
+	ms_attach_tbf(ms, dl_tbf_as_tbf(dl_tbf));
+
 	LOGPTBFDL(dl_tbf, LOGL_DEBUG, "[DOWNLINK] START (PACCH)\n");
 	dl_tbf_trigger_ass_on_pacch(dl_tbf, tbf);
 	return 0;
@@ -1194,16 +1304,45 @@
  */
 int ms_new_dl_tbf_assigned_on_pch(struct GprsMs *ms)
 {
-	const int8_t trx_no = -1;
-	const bool single_slot = true;
 	struct gprs_rlcmac_dl_tbf *dl_tbf;
+	const struct alloc_resources_req req = {
+		.bts = ms->bts,
+		.ms = ms,
+		.direction = GPRS_RLCMAC_DL_TBF,
+		.single = true,
+		.use_trx = -1,
+	};
+	struct alloc_resources_res res = {};
+	int rc;
 
-	dl_tbf = dl_tbf_alloc(ms->bts, ms, trx_no, single_slot);
-	if (!dl_tbf) {
-		LOGPMS(ms, DTBF, LOGL_NOTICE, "No PDCH resource\n");
+	rc = the_pcu->alloc_algorithm(&req, &res);
+	if (rc < 0) {
+		LOGPMS(ms, DTBF, LOGL_NOTICE,
+			"Timeslot Allocation failed: trx = %d, single_slot = %d\n",
+			req.use_trx, req.single);
+		bts_do_rate_ctr_inc(ms->bts, CTR_TBF_ALLOC_FAIL);
 		return -EBUSY;
 	}
 
+	dl_tbf = dl_tbf_alloc(ms->bts, ms);
+	if (!dl_tbf) {
+		LOGPMS(ms, DTBF, LOGL_NOTICE, "dl_tbf_alloc() failed\n");
+		return -1;
+	}
+
+	/* Update MS, really allocate the resources */
+	if (res.reserved_ul_slots != ms_reserved_ul_slots(ms) ||
+	    res.reserved_dl_slots != ms_reserved_dl_slots(ms)) {
+		/* The reserved slots have changed, update the MS */
+		ms_set_reserved_slots(ms, res.trx, res.reserved_ul_slots, res.reserved_dl_slots);
+	}
+	ms_set_first_common_ts(ms, res.first_common_ts);
+
+	/* Apply allocated resources to TBF: */
+	dl_tbf_apply_allocated_resources(dl_tbf, &res);
+
+	ms_attach_tbf(ms, dl_tbf_as_tbf(dl_tbf));
+
 	LOGPTBFDL(dl_tbf, LOGL_DEBUG, "[DOWNLINK] START (PCH)\n");
 	dl_tbf_trigger_ass_on_pch(dl_tbf);
 	return 0;
diff --git a/src/tbf.cpp b/src/tbf.cpp
index 921611d..7f549c7 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -222,8 +222,10 @@
 	 * confirmation from the MS and goes through the FLOW state. Hence, we
 	 * may have ULC pollings ongoing and we need to make sure we drop all
 	 * reserved nodes there: */
-	if (tbf->control_ts)
+	if (tbf->control_ts) {
 		pdch_ulc_release_tbf(tbf->control_ts->ulc, tbf);
+		tbf->control_ts = NULL;
+	}
 
 	/* Now simply detach from all attached PDCHs */
 	for (ts = 0; ts < 8; ts++) {
@@ -233,6 +235,12 @@
 		tbf->pdch[ts]->detach_tbf(tbf);
 		tbf->pdch[ts] = NULL;
 	}
+
+	/* Detach from TRX: */
+	if (tbf->trx) {
+		llist_del(tbf_trx_list(tbf));
+		tbf->trx = NULL;
+	}
 }
 
 void tbf_free(struct gprs_rlcmac_tbf *tbf)
@@ -264,7 +272,6 @@
 	tbf->stop_timers("freeing TBF");
 	/* TODO: Could/Should generate  bssgp_tx_llc_discarded */
 	tbf_unlink_pdch(tbf);
-	llist_del(tbf_trx_list(tbf));
 
 	if (tbf->ms())
 		tbf->set_ms(NULL);
@@ -572,68 +579,6 @@
 	}
 }
 
-int gprs_rlcmac_tbf::alloc_algorithm(const struct alloc_resources_req *req)
-{
-	int rc;
-
-	/* select algorithm */
-	struct alloc_resources_res res = {};
-	rc = the_pcu->alloc_algorithm(req, &res);
-	if (rc < 0)
-		return rc;
-
-	/* The allocation will be successful, so the system state and tbf/ms
-	 * may be modified from now on. */
-
-	/* Update MS, really allocate the resources */
-	if (res.reserved_ul_slots != ms_reserved_ul_slots(req->ms) ||
-	    res.reserved_dl_slots != ms_reserved_dl_slots(req->ms)) {
-		/* The reserved slots have changed, update the MS */
-		ms_set_reserved_slots(ms(), res.trx, res.reserved_ul_slots, res.reserved_dl_slots);
-	}
-	ms_set_first_common_ts(ms(), res.first_common_ts);
-
-	/* Assign TRX,TS,TFI,USF to TBF: */
-	this->apply_allocated_resources(&res);
-
-	return 0;
-}
-
-int gprs_rlcmac_tbf::setup(int8_t use_trx, bool single_slot)
-{
-	int rc;
-	const struct alloc_resources_req req = {
-		.bts = bts,
-		.ms = this->ms(),
-		.direction = this->direction,
-		.single = single_slot,
-		.use_trx = use_trx,
-	};
-
-	/* select algorithm */
-	rc = this->alloc_algorithm(&req);
-	/* if no resource */
-	if (rc < 0) {
-		LOGPTBF(this, LOGL_NOTICE,
-			"Timeslot Allocation failed: trx = %d, single_slot = %d\n",
-			use_trx, single_slot);
-		bts_do_rate_ctr_inc(bts, CTR_TBF_ALLOC_FAIL);
-		return -1;
-	}
-	/* assign initial control ts */
-	tbf_assign_control_ts(this);
-
-	LOGPTBF(this, LOGL_INFO,
-		"Allocated: trx = %d, ul_slots = %02x, dl_slots = %02x\n",
-		this->trx->trx_no, ul_slots(), dl_slots());
-
-	tbf_update_state_fsm_name(this);
-
-	ms_attach_tbf(m_ms, this);
-
-	return 0;
-}
-
 const char *tbf_name(const gprs_rlcmac_tbf *tbf)
 {
 	return tbf ? tbf->name() : "(no TBF)";
diff --git a/src/tbf.h b/src/tbf.h
index ba2a755..878c77b 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -165,7 +165,6 @@
 	virtual gprs_rlc_window *window() = 0;
 	virtual void apply_allocated_resources(const struct alloc_resources_res *res) = 0;
 
-	int setup(int8_t use_trx, bool single_slot);
 	bool state_is(enum tbf_fsm_states rhs) const;
 	bool state_is_not(enum tbf_fsm_states rhs) const;
 	bool dl_ass_state_is(enum tbf_dl_ass_fsm_states rhs) const;
@@ -214,8 +213,6 @@
 	/* attempt to make things a bit more fair */
 	void rotate_in_list();
 
-	int alloc_algorithm(const struct alloc_resources_req *req);
-
 	enum gprs_rlcmac_tbf_direction direction;
 	struct gprs_rlcmac_trx *trx;
 	struct gprs_rlcmac_pdch *control_ts; /* timeslot control messages and polling */
diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp
index 4af9ae6..3ffafbf 100644
--- a/src/tbf_dl.cpp
+++ b/src/tbf_dl.cpp
@@ -106,10 +106,9 @@
 	return 0;
 }
 
-struct gprs_rlcmac_dl_tbf *dl_tbf_alloc(struct gprs_rlcmac_bts *bts, struct GprsMs *ms, int8_t use_trx, bool single_slot)
+struct gprs_rlcmac_dl_tbf *dl_tbf_alloc(struct gprs_rlcmac_bts *bts, struct GprsMs *ms)
 {
 	struct gprs_rlcmac_dl_tbf *tbf;
-	int rc;
 
 	OSMO_ASSERT(ms != NULL);
 
@@ -124,15 +123,7 @@
 	talloc_set_destructor(tbf, dl_tbf_dtor);
 	new (tbf) gprs_rlcmac_dl_tbf(bts, ms);
 
-	rc = tbf->setup(use_trx, single_slot);
-	/* if no resource */
-	if (rc < 0) {
-		talloc_free(tbf);
-		return NULL;
-	}
-
 	if (tbf->is_egprs_enabled()) {
-		tbf->set_window_size();
 		tbf->m_dl_egprs_ctrs = rate_ctr_group_alloc(tbf,
 							&tbf_dl_egprs_ctrg_desc,
 							tbf->m_ctrs->idx);
@@ -151,8 +142,6 @@
 			return NULL;
 		}
 	}
-
-	llist_add(tbf_trx_list((struct gprs_rlcmac_tbf *)tbf), &tbf->trx->dl_tbfs);
 	bts_do_rate_ctr_inc(tbf->bts, CTR_TBF_DL_ALLOCATED);
 
 	return tbf;
@@ -422,6 +411,11 @@
 {
 	uint8_t ts;
 
+	if (this->trx)
+		llist_del(&this->m_trx_list.list);
+
+	llist_add(&this->m_trx_list.list, &res->trx->dl_tbfs);
+
 	this->trx = res->trx;
 	this->upgrade_to_multislot = res->upgrade_to_multislot;
 
@@ -438,6 +432,23 @@
 		this->pdch[pdch->ts_no] = pdch;
 		pdch->attach_tbf(this);
 	}
+
+	/* assign initial control ts */
+	tbf_assign_control_ts(this);
+
+	LOGPTBF(this, LOGL_INFO,
+		"Allocated: trx = %d, ul_slots = %02x, dl_slots = %02x\n",
+		this->trx->trx_no, ul_slots(), dl_slots());
+
+	if (tbf_is_egprs_enabled(this))
+		this->set_window_size();
+
+	tbf_update_state_fsm_name(this);
+}
+
+void dl_tbf_apply_allocated_resources(struct gprs_rlcmac_dl_tbf *dl_tbf, const struct alloc_resources_res *res)
+{
+	dl_tbf->apply_allocated_resources(res);
 }
 
 /* old_tbf (UL TBF or DL TBF) will send a Pkt Dl Ass on PACCH to assign tbf.
@@ -483,6 +494,7 @@
 	struct gprs_rlcmac_tbf *tbf = dl_tbf_as_tbf(dl_tbf);
 	struct gprs_rlcmac_trx *trx = tbf_get_trx(dl_tbf);
 	struct gprs_rlcmac_bts *bts = trx->bts;
+	struct GprsMs *ms = tbf->ms();
 
 	LOGPTBFDL(dl_tbf, LOGL_DEBUG, "Upgrade to multislot\n");
 
@@ -490,12 +502,14 @@
 
 	const struct alloc_resources_req req = {
 		.bts = bts,
-		.ms = tbf->ms(),
+		.ms = ms,
 		.direction = tbf_direction(tbf),
 		.single = false,
 		.use_trx = -1,
 	};
-	rc = dl_tbf->alloc_algorithm(&req);
+	struct alloc_resources_res res = {};
+
+	rc = the_pcu->alloc_algorithm(&req, &res);
 	/* if no resource */
 	if (rc < 0) {
 		LOGPTBFDL(dl_tbf, LOGL_ERROR, "No resources allocated during upgrade to multislot!\n");
@@ -503,9 +517,18 @@
 		return rc;
 	}
 
-	if (tbf_is_egprs_enabled(tbf))
-		dl_tbf->set_window_size();
-	tbf_update_state_fsm_name(tbf);
+	/* Update MS, really allocate the resources */
+	if (res.reserved_ul_slots != ms_reserved_ul_slots(ms) ||
+	    res.reserved_dl_slots != ms_reserved_dl_slots(ms)) {
+		/* The reserved slots have changed, update the MS */
+		ms_set_reserved_slots(ms, res.trx, res.reserved_ul_slots, res.reserved_dl_slots);
+	}
+	ms_set_first_common_ts(ms, res.first_common_ts);
+
+	/* Apply allocated resources to TBF: */
+	dl_tbf_apply_allocated_resources(dl_tbf, &res);
+
+	/* Note: No need to call ms_attach_tbf(), tbf is already attached to the MS */
 
 	/* Now trigger the assignment using the pre-existing TBF: */
 	dl_tbf_trigger_ass_on_pacch(dl_tbf, tbf);
diff --git a/src/tbf_dl.h b/src/tbf_dl.h
index 90dfb12..6718c13 100644
--- a/src/tbf_dl.h
+++ b/src/tbf_dl.h
@@ -138,8 +138,7 @@
 #endif
 struct gprs_rlcmac_bts;
 
-struct gprs_rlcmac_dl_tbf *dl_tbf_alloc(struct gprs_rlcmac_bts *bts, struct GprsMs *ms,
-					int8_t use_trx, bool single_slot);
+struct gprs_rlcmac_dl_tbf *dl_tbf_alloc(struct gprs_rlcmac_bts *bts, struct GprsMs *ms);
 
 struct gprs_rlcmac_dl_tbf *tbf_as_dl_tbf(struct gprs_rlcmac_tbf *tbf);
 const struct gprs_rlcmac_dl_tbf *tbf_as_dl_tbf_const(const struct gprs_rlcmac_tbf *tbf);
@@ -150,6 +149,7 @@
 		  const uint8_t egprs_ms_class, const uint16_t delay_csec,
 		  const uint8_t *data, const uint16_t len);
 
+void dl_tbf_apply_allocated_resources(struct gprs_rlcmac_dl_tbf *dl_tbf, const struct alloc_resources_res *res);
 void dl_tbf_trigger_ass_on_pacch(struct gprs_rlcmac_dl_tbf *tbf, struct gprs_rlcmac_tbf *old_tbf);
 void dl_tbf_trigger_ass_on_pch(struct gprs_rlcmac_dl_tbf *tbf);
 void dl_tbf_request_dl_ack(struct gprs_rlcmac_dl_tbf *tbf);
diff --git a/src/tbf_ul.cpp b/src/tbf_ul.cpp
index 47347f9..9a139ba 100644
--- a/src/tbf_ul.cpp
+++ b/src/tbf_ul.cpp
@@ -105,10 +105,9 @@
 }
 
 /* Generic function to alloc a UL TBF, later configured to be assigned either over CCCH or PACCH */
-struct gprs_rlcmac_ul_tbf *ul_tbf_alloc(struct gprs_rlcmac_bts *bts, struct GprsMs *ms, int8_t use_trx, bool single_slot)
+struct gprs_rlcmac_ul_tbf *ul_tbf_alloc(struct gprs_rlcmac_bts *bts, struct GprsMs *ms)
 {
 	struct gprs_rlcmac_ul_tbf *tbf;
-	int rc;
 
 	OSMO_ASSERT(ms != NULL);
 
@@ -121,53 +120,11 @@
 	talloc_set_destructor(tbf, ul_tbf_dtor);
 	new (tbf) gprs_rlcmac_ul_tbf(bts, ms);
 
-	rc = tbf->setup(use_trx, single_slot);
-
-	/* if no resource */
-	if (rc < 0) {
-		talloc_free(tbf);
-		return NULL;
-	}
-
-	if (tbf->is_egprs_enabled())
-		tbf->set_window_size();
-
-	llist_add_tail(tbf_trx_list(tbf), &tbf->trx->ul_tbfs);
 	bts_do_rate_ctr_inc(tbf->bts, CTR_TBF_UL_ALLOCATED);
 
 	return tbf;
 }
 
-/* Create a temporary dummy TBF to Tx a ImmAssReject if allocating a new one during
- * packet resource Request failed. This is similar as tbf_alloc_ul() but without
- * calling tbf->setup() (in charge of TFI/USF allocation), and reusing resources
- * from Packet Resource Request we received. See TS 44.060 sec 7.1.3.2.1  */
-struct gprs_rlcmac_ul_tbf *ul_tbf_alloc_rejected(struct gprs_rlcmac_bts *bts, struct GprsMs *ms,
-						 struct gprs_rlcmac_pdch *pdch)
-{
-	struct gprs_rlcmac_ul_tbf *ul_tbf = NULL;
-	struct gprs_rlcmac_trx *trx = pdch->trx;
-	OSMO_ASSERT(ms);
-
-	ul_tbf = talloc(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);
-	if (!ul_tbf)
-		return ul_tbf;
-	talloc_set_destructor(ul_tbf, ul_tbf_dtor);
-	new (ul_tbf) gprs_rlcmac_ul_tbf(bts, ms);
-
-	ul_tbf->trx = trx;
-	/* The only one TS is the common, control TS */
-	ms_set_first_common_ts(ms, pdch);
-	tbf_assign_control_ts(ul_tbf);
-	tbf_update_state_fsm_name(ul_tbf);
-
-	ms_attach_tbf(ms, ul_tbf);
-	llist_add(tbf_trx_list(ul_tbf), &trx->ul_tbfs);
-	bts_do_rate_ctr_inc(ul_tbf->bts, CTR_TBF_UL_ALLOCATED);
-
-	return ul_tbf;
-}
-
 gprs_rlcmac_ul_tbf::gprs_rlcmac_ul_tbf(struct gprs_rlcmac_bts *bts_, GprsMs *ms) :
 	gprs_rlcmac_tbf(bts_, ms, GPRS_RLCMAC_UL_TBF),
 	m_rx_counter(0),
@@ -709,6 +666,11 @@
 {
 	uint8_t ts;
 
+	if (this->trx)
+		llist_del(&this->m_trx_list.list);
+
+	llist_add(&this->m_trx_list.list, &res->trx->ul_tbfs);
+
 	this->trx = res->trx;
 	this->upgrade_to_multislot = res->upgrade_to_multislot;
 
@@ -727,6 +689,27 @@
 		this->pdch[pdch->ts_no] = pdch;
 		pdch->attach_tbf(this);
 	}
+
+	/* assign initial control ts */
+	tbf_assign_control_ts(this);
+
+	/* res.ass_slots_mask == 0 -> special case for Rejected UL TBFs,
+	 * see ms_new_ul_tbf_rejected_pacch() */
+	if (res->ass_slots_mask != 0) {
+		LOGPTBF(this, LOGL_INFO,
+			"Allocated: trx = %d, ul_slots = %02x, dl_slots = %02x\n",
+			this->trx->trx_no, ul_slots(), dl_slots());
+
+		if (tbf_is_egprs_enabled(this))
+			this->set_window_size();
+	}
+
+	tbf_update_state_fsm_name(this);
+}
+
+void ul_tbf_apply_allocated_resources(struct gprs_rlcmac_ul_tbf *ul_tbf, const struct alloc_resources_res *res)
+{
+	ul_tbf->apply_allocated_resources(res);
 }
 
 void gprs_rlcmac_ul_tbf::usf_timeout()
diff --git a/src/tbf_ul.h b/src/tbf_ul.h
index 5ef8465..14884ab 100644
--- a/src/tbf_ul.h
+++ b/src/tbf_ul.h
@@ -133,14 +133,13 @@
 #ifdef __cplusplus
 extern "C" {
 #endif
-struct gprs_rlcmac_ul_tbf *ul_tbf_alloc(struct gprs_rlcmac_bts *bts, struct GprsMs *ms, int8_t use_trx, bool single_slot);
-struct gprs_rlcmac_ul_tbf *ul_tbf_alloc_rejected(struct gprs_rlcmac_bts *bts, struct GprsMs *ms,
-						 struct gprs_rlcmac_pdch *pdch);
+struct gprs_rlcmac_ul_tbf *ul_tbf_alloc(struct gprs_rlcmac_bts *bts, struct GprsMs *ms);
 void update_tbf_ta(struct gprs_rlcmac_ul_tbf *tbf, int8_t ta_delta);
 void set_tbf_ta(struct gprs_rlcmac_ul_tbf *tbf, uint8_t ta);
 struct gprs_rlcmac_ul_tbf *tbf_as_ul_tbf(struct gprs_rlcmac_tbf *tbf);
 const struct gprs_rlcmac_ul_tbf *tbf_as_ul_tbf_const(const struct gprs_rlcmac_tbf *tbf);
 void tbf_usf_timeout(struct gprs_rlcmac_ul_tbf *tbf);
+void ul_tbf_apply_allocated_resources(struct gprs_rlcmac_ul_tbf *ul_tbf, const struct alloc_resources_res *res);
 void ul_tbf_contention_resolution_start(struct gprs_rlcmac_ul_tbf *tbf);
 void ul_tbf_contention_resolution_success(struct gprs_rlcmac_ul_tbf *tbf);
 bool ul_tbf_contention_resolution_done(const struct gprs_rlcmac_ul_tbf *tbf);