aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2015-07-10 19:52:37 +0200
committerJacob Erlbeck <jerlbeck@sysmocom.de>2015-07-16 10:25:14 +0200
commit3a10dbd56428cf0e79b738f62748509bbd04aa68 (patch)
tree9f5e96fc468f62c0a1f68547b9a249f757c2aa64
parente0853cdf42e60acd7759acd4869c84756eb1fa27 (diff)
tbf: Put the TFI->TBF mapping into the PDCH objects
Currently the TBFs are registered in a TFI indexed array within the TRX objects. TBFs can be searched globally by TFI and TRX number. This conflicts with the use of the same TFI for different TBF on different PDCH. This use case requires the specification of the PDCH as additional search dimension. This commit moves the TFI index TBF arrays into the PDCH objects. The related methods are updated accordingly. Ticket: #1793 Sponsored-by: On-Waves ehf
-rw-r--r--src/bts.cpp130
-rw-r--r--src/bts.h10
-rw-r--r--src/gprs_rlcmac_ts_alloc.cpp2
-rw-r--r--src/tbf.cpp17
-rw-r--r--tests/alloc/AllocTest.cpp14
-rw-r--r--tests/tbf/TbfTest.cpp4
-rw-r--r--tests/tbf/TbfTest.err14
7 files changed, 98 insertions, 93 deletions
diff --git a/src/bts.cpp b/src/bts.cpp
index 712954e..412e0c0 100644
--- a/src/bts.cpp
+++ b/src/bts.cpp
@@ -257,48 +257,35 @@ gprs_rlcmac_ul_tbf *BTS::ul_tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts)
}
/* lookup downlink TBF Entity (by TFI) */
-gprs_rlcmac_dl_tbf *BTS::dl_tbf_by_tfi(uint8_t tfi, uint8_t trx)
+gprs_rlcmac_dl_tbf *BTS::dl_tbf_by_tfi(uint8_t tfi, uint8_t trx, uint8_t ts)
{
- return static_cast<gprs_rlcmac_dl_tbf *>(tbf_by_tfi(tfi, trx, GPRS_RLCMAC_DL_TBF));
-}
+ if (trx >= 8 || ts >= 8)
+ return NULL;
-/* lookup uplink TBF Entity (by TFI) */
-gprs_rlcmac_ul_tbf *BTS::ul_tbf_by_tfi(uint8_t tfi, uint8_t trx)
-{
- return static_cast<gprs_rlcmac_ul_tbf *>(tbf_by_tfi(tfi, trx, GPRS_RLCMAC_UL_TBF));
+ return m_bts.trx[trx].pdch[ts].dl_tbf_by_tfi(tfi);
}
-/* lookup TBF Entity (by TFI) */
-gprs_rlcmac_tbf *BTS::tbf_by_tfi(uint8_t tfi, uint8_t trx,
- enum gprs_rlcmac_tbf_direction dir)
+/* lookup uplink TBF Entity (by TFI) */
+gprs_rlcmac_ul_tbf *BTS::ul_tbf_by_tfi(uint8_t tfi, uint8_t trx, uint8_t ts)
{
- struct gprs_rlcmac_tbf *tbf;
-
- if (tfi >= 32 || trx >= 8)
- return NULL;
-
- if (dir == GPRS_RLCMAC_UL_TBF)
- tbf = m_bts.trx[trx].ul_tbf[tfi];
- else
- tbf = m_bts.trx[trx].dl_tbf[tfi];
- if (!tbf)
+ if (trx >= 8 || ts >= 8)
return NULL;
- if (tbf->state_is_not(GPRS_RLCMAC_RELEASING)) {
- return tbf;
- }
-
- return NULL;
+ return m_bts.trx[trx].pdch[ts].ul_tbf_by_tfi(tfi);
}
-/* FIXME: spread resources over multiple TRX. Also add option to use same
- * TRX in case of existing TBF for TLLI in the other direction. */
-/* search for free TFI and return TFI, TRX */
+/*
+ * Search for free TFI and return TFI, TRX.
+ * This method returns the first TFI that is currently not used in any PDCH of
+ * a TRX. The first TRX that contains such an TFI is returned. Negative values
+ * indicate errors.
+ */
int BTS::tfi_find_free(enum gprs_rlcmac_tbf_direction dir,
uint8_t *_trx, int8_t use_trx)
{
struct gprs_rlcmac_pdch *pdch;
- struct gprs_rlcmac_tbf **tbfp;
+ uint32_t free_tfis;
+ bool has_pdch = false;
uint8_t trx_from, trx_to, trx, ts, tfi;
if (use_trx >= 0 && use_trx < 8)
@@ -308,42 +295,50 @@ int BTS::tfi_find_free(enum gprs_rlcmac_tbf_direction dir,
trx_to = 7;
}
- /* on TRX find first enabled TS */
+ /* find a TFI that is unused on all PDCH */
for (trx = trx_from; trx <= trx_to; trx++) {
+ bool trx_has_pdch = false;
+
+ free_tfis = 0xffffffff;
+
for (ts = 0; ts < 8; ts++) {
pdch = &m_bts.trx[trx].pdch[ts];
if (!pdch->is_enabled())
continue;
- break;
+ free_tfis &= ~pdch->assigned_tfi(dir);
+ trx_has_pdch = true;
+ has_pdch = true;
}
- if (ts < 8)
+ if (trx_has_pdch && free_tfis)
break;
+
+ free_tfis = 0;
}
- if (trx > trx_to) {
+ if (!has_pdch) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH available.\n");
return -EINVAL;
}
+ if (!free_tfis) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "No TFI available.\n");
+ return -EBUSY;
+ }
- LOGP(DRLCMAC, LOGL_DEBUG, "Searching for first unallocated TFI: "
- "TRX=%d first TS=%d\n", trx, ts);
- if (dir == GPRS_RLCMAC_UL_TBF)
- tbfp = m_bts.trx[trx].ul_tbf;
- else
- tbfp = m_bts.trx[trx].dl_tbf;
+
+ LOGP(DRLCMAC, LOGL_DEBUG,
+ "Searching for first unallocated TFI: TRX=%d\n", trx);
+
+ /* find the first */
for (tfi = 0; tfi < 32; tfi++) {
- if (!tbfp[tfi])
+ if (free_tfis & 1 << tfi)
break;
}
- if (tfi < 32) {
- LOGP(DRLCMAC, LOGL_DEBUG, " Found TFI=%d.\n", tfi);
- *_trx = trx;
- return tfi;
- }
- LOGP(DRLCMAC, LOGL_NOTICE, "No TFI available.\n");
+ OSMO_ASSERT(tfi < 32);
- return -1;
+ LOGP(DRLCMAC, LOGL_DEBUG, " Found TFI=%d.\n", tfi);
+ *_trx = trx;
+ return tfi;
}
int BTS::rcv_imm_ass_cnf(const uint8_t *data, uint32_t fn)
@@ -693,7 +688,7 @@ int gprs_rlcmac_pdch::rcv_data_block_acknowledged(uint8_t *data, uint8_t len,
}
/* find TBF inst from given TFI */
- tbf = bts()->ul_tbf_by_tfi(rh->tfi, trx_no());
+ tbf = ul_tbf_by_tfi(rh->tfi);
if (!tbf) {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA unknown TFI=%d\n",
rh->tfi);
@@ -990,7 +985,7 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
if (request->ID.u.Global_TFI.UnionType) {
struct gprs_rlcmac_dl_tbf *dl_tbf;
int8_t tfi = request->ID.u.Global_TFI.u.DOWNLINK_TFI;
- dl_tbf = bts()->dl_tbf_by_tfi(tfi, trx_no());
+ dl_tbf = bts()->dl_tbf_by_tfi(tfi, trx_no(), ts_no);
if (!dl_tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESSOURCE REQ unknown downlink TFI=%d\n", tfi);
return;
@@ -1001,7 +996,7 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
} else {
struct gprs_rlcmac_ul_tbf *ul_tbf;
int8_t tfi = request->ID.u.Global_TFI.u.UPLINK_TFI;
- ul_tbf = bts()->ul_tbf_by_tfi(tfi, trx_no());
+ ul_tbf = bts()->ul_tbf_by_tfi(tfi, trx_no(), ts_no);
if (!ul_tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESSOURCE REQ unknown uplink TFI=%d\n", tfi);
return;
@@ -1120,24 +1115,54 @@ gprs_rlcmac_tbf *gprs_rlcmac_pdch::tbf_from_list_by_tfi(struct llist_head *tbf_l
gprs_rlcmac_ul_tbf *gprs_rlcmac_pdch::ul_tbf_by_tfi(uint8_t tfi)
{
- return static_cast<gprs_rlcmac_ul_tbf *>(tbf_from_list_by_tfi(&bts_data()->ul_tbfs, tfi, GPRS_RLCMAC_UL_TBF));
+ return static_cast<gprs_rlcmac_ul_tbf *>(
+ tbf_by_tfi(tfi, GPRS_RLCMAC_UL_TBF));
}
gprs_rlcmac_dl_tbf *gprs_rlcmac_pdch::dl_tbf_by_tfi(uint8_t tfi)
{
- return static_cast<gprs_rlcmac_dl_tbf *>(tbf_from_list_by_tfi(&bts_data()->dl_tbfs, tfi, GPRS_RLCMAC_DL_TBF));
+ return static_cast<gprs_rlcmac_dl_tbf *>(
+ tbf_by_tfi(tfi, GPRS_RLCMAC_DL_TBF));
+}
+
+/* lookup TBF Entity (by TFI) */
+gprs_rlcmac_tbf *gprs_rlcmac_pdch::tbf_by_tfi(uint8_t tfi,
+ enum gprs_rlcmac_tbf_direction dir)
+{
+ struct gprs_rlcmac_tbf *tbf;
+
+ if (tfi >= 32)
+ return NULL;
+
+ tbf = m_tbfs[dir][tfi];
+
+ if (!tbf)
+ return NULL;
+
+ if (tbf->state_is_not(GPRS_RLCMAC_RELEASING)) {
+ return tbf;
+ }
+
+ return NULL;
}
void gprs_rlcmac_pdch::attach_tbf(gprs_rlcmac_tbf *tbf)
{
gprs_rlcmac_ul_tbf *ul_tbf;
+ if (m_tbfs[tbf->direction][tbf->tfi()])
+ LOGP(DRLCMAC, LOGL_ERROR, "PDCH(TS %d, TRX %d): "
+ "%s has not been detached, overwriting it\n",
+ ts_no, trx_no(),
+ m_tbfs[tbf->direction][tbf->tfi()]->name());
+
m_num_tbfs[tbf->direction] += 1;
if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
ul_tbf = static_cast<gprs_rlcmac_ul_tbf *>(tbf);
m_assigned_usf |= 1 << ul_tbf->m_usf[ts_no];
}
m_assigned_tfi[tbf->direction] |= 1UL << tbf->tfi();
+ m_tbfs[tbf->direction][tbf->tfi()] = tbf;
LOGP(DRLCMAC, LOGL_INFO, "PDCH(TS %d, TRX %d): Attaching %s, %d TBFs, "
"USFs = %02x, TFIs = %08x.\n",
@@ -1157,6 +1182,7 @@ void gprs_rlcmac_pdch::detach_tbf(gprs_rlcmac_tbf *tbf)
m_assigned_usf &= ~(1 << ul_tbf->m_usf[ts_no]);
}
m_assigned_tfi[tbf->direction] &= ~(1UL << tbf->tfi());
+ m_tbfs[tbf->direction][tbf->tfi()] = NULL;
LOGP(DRLCMAC, LOGL_INFO, "PDCH(TS %d, TRX %d): Detaching %s, %d TBFs, "
"USFs = %02x, TFIs = %08x.\n",
diff --git a/src/bts.h b/src/bts.h
index 8784f4d..ebfcd5e 100644
--- a/src/bts.h
+++ b/src/bts.h
@@ -104,20 +104,21 @@ private:
void rcv_measurement_report(Packet_Measurement_Report_t *t, uint32_t fn);
gprs_rlcmac_tbf *tbf_from_list_by_tfi(struct llist_head *tbf_list, uint8_t tfi,
enum gprs_rlcmac_tbf_direction dir);
+ gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi,
+ enum gprs_rlcmac_tbf_direction dir);
#endif
uint8_t m_num_tbfs[2];
uint8_t m_num_reserved[2];
uint8_t m_assigned_usf; /* bit set */
uint32_t m_assigned_tfi[2]; /* bit set */
+ struct gprs_rlcmac_tbf *m_tbfs[2][32];
};
struct gprs_rlcmac_trx {
void *fl1h;
uint16_t arfcn;
struct gprs_rlcmac_pdch pdch[8];
- struct gprs_rlcmac_tbf *ul_tbf[32]; /* array of UL TBF, by UL TFI */
- struct gprs_rlcmac_tbf *dl_tbf[32]; /* array of DL TBF, by DL TFI */
/* back pointers */
struct BTS *bts;
@@ -242,8 +243,8 @@ public:
gprs_rlcmac_dl_tbf *dl_tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts);
gprs_rlcmac_ul_tbf *ul_tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts);
- gprs_rlcmac_dl_tbf *dl_tbf_by_tfi(uint8_t tfi, uint8_t trx);
- gprs_rlcmac_ul_tbf *ul_tbf_by_tfi(uint8_t tfi, uint8_t trx);
+ gprs_rlcmac_dl_tbf *dl_tbf_by_tfi(uint8_t tfi, uint8_t trx, uint8_t ts);
+ gprs_rlcmac_ul_tbf *ul_tbf_by_tfi(uint8_t tfi, uint8_t trx, uint8_t ts);
int tfi_find_free(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, int8_t use_trx);
@@ -293,7 +294,6 @@ private:
PollController m_pollController;
SBAController m_sba;
struct rate_ctr_group *m_ratectrs;
- gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, uint8_t trx, enum gprs_rlcmac_tbf_direction dir);
GprsMsStorage m_ms_store;
diff --git a/src/gprs_rlcmac_ts_alloc.cpp b/src/gprs_rlcmac_ts_alloc.cpp
index 55c3ea6..b6f5886 100644
--- a/src/gprs_rlcmac_ts_alloc.cpp
+++ b/src/gprs_rlcmac_ts_alloc.cpp
@@ -300,7 +300,6 @@ static void assign_uplink_tbf_usf(
int tfi, int8_t usf)
{
tbf->m_tfi = tfi;
- tbf->trx->ul_tbf[tbf->tfi()] = tbf;
tbf->m_usf[pdch->ts_no] = usf;
attach_tbf_to_pdch(pdch, tbf);
}
@@ -311,7 +310,6 @@ static void assign_dlink_tbf(
int tfi)
{
tbf->m_tfi = tfi;
- tbf->trx->dl_tbf[tbf->tfi()] = tbf;
attach_tbf_to_pdch(pdch, tbf);
}
diff --git a/src/tbf.cpp b/src/tbf.cpp
index 70483e3..e3a441a 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -201,11 +201,6 @@ static void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf)
{
int ts;
- if (tbf->direction == GPRS_RLCMAC_UL_TBF)
- tbf->trx->ul_tbf[tbf->tfi()] = NULL;
- else
- tbf->trx->dl_tbf[tbf->tfi()] = NULL;
-
for (ts = 0; ts < 8; ts++) {
if (!tbf->pdch[ts])
continue;
@@ -800,16 +795,8 @@ struct msgb *gprs_rlcmac_tbf::create_ul_ass(uint32_t fn)
void gprs_rlcmac_tbf::free_all(struct gprs_rlcmac_trx *trx)
{
- for (uint8_t tfi = 0; tfi < 32; tfi++) {
- struct gprs_rlcmac_tbf *tbf;
-
- tbf = trx->ul_tbf[tfi];
- if (tbf)
- tbf_free(tbf);
- tbf = trx->dl_tbf[tfi];
- if (tbf)
- tbf_free(tbf);
- }
+ for (uint8_t ts = 0; ts < 8; ts++)
+ free_all(&trx->pdch[ts]);
}
void gprs_rlcmac_tbf::free_all(struct gprs_rlcmac_pdch *pdch)
diff --git a/tests/alloc/AllocTest.cpp b/tests/alloc/AllocTest.cpp
index e419cd2..7bc865d 100644
--- a/tests/alloc/AllocTest.cpp
+++ b/tests/alloc/AllocTest.cpp
@@ -82,23 +82,17 @@ static void check_tfi_usage(BTS *the_bts)
if (tbf->direction == GPRS_RLCMAC_DL_TBF) {
OSMO_ASSERT(pdch->dl_tbf_by_tfi(
tbf->tfi()) == tbf);
- /* This assertion cannot hold with the
- * current API and shared TFI */
-#if 0
OSMO_ASSERT(the_bts->dl_tbf_by_tfi(
tbf->tfi(),
- tbf->trx->trx_no) == tbf);
-#endif
+ tbf->trx->trx_no,
+ pdch_no) == tbf);
} else {
OSMO_ASSERT(pdch->ul_tbf_by_tfi(
tbf->tfi()) == tbf);
- /* This assertion cannot hold with the
- * current API and shared TFI */
-#if 0
OSMO_ASSERT(the_bts->ul_tbf_by_tfi(
tbf->tfi(),
- tbf->trx->trx_no) == tbf);
-#endif
+ tbf->trx->trx_no,
+ pdch_no) == tbf);
}
*tbf_var = tbf;
OSMO_ASSERT(pdch->assigned_tfi(tbf->direction) &
diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp
index 159c859..39f57ad 100644
--- a/tests/tbf/TbfTest.cpp
+++ b/tests/tbf/TbfTest.cpp
@@ -526,7 +526,7 @@ static void test_tbf_single_phase()
the_bts.rcv_rach(0x03, fn, qta);
- ul_tbf = the_bts.ul_tbf_by_tfi(tfi, trx_no);
+ ul_tbf = the_bts.ul_tbf_by_tfi(tfi, trx_no, ts_no);
OSMO_ASSERT(ul_tbf != NULL);
fprintf(stderr, "Got '%s', TA=%d\n",
@@ -605,7 +605,7 @@ static void test_tbf_two_phase()
pdch->rcv_block(&buf[0], num_bytes, 2654270, &meas);
/* check the TBF */
- ul_tbf = the_bts.ul_tbf_by_tfi(tfi, trx_no);
+ ul_tbf = the_bts.ul_tbf_by_tfi(tfi, trx_no, ts_no);
OSMO_ASSERT(ul_tbf != NULL);
fprintf(stderr, "Got '%s', TA=%d, CS=%d\n",
diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err
index 72c3851..ee57d63 100644
--- a/tests/tbf/TbfTest.err
+++ b/tests/tbf/TbfTest.err
@@ -35,7 +35,7 @@ Modifying MS object, TLLI: 0x00000000 -> 0x00002342, already confirmed partly
The MS object cannot fully confirm an unexpected TLLI: 0x00004232, partly confirmed
Modifying MS object, TLLI: 0x00002342 -> 0x00004232, already confirmed partly
Modifying MS object, TLLI = 0x00004232, TA 4 -> 6
-Searching for first unallocated TFI: TRX=0 first TS=4
+Searching for first unallocated TFI: TRX=0
Found TFI=0.
********** TBF starts here **********
Allocating DL TBF: MS_CLASS=45
@@ -110,7 +110,7 @@ PDCH(TS 4, TRX 0): Detaching TBF(TFI=1 TLLI=0xffeeddcc DIR=DL STATE=ASSIGN), 0 T
Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=1 TLLI=0xffeeddcc DIR=DL STATE=ASSIGN)
********** TBF ends here **********
Destroying MS object, TLLI = 0xffeeddcc
-Searching for first unallocated TFI: TRX=0 first TS=4
+Searching for first unallocated TFI: TRX=0
Found TFI=0.
********** TBF starts here **********
Allocating DL TBF: MS_CLASS=45
@@ -185,7 +185,7 @@ TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=WAIT RELEASE) free
PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=WAIT RELEASE), 0 TBFs, USFs = 00, TFIs = 00000000.
********** TBF ends here **********
Destroying MS object, TLLI = 0xffeeddcc
-Searching for first unallocated TFI: TRX=0 first TS=4
+Searching for first unallocated TFI: TRX=0
Found TFI=0.
********** TBF starts here **********
Allocating DL TBF: MS_CLASS=45
@@ -414,7 +414,7 @@ PDCH(TS 4, TRX 0): Detaching TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE
Detaching TBF from MS object, TLLI = 0xffeeddcc, TBF = TBF(TFI=0 TLLI=0xffeeddcc DIR=DL STATE=WAIT RELEASE)
Destroying MS object, TLLI = 0xffeeddcc
********** TBF ends here **********
-Searching for first unallocated TFI: TRX=0 first TS=4
+Searching for first unallocated TFI: TRX=0
Found TFI=0.
********** TBF starts here **********
Allocating DL TBF: MS_CLASS=45
@@ -434,7 +434,7 @@ PDCH(TS 4, TRX 0): Attaching TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL), 1 TBF
Attaching TBF to MS object, TLLI = 0x00000000, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL)
Allocated TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL): trx = 0, ul_slots = 10, dl_slots = 10
TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL) changes state from NULL to FLOW
-Searching for first unallocated TFI: TRX=0 first TS=4
+Searching for first unallocated TFI: TRX=0
Found TFI=1.
********** TBF starts here **********
Allocating DL TBF: MS_CLASS=45
@@ -1359,7 +1359,7 @@ data block: 07 01 04 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03
- Scheduling Ack/Nack polling, because is was requested explicitly (e.g. first final block sent).
Polling cannot be sheduled in this TS 7, waiting for TS 4
MSG = 07 01 04 4d 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03
-Searching for first unallocated TFI: TRX=0 first TS=7
+Searching for first unallocated TFI: TRX=0
Found TFI=0.
MS requests UL TBF on RACH, so we provide one:
********** TBF starts here **********
@@ -1412,7 +1412,7 @@ MS requests single block allocation
RX: [PCU <- BTS] RACH qbit-ta=31 ra=0x73, Fn=2654167 (17,25,9), SBFn=2654270
TX: Immediate Assignment Uplink (AGCH)
Sending data request: trx=0 ts=0 sapi=2 arfcn=0 fn=0 block=0 data=2d 06 3f 10 0f 00 00 73 8b 29 07 00 c0 0c 5a 43 2b 2b 2b 2b 2b 2b 2b
-Searching for first unallocated TFI: TRX=0 first TS=7
+Searching for first unallocated TFI: TRX=0
Found TFI=0.
+++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++
------------------------- RX : Uplink Control Block -------------------------