aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2012-07-13 14:46:03 +0200
committerAndreas Eversberg <jolly@eversberg.eu>2012-07-13 14:46:03 +0200
commitb0c7ea72c8157f1b8124bbe105aa05c46a77a005 (patch)
treedda9d26a9e6a8b12022a24bc3ae090b091cb2b97
parente266bd48aca6f5b7831eb7c44e4773e9884d4c56 (diff)
Changed data structures for TBF and PDCH instances, to allow multislot
The new data structure is required to define slot/TFI assigment for MS with multislot capability. Now there are two lists for TBFs: uplink and downlink. It is possible to have different TBFs with same TFI in the same direction, as long as they are assigned on different timeslots. See tbf.txt for description. Note: This does not implement any multislot support. It defines the new data structure. Currently only the first slot is assigned.
-rw-r--r--src/gprs_bssgp_pcu.cpp30
-rw-r--r--src/gprs_rlcmac.cpp303
-rw-r--r--src/gprs_rlcmac.h55
-rw-r--r--src/gprs_rlcmac_data.cpp103
-rw-r--r--src/gprs_rlcmac_sched.cpp58
-rw-r--r--src/pcu_l1_if.cpp43
-rw-r--r--src/sysmo_sock.cpp5
-rw-r--r--src/tbf.txt30
8 files changed, 411 insertions, 216 deletions
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp
index d1ef046e..c4d70afd 100644
--- a/src/gprs_bssgp_pcu.cpp
+++ b/src/gprs_bssgp_pcu.cpp
@@ -31,10 +31,9 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
{
struct bssgp_ud_hdr *budh;
- int tfi;
+ int8_t tfi; /* must be signed */
uint32_t tlli;
int i, j;
- uint8_t trx, ts;
uint8_t *data;
uint16_t len;
struct gprs_rlcmac_tbf *tbf;
@@ -101,19 +100,36 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
msgb_enqueue(&tbf->llc_queue, llc_msg);
}
} else {
- // Create new TBF
- tfi = tfi_alloc(&trx, &ts);
+ uint8_t trx, ts, use_trx, first_ts;
+
+ /* check for uplink data, so we copy our informations */
+ if ((tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF))) {
+ use_trx = tbf->trx;
+ first_ts = tbf->first_ts;
+ } else {
+ use_trx = -1;
+ first_ts = -1;
+ }
+
+ // Create new TBF (any TRX)
+ tfi = tfi_alloc(GPRS_RLCMAC_DL_TBF, &trx, &ts, use_trx, first_ts);
if (tfi < 0) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
/* FIXME: send reject */
return -EBUSY;
}
- tbf = tbf_alloc(tfi, trx, ts);
- tbf->direction = GPRS_RLCMAC_DL_TBF;
+ /* FIXME: set number of downlink slots according to multislot
+ * class */
+ tbf = tbf_alloc(GPRS_RLCMAC_DL_TBF, tfi, trx, ts, 1);
+ if (!tbf) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
+ /* FIXME: send reject */
+ return -EBUSY;
+ }
tbf->tlli = tlli;
tbf->tlli_valid = 1;
- LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [DOWNLINK] START TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli);
+ LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [DOWNLINK] START TFI: %d TLLI: 0x%08x \n", tbf->tfi, tbf->tlli);
/* new TBF, so put first frame */
memcpy(tbf->llc_frame, data, len);
diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp
index 9d2601c8..ab04aeab 100644
--- a/src/gprs_rlcmac.cpp
+++ b/src/gprs_rlcmac.cpp
@@ -22,18 +22,33 @@
#include <pcu_l1_if.h>
#include <gprs_rlcmac.h>
-LLIST_HEAD(gprs_rlcmac_tbfs);
+LLIST_HEAD(gprs_rlcmac_ul_tbfs);
+LLIST_HEAD(gprs_rlcmac_dl_tbfs);
void *rlcmac_tall_ctx;
-/* FIXME: spread ressources on multiple TRX */
-int tfi_alloc(uint8_t *_trx, uint8_t *_ts)
+/* FIXME: spread ressources 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 and first TS */
+int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, uint8_t *_ts,
+ uint8_t use_trx, uint8_t first_ts)
{
struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
struct gprs_rlcmac_pdch *pdch;
- uint8_t trx, ts, tfi;
+ struct gprs_rlcmac_tbf **tbfp;
+ uint8_t trx_from, trx_to, trx, ts, tfi;
+
+ if (use_trx >= 0 && use_trx < 8)
+ trx_from = trx_to = use_trx;
+ else {
+ trx_from = 0;
+ trx_to = 7;
+ }
+ if (first_ts < 0 || first_ts >= 8)
+ first_ts = 0;
- for (trx = 0; trx < 8; trx++) {
- for (ts = 0; ts < 8; ts++) {
+ /* on TRX find first enabled TS */
+ for (trx = trx_from; trx <= trx_to; trx++) {
+ for (ts = first_ts; ts < 8; ts++) {
pdch = &bts->trx[trx].pdch[ts];
if (!pdch->enable)
continue;
@@ -42,16 +57,20 @@ int tfi_alloc(uint8_t *_trx, uint8_t *_ts)
if (ts < 8)
break;
}
- if (trx == 8) {
+ if (trx > trx_to) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH available.\n");
return -EINVAL;
}
LOGP(DRLCMAC, LOGL_DEBUG, "Searching for first unallocated TFI: "
- "TRX=%d TS=%d\n", trx, ts);
+ "TRX=%d first TS=%d\n", trx, ts);
+ if (dir == GPRS_RLCMAC_UL_TBF)
+ tbfp = pdch->ul_tbf;
+ else
+ tbfp = pdch->dl_tbf;
for (tfi = 0; tfi < 32; tfi++) {
- if (!pdch->tbf[tfi])
+ if (!tbfp[tfi])
break;
}
@@ -66,126 +85,221 @@ int tfi_alloc(uint8_t *_trx, uint8_t *_ts)
return -1;
}
-int find_free_usf(uint8_t trx, uint8_t ts)
+static inline int8_t find_free_usf(struct gprs_rlcmac_pdch *pdch, uint8_t ts)
{
- struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
- struct gprs_rlcmac_pdch *pdch;
struct gprs_rlcmac_tbf *tbf;
uint8_t usf_map = 0;
uint8_t tfi, usf;
- if (trx >= 8 || ts >= 8)
- return -EINVAL;
- pdch = &bts->trx[trx].pdch[ts];
-
/* make map of used USF */
for (tfi = 0; tfi < 32; tfi++) {
- tbf = pdch->tbf[tfi];
+ tbf = pdch->ul_tbf[tfi];
if (!tbf)
continue;
- if (tbf->direction != GPRS_RLCMAC_UL_TBF)
- continue;
- usf_map |= (1 << tbf->dir.ul.usf);
+ usf_map |= (1 << tbf->dir.ul.usf[ts]);
}
/* look for USF, don't use USF=7 */
for (usf = 0; usf < 7; usf++) {
- if (!(usf_map & (1 << usf))) {
- LOGP(DRLCMAC, LOGL_DEBUG, " Found USF=%d.\n", usf);
+ if (!(usf_map & (1 << usf)))
return usf;
- }
}
- LOGP(DRLCMAC, LOGL_NOTICE, "No USF available.\n");
return -1;
}
/* lookup TBF Entity (by TFI) */
-#warning FIXME: use pdch instance by trx and ts, because tfi is local
-struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, int direction)
+struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, uint8_t trx, uint8_t ts,
+ enum gprs_rlcmac_tbf_direction dir)
{
struct gprs_rlcmac_tbf *tbf;
+ struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
+
+ if (tfi >= 32 || trx >= 8 || ts >= 8)
+ return NULL;
- llist_for_each_entry(tbf, &gprs_rlcmac_tbfs, list) {
- if (tbf->state != GPRS_RLCMAC_RELEASING
- && tbf->tfi == tfi
- && tbf->direction == direction)
+ if (dir == GPRS_RLCMAC_UL_TBF)
+ tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi];
+ else
+ tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi];
+ if (!tbf)
+ return NULL;
+
+ if (tbf->state != GPRS_RLCMAC_RELEASING)
return tbf;
- }
+
return NULL;
}
/* search for active downlink or uplink tbf */
-struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, int direction)
+struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli,
+ enum gprs_rlcmac_tbf_direction dir)
{
struct gprs_rlcmac_tbf *tbf;
- llist_for_each_entry(tbf, &gprs_rlcmac_tbfs, list) {
- if (tbf->state != GPRS_RLCMAC_RELEASING
- && tbf->tlli == tlli
- && tbf->direction == direction)
- return tbf;
+ if (dir == GPRS_RLCMAC_UL_TBF) {
+ llist_for_each_entry(tbf, &gprs_rlcmac_ul_tbfs, list) {
+ if (tbf->state != GPRS_RLCMAC_RELEASING
+ && tbf->tlli == tlli)
+ return tbf;
+ }
+ } else {
+ llist_for_each_entry(tbf, &gprs_rlcmac_dl_tbfs, list) {
+ if (tbf->state != GPRS_RLCMAC_RELEASING
+ && tbf->tlli == tlli)
+ return tbf;
+ }
}
return NULL;
}
-#warning FIXME: use pdch instance by trx and ts, because polling is local
-struct gprs_rlcmac_tbf *tbf_by_poll_fn(uint32_t fn)
+struct gprs_rlcmac_tbf *tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts)
{
+ struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
struct gprs_rlcmac_tbf *tbf;
- llist_for_each_entry(tbf, &gprs_rlcmac_tbfs, list) {
- if (tbf->state != GPRS_RLCMAC_RELEASING
+ uint8_t tfi;
+
+ /* only one TBF can poll on specific TS/FN, because scheduler can only
+ * schedule one downlink control block (with polling) at a FN per TS */
+ for (tfi = 0; tfi < 32; tfi++) {
+ tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi];
+ if (tbf && tbf->state != GPRS_RLCMAC_RELEASING
+ && tbf->poll_state == GPRS_RLCMAC_POLL_SCHED
+ && tbf->poll_fn == fn && tbf->poll_ts == ts)
+ return tbf;
+ tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi];
+ if (tbf && tbf->state != GPRS_RLCMAC_RELEASING
&& tbf->poll_state == GPRS_RLCMAC_POLL_SCHED
- && tbf->poll_fn == fn)
+ && tbf->poll_fn == fn && tbf->poll_ts == ts)
return tbf;
}
return NULL;
}
-struct gprs_rlcmac_tbf *tbf_alloc(uint8_t tfi, uint8_t trx, uint8_t ts)
+struct gprs_rlcmac_tbf *tbf_alloc(enum gprs_rlcmac_tbf_direction dir,
+ uint8_t tfi, uint8_t trx, uint8_t first_ts, uint8_t num_ts)
{
struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
struct gprs_rlcmac_pdch *pdch;
struct gprs_rlcmac_tbf *tbf;
+ uint8_t ts_count, ts;
+ int8_t usf, tsc = -1; /* both must be signed */
LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF starts here **********\n");
- LOGP(DRLCMAC, LOGL_INFO, "Allocating TBF with TFI=%d.\n", tfi);
+ LOGP(DRLCMAC, LOGL_INFO, "Allocating %s TBF with TFI=%d on TRX=%d.\n",
+ (dir == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tfi, trx);
- if (trx >= 8 || ts >= 8 || tfi >= 32)
+ if (trx >= 8 || first_ts >= 8 || tfi >= 32)
return NULL;
- pdch = &bts->trx[trx].pdch[ts];
tbf = talloc_zero(rlcmac_tall_ctx, struct gprs_rlcmac_tbf);
if (!tbf)
return NULL;
+ tbf->direction = dir;
tbf->tfi = tfi;
tbf->trx = trx;
- tbf->ts = ts;
tbf->arfcn = bts->trx[trx].arfcn;
- tbf->tsc = bts->trx[trx].pdch[ts].tsc;
- tbf->pdch = pdch;
+ /* assign free TS to TBF, where TFI is free
+ * for uplink: assign free USF to each uplink TS
+ * Note that the first TS must be free, because it was selected by
+ * tfi_alloc(). */
+ for (ts_count = 0, ts = first_ts; ts < 8; ts++) {
+ pdch = &bts->trx[trx].pdch[ts];
+ if (!pdch->enable)
+ continue;
+ if (tsc < 0)
+ tbf->tsc = tsc = pdch->tsc;
+ else if (tsc != pdch->tsc) {
+ LOGP(DRLCMAC, LOGL_ERROR, "Skipping TS=%d of TRX=%d, "
+ "because it has different TSC than lower TS "
+ "of TRX. In order to allow multislot, all "
+ "slots must be configured with the same TSC!\n",
+ ts, trx);
+ continue;
+ }
+ if (dir == GPRS_RLCMAC_UL_TBF) {
+ /* if TFI is free on TS */
+ if (!pdch->ul_tbf[tfi]) {
+ /* if USF available */
+ usf = find_free_usf(pdch, ts);
+ if (usf >= 0) {
+ LOGP(DRLCMAC, LOGL_DEBUG, " Assign "
+ "uplink TS=%d USF=%d\n",
+ ts, usf);
+ pdch->ul_tbf[tfi] = tbf;
+ tbf->pdch[ts] = pdch;
+ ts_count++;
+ } else
+ LOGP(DRLCMAC, LOGL_DEBUG, " Skipping "
+ "TS=%d, no USF available\n",
+ ts);
+ }
+ } else {
+ /* if TFI is free on TS */
+ if (!pdch->dl_tbf[tfi]) {
+ LOGP(DRLCMAC, LOGL_DEBUG, " Assign downlink "
+ "TS=%d\n", ts);
+ pdch->dl_tbf[tfi] = tbf;
+ tbf->pdch[ts] = pdch;
+ ts_count++;
+ }
+ }
+ if (ts_count == num_ts)
+ break;
+ }
+ if (!ts_count) { /* implies that direction is uplink */
+ LOGP(DRLCMAC, LOGL_NOTICE, "No USF available\n");
+ talloc_free(tbf);
+ return NULL;
+ }
+
+ tbf->first_ts = first_ts;
tbf->ws = 64;
tbf->sns = 128;
INIT_LLIST_HEAD(&tbf->llc_queue);
- llist_add(&tbf->list, &gprs_rlcmac_tbfs);
- pdch->tbf[tfi] = tbf;
+ if (dir == GPRS_RLCMAC_UL_TBF)
+ llist_add(&tbf->list, &gprs_rlcmac_ul_tbfs);
+ else
+ llist_add(&tbf->list, &gprs_rlcmac_dl_tbfs);
return tbf;
}
void tbf_free(struct gprs_rlcmac_tbf *tbf)
{
- struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
struct gprs_rlcmac_pdch *pdch;
struct msgb *msg;
+ int ts;
- LOGP(DRLCMAC, LOGL_INFO, "Free TBF=%d with TLLI=0x%08x.\n", tbf->tfi,
+ LOGP(DRLCMAC, LOGL_INFO, "Free %s TBF=%d with TLLI=0x%08x.\n",
+ (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi,
tbf->tlli);
+ if (tbf->ul_ass_state != GPRS_RLCMAC_UL_ASS_NONE)
+ LOGP(DRLCMAC, LOGL_ERROR, "Software error: Pending uplink "
+ "assignment. This may not happen, because the "
+ "assignment message never gets transmitted. Please "
+ "be shure not to free in this state. PLEASE FIX!\n");
+ if (tbf->dl_ass_state != GPRS_RLCMAC_DL_ASS_NONE)
+ LOGP(DRLCMAC, LOGL_ERROR, "Software error: Pending downlink "
+ "assignment. This may not happen, because the "
+ "assignment message never gets transmitted. Please "
+ "be shure not to free in this state. PLEASE FIX!\n");
tbf_timer_stop(tbf);
while ((msg = msgb_dequeue(&tbf->llc_queue)))
msgb_free(msg);
- pdch = &bts->trx[tbf->trx].pdch[tbf->ts];
- pdch->tbf[tbf->tfi] = NULL;
+ if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
+ for (ts = 0; ts < 8; ts++) {
+ pdch = tbf->pdch[ts];
+ if (pdch)
+ pdch->ul_tbf[tbf->tfi] = NULL;
+ }
+ } else {
+ for (ts = 0; ts < 8; ts++) {
+ pdch = tbf->pdch[ts];
+ if (pdch)
+ pdch->dl_tbf[tbf->tfi] = NULL;
+ }
+ }
llist_del(&tbf->list);
LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF ends here **********\n");
talloc_free(tbf);
@@ -203,8 +317,9 @@ const char *tbf_state_name[] = {
void tbf_new_state(struct gprs_rlcmac_tbf *tbf,
enum gprs_rlcmac_tbf_state state)
{
- LOGP(DRLCMAC, LOGL_DEBUG, "TBF=%d changes state from %s to %s\n",
- tbf->tfi, tbf_state_name[tbf->state], tbf_state_name[state]);
+ LOGP(DRLCMAC, LOGL_DEBUG, "%s TBF=%d changes state from %s to %s\n",
+ (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi,
+ tbf_state_name[tbf->state], tbf_state_name[state]);
tbf->state = state;
}
@@ -212,11 +327,14 @@ void tbf_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int T,
unsigned int seconds, unsigned int microseconds)
{
if (!osmo_timer_pending(&tbf->timer))
- LOGP(DRLCMAC, LOGL_DEBUG, "Starting TBF=%d timer %u.\n",
+ LOGP(DRLCMAC, LOGL_DEBUG, "Starting %s TBF=%d timer %u.\n",
+ (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL",
tbf->tfi, T);
else
- LOGP(DRLCMAC, LOGL_DEBUG, "Restarting TBF=%d timer %u while "
- "old timer %u pending \n", tbf->tfi, T, tbf->T);
+ LOGP(DRLCMAC, LOGL_DEBUG, "Restarting %s TBF=%d timer %u "
+ "while old timer %u pending \n",
+ (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL",
+ tbf->tfi, T, tbf->T);
tbf->T = T;
tbf->num_T_exp = 0;
@@ -231,7 +349,8 @@ void tbf_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int T,
void tbf_timer_stop(struct gprs_rlcmac_tbf *tbf)
{
if (osmo_timer_pending(&tbf->timer)) {
- LOGP(DRLCMAC, LOGL_DEBUG, "Stopping TBF=%d timer %u.\n",
+ LOGP(DRLCMAC, LOGL_DEBUG, "Stopping %s TBF=%d timer %u.\n",
+ (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL",
tbf->tfi, tbf->T);
osmo_timer_del(&tbf->timer);
}
@@ -286,7 +405,8 @@ void gprs_rlcmac_enqueue_block(bitvec *block, int len)
#endif
/* received RLC/MAC block from L1 */
-int gprs_rlcmac_rcv_block(uint8_t *data, uint8_t len, uint32_t fn)
+int gprs_rlcmac_rcv_block(uint8_t trx, uint8_t ts, uint8_t *data, uint8_t len,
+ uint32_t fn)
{
unsigned payload = data[0] >> 6;
bitvec *block;
@@ -294,14 +414,15 @@ int gprs_rlcmac_rcv_block(uint8_t *data, uint8_t len, uint32_t fn)
switch (payload) {
case GPRS_RLCMAC_DATA_BLOCK:
- rc = gprs_rlcmac_rcv_data_block_acknowledged(data, len);
+ rc = gprs_rlcmac_rcv_data_block_acknowledged(trx, ts, data,
+ len);
break;
case GPRS_RLCMAC_CONTROL_BLOCK:
block = bitvec_alloc(len);
if (!block)
return -ENOMEM;
bitvec_unpack(block, data);
- rc = gprs_rlcmac_rcv_control_block(block, fn);
+ rc = gprs_rlcmac_rcv_control_block(block, trx, ts, fn);
bitvec_free(block);
break;
case GPRS_RLCMAC_CONTROL_BLOCK_OPT:
@@ -417,14 +538,13 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
/* generate uplink assignment */
void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi,
- uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli, uint8_t new_tfi,
- uint8_t usf, uint16_t arfcn, uint8_t tn, uint8_t ta, uint8_t tsc,
- uint8_t poll)
+ uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli,
+ struct gprs_rlcmac_tbf *tbf, uint8_t poll)
{
// TODO We should use our implementation of encode RLC/MAC Control messages.
struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
unsigned wp = 0;
- int i;
+ uint8_t ts;
bitvec_write_field(dest, wp,0x1,2); // Payload Type
bitvec_write_field(dest, wp,0x0,2); // Uplink block with TDMA framenumber (N+13)
@@ -445,18 +565,18 @@ void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi,
}
bitvec_write_field(dest, wp,0x0,1); // Message escape
- bitvec_write_field(dest, wp, bts->initial_cs-1, 2); // CHANNEL_CODING_COMMAND
+ bitvec_write_field(dest, wp,bts->initial_cs-1, 2); // CHANNEL_CODING_COMMAND
bitvec_write_field(dest, wp,0x1,1); // TLLI_BLOCK_CHANNEL_CODING
bitvec_write_field(dest, wp,0x1,1); // switch TIMING_ADVANCE_VALUE = on
- bitvec_write_field(dest, wp,ta,6); // TIMING_ADVANCE_VALUE
+ bitvec_write_field(dest, wp,tbf->ta,6); // TIMING_ADVANCE_VALUE
bitvec_write_field(dest, wp,0x0,1); // switch TIMING_ADVANCE_INDEX = off
#if 1
bitvec_write_field(dest, wp,0x1,1); // Frequency Parameters information elements = present
- bitvec_write_field(dest, wp,tsc,3); // Training Sequence Code (TSC)
+ bitvec_write_field(dest, wp,tbf->tsc,3); // Training Sequence Code (TSC)
bitvec_write_field(dest, wp,0x0,2); // ARFCN = present
- bitvec_write_field(dest, wp,arfcn,10); // ARFCN
+ bitvec_write_field(dest, wp,tbf->arfcn,10); // ARFCN
#else
bitvec_write_field(dest, wp,0x0,1); // Frequency Parameters = off
#endif
@@ -468,16 +588,16 @@ void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi,
bitvec_write_field(dest, wp,0x0,1); // USF_GRANULARITY
bitvec_write_field(dest, wp,0x1,1); // switch TFI : on
- bitvec_write_field(dest, wp,new_tfi,5);// TFI
+ bitvec_write_field(dest, wp,tbf->tfi,5);// TFI
bitvec_write_field(dest, wp,0x0,1); //
bitvec_write_field(dest, wp,0x0,1); // TBF Starting Time = off
bitvec_write_field(dest, wp,0x0,1); // Timeslot Allocation
- for (i = 0; i < 8; i++) {
- if (tn == i) {
+ for (ts = 0; ts < 8; ts++) {
+ if (tbf->pdch[ts]) {
bitvec_write_field(dest, wp,0x1,1); // USF_TN(i): on
- bitvec_write_field(dest, wp,usf,3); // USF_TN(i)
+ bitvec_write_field(dest, wp,tbf->dir.ul.usf[ts],3); // USF_TN(i)
} else
bitvec_write_field(dest, wp,0x0,1); // USF_TN(i): off
}
@@ -487,12 +607,11 @@ void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi,
/* generate downlink assignment */
void write_packet_downlink_assignment(RlcMacDownlink_t * block, uint8_t old_tfi,
- uint8_t old_downlink, uint8_t new_tfi, uint16_t arfcn,
- uint8_t tn, uint8_t ta, uint8_t tsc, uint8_t poll)
+ uint8_t old_downlink, struct gprs_rlcmac_tbf *tbf, uint8_t poll)
{
// Packet downlink assignment TS 44.060 11.2.7
- int i;
+ uint8_t tn;
block->PAYLOAD_TYPE = 0x1; // RLC/MAC control block that does not include the optional octets of the RLC/MAC control header
block->RRBP = 0x0; // N+13
@@ -511,35 +630,39 @@ void write_packet_downlink_assignment(RlcMacDownlink_t * block, uint8_t old_tfi,
block->u.Packet_Downlink_Assignment.MAC_MODE = 0x0; // Dynamic Allocation
block->u.Packet_Downlink_Assignment.RLC_MODE = 0x0; // RLC acknowledged mode
block->u.Packet_Downlink_Assignment.CONTROL_ACK = old_downlink; // NW establishes no new DL TBF for the MS with running timer T3192
- block->u.Packet_Downlink_Assignment.TIMESLOT_ALLOCATION = 0x80 >> tn; // timeslot(s)
+ block->u.Packet_Downlink_Assignment.TIMESLOT_ALLOCATION = 0; // timeslot(s)
+ for (tn = 0; tn < 8; tn++) {
+ if (tbf->pdch[tn])
+ block->u.Packet_Downlink_Assignment.TIMESLOT_ALLOCATION |= 0x80 >> tn; // timeslot(s)
+ }
block->u.Packet_Downlink_Assignment.Packet_Timing_Advance.Exist_TIMING_ADVANCE_VALUE = 0x1; // TIMING_ADVANCE_VALUE = on
- block->u.Packet_Downlink_Assignment.Packet_Timing_Advance.TIMING_ADVANCE_VALUE = ta; // TIMING_ADVANCE_VALUE
+ block->u.Packet_Downlink_Assignment.Packet_Timing_Advance.TIMING_ADVANCE_VALUE = tbf->ta; // TIMING_ADVANCE_VALUE
block->u.Packet_Downlink_Assignment.Packet_Timing_Advance.Exist_IndexAndtimeSlot = 0x0; // TIMING_ADVANCE_INDEX = off
block->u.Packet_Downlink_Assignment.Exist_P0_and_BTS_PWR_CTRL_MODE = 0x0; // POWER CONTROL = off
block->u.Packet_Downlink_Assignment.Exist_Frequency_Parameters = 0x1; // Frequency Parameters = on
- block->u.Packet_Downlink_Assignment.Frequency_Parameters.TSC = tsc; // Training Sequence Code (TSC)
+ block->u.Packet_Downlink_Assignment.Frequency_Parameters.TSC = tbf->tsc; // Training Sequence Code (TSC)
block->u.Packet_Downlink_Assignment.Frequency_Parameters.UnionType = 0x0; // ARFCN = on
- block->u.Packet_Downlink_Assignment.Frequency_Parameters.u.ARFCN = arfcn; // ARFCN
+ block->u.Packet_Downlink_Assignment.Frequency_Parameters.u.ARFCN = tbf->arfcn; // ARFCN
block->u.Packet_Downlink_Assignment.Exist_DOWNLINK_TFI_ASSIGNMENT = 0x1; // DOWNLINK TFI ASSIGNMENT = on
- block->u.Packet_Downlink_Assignment.DOWNLINK_TFI_ASSIGNMENT = new_tfi; // TFI
+ block->u.Packet_Downlink_Assignment.DOWNLINK_TFI_ASSIGNMENT = tbf->tfi; // TFI
block->u.Packet_Downlink_Assignment.Exist_Power_Control_Parameters = 0x1; // Power Control Parameters = on
block->u.Packet_Downlink_Assignment.Power_Control_Parameters.ALPHA = 0x0; // ALPHA
- for (i = 0; i < 8; i++)
+ for (tn = 0; tn < 8; tn++)
{
- if (tn == i)
+ if (tbf->pdch[tn])
{
- block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[i].Exist = 0x1; // Slot[i] = on
- block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[i].GAMMA_TN = 0x0; // GAMMA_TN
+ block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[tn].Exist = 0x1; // Slot[i] = on
+ block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[tn].GAMMA_TN = 0x0; // GAMMA_TN
}
else
{
- block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[i].Exist = 0x0; // Slot[i] = off
+ block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[tn].Exist = 0x0; // Slot[i] = off
}
}
@@ -616,7 +739,7 @@ int gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf)
struct msgb *llc_pdu;
unsigned msg_len = NS_HDR_LEN + BSSGP_HDR_LEN + tbf->llc_index;
- LOGP(DBSSGP, LOGL_INFO, "LLC [PCU -> SGSN] TFI: %u TLLI: 0x%08x %s\n", tbf->tfi, tbf->tlli, osmo_hexdump(tbf->llc_frame, tbf->llc_index));
+ LOGP(DBSSGP, LOGL_INFO, "LLC [PCU -> SGSN] TFI: %u TLLI: 0x%08x len=%d\n", tbf->tfi, tbf->tlli, tbf->llc_index);
if (!bctx) {
LOGP(DBSSGP, LOGL_ERROR, "No bctx\n");
return -EIO;
diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h
index 635a6b11..db0e9ab9 100644
--- a/src/gprs_rlcmac.h
+++ b/src/gprs_rlcmac.h
@@ -46,7 +46,8 @@ struct gprs_rlcmac_pdch {
uint8_t tsc; /* TSC of this slot */
uint8_t next_ul_tfi; /* next uplink TBF/TFI to schedule (0..31) */
uint8_t next_dl_tfi; /* next downlink TBF/TFI to schedule (0..31) */
- struct gprs_rlcmac_tbf *tbf[32]; /* array of TBF pointers, by TFI */
+ 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 */
uint32_t last_rts_fn; /* store last frame number of RTS */
};
@@ -130,9 +131,12 @@ struct gprs_rlcmac_tbf {
uint8_t tfi;
uint32_t tlli;
uint8_t tlli_valid;
- uint8_t trx, ts, tsc;
- struct gprs_rlcmac_pdch *pdch;
- uint16_t arfcn, ta;
+ uint8_t trx;
+ uint16_t arfcn;
+ uint8_t tsc;
+ uint8_t first_ts;
+ struct gprs_rlcmac_pdch *pdch[8]; /* list of PDCHs allocated to TBF */
+ uint16_t ta;
uint8_t llc_frame[LLC_MAX_LEN]; /* current DL or UL frame */
uint16_t llc_index; /* current write/read position of frame */
uint16_t llc_length; /* len of current DL LLC_frame, 0 == no frame */
@@ -143,7 +147,8 @@ struct gprs_rlcmac_tbf {
enum gprs_rlcmac_tbf_ul_ack_state ul_ack_state;
enum gprs_rlcmac_tbf_poll_state poll_state;
- uint32_t poll_fn;
+ uint32_t poll_fn; /* frame number to poll */
+ uint8_t poll_ts; /* timeslot to poll */
uint16_t ws; /* window size */
uint16_t sns; /* sequence number space */
@@ -169,7 +174,7 @@ struct gprs_rlcmac_tbf {
char v_n[RLC_MAX_SNS/2]; /* receive state array */
int32_t rx_counter; /* count all received blocks */
uint8_t n3103; /* N3103 counter */
- uint8_t usf; /* USF */
+ uint8_t usf[8]; /* list USFs per PDCH (timeslot) */
} ul;
} dir;
uint8_t rlc_block[RLC_MAX_SNS/2][RLC_MAX_LEN]; /* block history */
@@ -184,19 +189,22 @@ struct gprs_rlcmac_tbf {
unsigned int num_fT_exp; /* number of consecutive fT expirations */
};
-extern struct llist_head gprs_rlcmac_tbfs;
-
-int tfi_alloc(uint8_t *_trx, uint8_t *_ts);
+extern struct llist_head gprs_rlcmac_ul_tbfs; /* list of uplink TBFs */
+extern struct llist_head gprs_rlcmac_dl_tbfs; /* list of downlink TBFs */
-struct gprs_rlcmac_tbf *tbf_alloc(uint8_t tfi, uint8_t trx, uint8_t ts);
+int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, uint8_t *_ts,
+ uint8_t use_trx, uint8_t first_ts);
-struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, int direction);
+struct gprs_rlcmac_tbf *tbf_alloc(enum gprs_rlcmac_tbf_direction dir,
+ uint8_t tfi, uint8_t trx, uint8_t first_ts, uint8_t num_ts);
-struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, int direction);
+struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, uint8_t trx, uint8_t ts,
+ enum gprs_rlcmac_tbf_direction dir);
-struct gprs_rlcmac_tbf *tbf_by_poll_fn(uint32_t fn);
+struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli,
+ enum gprs_rlcmac_tbf_direction dir);
-int find_free_usf(uint8_t trx, uint8_t ts);
+struct gprs_rlcmac_tbf *tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts);
void tbf_free(struct gprs_rlcmac_tbf *tbf);
@@ -216,7 +224,8 @@ enum gprs_rlcmac_block_type {
GPRS_RLCMAC_RESERVED = 0x3
};
-int gprs_rlcmac_rcv_block(uint8_t *data, uint8_t len, uint32_t fn);
+int gprs_rlcmac_rcv_block(uint8_t trx, uint8_t ts, uint8_t *data, uint8_t len,
+ 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,
@@ -224,13 +233,13 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
uint32_t poll_fn);
void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi,
- uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli, uint8_t new_tfi,
- uint8_t usf, uint16_t arfcn, uint8_t tn, uint8_t ta, uint8_t tsc,
- uint8_t poll);
+ uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli,
+ struct gprs_rlcmac_tbf *tbf, uint8_t poll);
void write_packet_downlink_assignment(RlcMacDownlink_t * block, uint8_t old_tfi,
- uint8_t old_downlink, uint8_t new_tfi, uint16_t arfcn,
- uint8_t tn, uint8_t ta, uint8_t tsc, uint8_t poll);
+ uint8_t old_downlink, struct gprs_rlcmac_tbf *tbf, uint8_t poll);
+
+
void write_packet_uplink_ack(RlcMacDownlink_t * block, struct gprs_rlcmac_tbf *tbf,
uint8_t final);
@@ -243,7 +252,8 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf);
int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta);
-int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint32_t fn);
+int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
+ uint32_t fn);
struct msgb *gprs_rlcmac_send_packet_uplink_assignment(
struct gprs_rlcmac_tbf *tbf, uint32_t fn);
@@ -257,7 +267,8 @@ void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf,
int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final,
uint8_t ssn, uint8_t *rbb);
-int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t *data, uint8_t len);
+int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts,
+ uint8_t *data, uint8_t len);
struct msgb *gprs_rlcmac_send_data_block_acknowledged(
struct gprs_rlcmac_tbf *tbf, uint32_t fn);
diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp
index 7beca38f..0e8aca3e 100644
--- a/src/gprs_rlcmac_data.cpp
+++ b/src/gprs_rlcmac_data.cpp
@@ -64,7 +64,8 @@ struct rlc_li_field {
int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf)
{
- LOGP(DRLCMAC, LOGL_NOTICE, "Poll timeout for TBF=%d\n", tbf->tfi);
+ LOGP(DRLCMAC, LOGL_NOTICE, "Poll timeout for %s TBF=%d\n",
+ (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi);
tbf->poll_state = GPRS_RLCMAC_POLL_NONE;
@@ -120,9 +121,10 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf)
}
/* Received Uplink RLC control block. */
-int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint32_t fn)
+int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
+ uint32_t fn)
{
- uint8_t tfi = 0;
+ int8_t tfi = 0; /* must be signed */
uint32_t tlli = 0;
struct gprs_rlcmac_tbf *tbf;
@@ -134,7 +136,7 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint32_t fn)
switch (ul_control_block->u.MESSAGE_TYPE) {
case MT_PACKET_CONTROL_ACK:
tlli = ul_control_block->u.Packet_Control_Acknowledgement.TLLI;
- tbf = tbf_by_poll_fn(fn);
+ tbf = tbf_by_poll_fn(fn, trx, ts);
if (!tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "PACKET CONTROL ACK with "
"unknown FN=%u TLL=0x%08x\n", fn, tlli);
@@ -171,7 +173,7 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint32_t fn)
break;
case MT_PACKET_DOWNLINK_ACK_NACK:
tfi = ul_control_block->u.Packet_Downlink_Ack_Nack.DOWNLINK_TFI;
- tbf = tbf_by_poll_fn(fn);
+ tbf = tbf_by_poll_fn(fn, trx, ts);
if (!tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "PACKET DOWNLINK ACK with "
"unknown FN=%u TBF=%d\n", fn, tfi);
@@ -191,32 +193,31 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint32_t fn)
ul_control_block->u.Packet_Downlink_Ack_Nack.Ack_Nack_Description.RECEIVED_BLOCK_BITMAP);
/* check for channel request */
if (ul_control_block->u.Packet_Downlink_Ack_Nack.Exist_Channel_Request_Description) {
- uint8_t trx, ts, usf;
+ uint8_t trx, ts;
struct gprs_rlcmac_tbf *ul_tbf;
struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack "
"message, so we provide one:\n");
uplink_request:
- /* create new tbf */
- tfi = tfi_alloc(&trx, &ts);
+ /* 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;
}
- usf = find_free_usf(trx, ts);
- if (usf < 0) {
- LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource for USF\n");
+ /* FIXME: set number of downlink slots according to
+ * multislot class */
+ ul_tbf = tbf_alloc(GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 1);
+ if (!ul_tbf) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
/* FIXME: send reject */
break;
}
- ul_tbf = tbf_alloc(tfi, trx, ts);
ul_tbf->tlli = tbf->tlli;
ul_tbf->tlli_valid = 1; /* no content resolution */
ul_tbf->ta = tbf->ta; /* use current TA */
- ul_tbf->direction = GPRS_RLCMAC_UL_TBF;
- ul_tbf->dir.ul.usf = usf;
tbf_new_state(ul_tbf, GPRS_RLCMAC_FLOW);
tbf_timer_start(ul_tbf, 3169, bts->t3169, 0);
/* schedule uplink assignment */
@@ -235,14 +236,14 @@ uplink_request:
} else {
if (ul_control_block->u.Packet_Resource_Request.ID.u.Global_TFI.UnionType) {
tfi = ul_control_block->u.Packet_Resource_Request.ID.u.Global_TFI.u.DOWNLINK_TFI;
- tbf = tbf_by_tfi(tfi, GPRS_RLCMAC_DL_TBF);
+ tbf = tbf_by_tfi(tfi, trx, ts, GPRS_RLCMAC_DL_TBF);
if (!tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESSOURCE REQ unknown downlink TBF=%d\n", tlli);
break;
}
} else {
tfi = ul_control_block->u.Packet_Resource_Request.ID.u.Global_TFI.u.UPLINK_TFI;
- tbf = tbf_by_tfi(tfi, GPRS_RLCMAC_UL_TBF);
+ tbf = tbf_by_tfi(tfi, trx, ts, GPRS_RLCMAC_UL_TBF);
if (!tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESSOURCE REQ unknown uplink TBF=%d\n", tlli);
break;
@@ -250,7 +251,7 @@ uplink_request:
}
tlli = tbf->tlli;
}
- LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] TFI: %u TLLI: 0x%08x Packet ressource request\n", tbf->tfi, tbf->tlli);
+ LOGP(DRLCMAC, LOGL_INFO, "RX: [PCU <- BTS] %s TFI: %u TLLI: 0x%08x Packet ressource request\n", (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi, tbf->tlli);
#warning FIXME
puts("FIXME: UL request during UL request"); exit(0);
@@ -271,7 +272,8 @@ void tbf_timer_cb(void *_tbf)
{
struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)_tbf;
- LOGP(DRLCMAC, LOGL_DEBUG, "TBF=%d timer %u expired.\n", tbf->tfi,
+ LOGP(DRLCMAC, LOGL_DEBUG, "%s TBF=%d timer %u expired.\n",
+ (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi,
tbf->T);
tbf->num_T_exp++;
@@ -495,8 +497,7 @@ static int gprs_rlcmac_assemble_llc(struct gprs_rlcmac_tbf *tbf, uint8_t *data,
if (i != frames - 1) {
/* send frame to SGSN */
LOGP(DRLCMACUL, LOGL_INFO, "Complete UL frame for "
- "TBF=%d: %s\n", tbf->tfi,
- osmo_hexdump(tbf->llc_frame, tbf->llc_index));
+ "TBF=%d: len=%d\n", tbf->tfi, tbf->llc_index);
gprs_rlcmac_tx_ul_ud(tbf);
tbf->llc_index = 0; /* reset frame space */
/* also check if CV==0, because the frame may fill up the
@@ -507,8 +508,7 @@ static int gprs_rlcmac_assemble_llc(struct gprs_rlcmac_tbf *tbf, uint8_t *data,
/* send frame to SGSN */
LOGP(DRLCMACUL, LOGL_INFO, "Complete UL frame for "
"TBF=%d that fits precisely in last block: "
- "%s\n", tbf->tfi,
- osmo_hexdump(tbf->llc_frame, tbf->llc_index));
+ "len=%d\n", tbf->tfi, tbf->llc_index);
gprs_rlcmac_tx_ul_ud(tbf);
tbf->llc_index = 0; /* reset frame space */
}
@@ -550,6 +550,7 @@ struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf,
if (final) {
tbf->poll_state = GPRS_RLCMAC_POLL_SCHED;
tbf->poll_fn = (fn + 13) % 2715648;
+ tbf->poll_ts = tbf->first_ts;
/* waiting for final acknowledge */
tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_WAIT_ACK;
} else
@@ -562,7 +563,8 @@ struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf,
*
* The blocks are defragmented and forwarded as LLC frames, if complete.
*/
-int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t *data, uint8_t len)
+int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts,
+ uint8_t *data, uint8_t len)
{
struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
struct gprs_rlcmac_tbf *tbf;
@@ -592,19 +594,13 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t *data, uint8_t len)
}
/* find TBF inst from given TFI */
- tbf = tbf_by_tfi(rh->tfi, GPRS_RLCMAC_UL_TBF);
+ tbf = tbf_by_tfi(rh->tfi, trx, ts, GPRS_RLCMAC_UL_TBF);
if (!tbf) {
LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA unknown TBF=%d\n",
rh->tfi);
return 0;
}
- if (tbf->direction != GPRS_RLCMAC_UL_TBF) {
- LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TBF=%d not Uplink "
- "tbf\n", rh->tfi);
- return 0;
- }
-
LOGP(DRLCMACUL, LOGL_DEBUG, "UL DATA TBF=%d received (V(Q)=%d .. "
"V(R)=%d)\n", rh->tfi, tbf->dir.ul.v_q, tbf->dir.ul.v_r);
@@ -755,12 +751,14 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment(
struct msgb *msg;
struct gprs_rlcmac_tbf *new_tbf;
+#if POLLING_ASSIGNMENT == 1
if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE) {
LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
"sheduled for TBF=%d, so we must wait for uplink "
"assignment...\n", tbf->tfi);
return NULL;
}
+#endif
/* on down TBF we get the uplink TBF to be assigned. */
if (tbf->direction == GPRS_RLCMAC_DL_TBF)
@@ -788,9 +786,8 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment(
bitvec_unhex(ass_vec,
"2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
write_packet_uplink_assignment(ass_vec, tbf->tfi,
- (tbf->direction == GPRS_RLCMAC_DL_TBF), 0, 0, new_tbf->tfi,
- new_tbf->dir.ul.usf, new_tbf->arfcn, new_tbf->ts, new_tbf->ta,
- new_tbf->tsc, POLLING_ASSIGNMENT);
+ (tbf->direction == GPRS_RLCMAC_DL_TBF), 0, 0, new_tbf,
+ POLLING_ASSIGNMENT);
bitvec_pack(ass_vec, msgb_put(msg, 23));
RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)malloc(sizeof(RlcMacDownlink_t));
LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++\n");
@@ -803,6 +800,7 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment(
FIXME process does not work, also the acknowledgement is not checked.
tbf->poll_state = GPRS_RLCMAC_POLL_SCHED;
tbf->poll_fn = (fn + 13) % 2715648;
+ tbf->poll_ts = tbf->first_ts;
tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_WAIT_ACK;
#else
tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE;
@@ -816,31 +814,29 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta)
struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
struct gprs_rlcmac_tbf *tbf;
uint8_t trx, ts;
- int tfi, usf; /* must be signed */
+ int8_t tfi; /* must be signed */
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF on RACH, so we provide "
"one:\n");
// Create new TBF
- tfi = tfi_alloc(&trx, &ts);
+ 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;
}
- usf = find_free_usf(trx, ts);
- if (usf < 0) {
- LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource for USF\n");
+ /* select only one TS, since we don't know the multislot class yet */
+ tbf = tbf_alloc(GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 1);
+ if (!tbf) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
/* FIXME: send reject */
return -EBUSY;
}
- tbf = tbf_alloc(tfi, trx, ts);
if (qta < 0)
qta = 0;
if (qta > 252)
qta = 252;
tbf->ta = qta >> 2;
- tbf->direction = GPRS_RLCMAC_UL_TBF;
- tbf->dir.ul.usf = usf;
tbf_new_state(tbf, GPRS_RLCMAC_FLOW);
tbf_timer_start(tbf, 3169, bts->t3169, 0);
LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [UPLINK] START TFI: %u\n", tbf->tfi);
@@ -848,7 +844,7 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta)
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->ts, tbf->tsc, tbf->tfi, usf, 0, 0, 0);
+ 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);
pcu_l1if_tx_agch(immediate_assignment, plen);
bitvec_free(immediate_assignment);
@@ -1013,8 +1009,7 @@ do_resend:
"header, and we are done\n", chunk, space);
LOGP(DRLCMACDL, LOGL_INFO, "Complete DL frame for "
"TBF=%d that fits precisely in last block: "
- "%s\n", tbf->tfi,
- osmo_hexdump(tbf->llc_frame, tbf->llc_length));
+ "len=%d\n", tbf->tfi, tbf->llc_length);
/* block is filled, so there is no extension */
*e_pointer |= 0x01;
/* fill space */
@@ -1072,9 +1067,8 @@ do_resend:
memcpy(data, tbf->llc_frame + tbf->llc_index, chunk);
data += chunk;
space -= chunk;
- LOGP(DRLCMACDL, LOGL_INFO, "Complete DL frame for TBF=%d: %s\n",
- tbf->tfi,
- osmo_hexdump(tbf->llc_frame, tbf->llc_length));
+ LOGP(DRLCMACDL, LOGL_INFO, "Complete DL frame for TBF=%d: "
+ "len=%d\n", tbf->tfi, tbf->llc_length);
/* reset LLC frame */
tbf->llc_index = tbf->llc_length = 0;
/* dequeue next LLC frame, if any */
@@ -1150,6 +1144,7 @@ tx_block:
/* schedule polling */
tbf->poll_state = GPRS_RLCMAC_POLL_SCHED;
tbf->poll_fn = (fn + 13) % 2715648;
+ tbf->poll_ts = tbf->first_ts;
/* set polling in header */
rh->rrbp = 0; /* N+13 */
@@ -1286,12 +1281,14 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment(
struct msgb *msg;
struct gprs_rlcmac_tbf *new_tbf;
+#if POLLING_ASSIGNMENT == 1
if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE) {
- LOGP(DRLCMACDL, LOGL_DEBUG, "Polling is already "
+ LOGP(DRLCMAC, LOGL_DEBUG, "Polling is already "
"sheduled for TBF=%d, so we must wait for downlink "
"assignment...\n", tbf->tfi);
return NULL;
}
+#endif
/* on uplink TBF we get the downlink TBF to be assigned. */
if (tbf->direction == GPRS_RLCMAC_UL_TBF)
@@ -1319,8 +1316,7 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment(
LOGP(DRLCMAC, LOGL_INFO, "TBF: START TFI: %u TLLI: 0x%08x Packet Downlink Assignment (PACCH)\n", new_tbf->tfi, new_tbf->tlli);
RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)malloc(sizeof(RlcMacDownlink_t));
write_packet_downlink_assignment(mac_control_block, tbf->tfi,
- (tbf->direction == GPRS_RLCMAC_DL_TBF), new_tbf->tfi,
- new_tbf->arfcn, new_tbf->ts, new_tbf->ta, new_tbf->tsc,
+ (tbf->direction == GPRS_RLCMAC_DL_TBF), new_tbf,
POLLING_ASSIGNMENT);
LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Downlink Assignment +++++++++++++++++++++++++\n");
encode_gsm_rlcmac_downlink(ass_vec, mac_control_block);
@@ -1333,6 +1329,7 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment(
#if POLLING_ASSIGNMENT == 1
tbf->poll_state = GPRS_RLCMAC_POLL_SCHED;
tbf->poll_fn = (fn + 13) % 2715648;
+ tbf->poll_ts = tbf->first_ts;
tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_WAIT_ACK;
#else
tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE;
@@ -1349,7 +1346,7 @@ static void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf, uint8_t poll,
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->last_rts_fn + 21216) % 2715648, tbf->ta, tbf->arfcn, tbf->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);
pcu_l1if_tx_pch(immediate_assignment, plen, imsi);
bitvec_free(immediate_assignment);
}
@@ -1381,8 +1378,8 @@ void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf,
tbf_timer_start(tbf, 1234, 1,0);
#else
LOGP(DRLCMAC, LOGL_DEBUG, "Send dowlink assignment on "
- "PACCH, because %slink TBF=%d exists for TLLI=0x%08x\n",
- (tbf->direction == GPRS_RLCMAC_DL_TBF) ? "down" : "up",
+ "PACCH, because %s TBF=%d exists for TLLI=0x%08x\n",
+ (old_tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL",
old_tbf->tfi, old_tbf->tlli);
old_tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_SEND_ASS;
/* use TA from old TBF */
diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp
index 4a4b85ca..7d9a156f 100644
--- a/src/gprs_rlcmac_sched.cpp
+++ b/src/gprs_rlcmac_sched.cpp
@@ -61,36 +61,43 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
poll_fn ++;
poll_fn = poll_fn % 2715648;
for (tfi = 0; tfi < 32; tfi++) {
- tbf = pdch->tbf[tfi];
- /* no TBF for this tfi, go next */
- if (!tbf)
- continue;
- /* no polling */
- if (tbf->poll_state != GPRS_RLCMAC_POLL_SCHED)
- continue;
- /* polling for next uplink block */
- if (tbf->poll_fn == poll_fn)
- break;
+ tbf = pdch->ul_tbf[tfi];
+ if (tbf) {
+ /* no polling */
+ if (tbf->poll_state != GPRS_RLCMAC_POLL_SCHED)
+ continue;
+ /* polling for next uplink block */
+ if (tbf->poll_fn == poll_fn)
+ break;
+ }
+ tbf = pdch->dl_tbf[tfi];
+ if (tbf) {
+ /* no polling */
+ if (tbf->poll_state != GPRS_RLCMAC_POLL_SCHED)
+ continue;
+ /* polling for next uplink block */
+ if (tbf->poll_fn == poll_fn)
+ break;
+ }
}
/* found uplink where a block is polled */
if (tfi < 32) {
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d "
"TS=%d FN=%d block_nr=%d scheduling free USF for "
- "polling at FN=%d of TFI=%d\n", trx, ts, fn, block_nr,
- poll_fn, tfi);
+ "polling at FN=%d of %s TFI=%d\n", trx, ts, fn,
+ block_nr, poll_fn,
+ (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL",
+ tfi);
/* use free USF */
/* else, we search for uplink ressource */
} else {
/* select uplink ressource */
for (i = 0, tfi = pdch->next_ul_tfi; i < 32;
i++, tfi = (tfi + 1) & 31) {
- tbf = pdch->tbf[tfi];
+ tbf = pdch->ul_tbf[tfi];
/* no TBF for this tfi, go next */
if (!tbf)
continue;
- /* no UL TBF, go next */
- if (tbf->direction != GPRS_RLCMAC_UL_TBF)
- continue;
/* no UL ressources needed, go next */
/* we don't need to give ressources in FINISHED state,
* because we have received all blocks and only poll
@@ -99,11 +106,11 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
continue;
/* use this USF */
- usf = tbf->dir.ul.usf;
+ usf = tbf->dir.ul.usf[ts];
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: "
"TRX=%d TS=%d FN=%d block_nr=%d scheduling "
"USF=%d for required uplink ressource of "
- "TBF=%d\n", trx, ts, fn, block_nr, usf, tfi);
+ "UL TBF=%d\n", trx, ts, fn, block_nr, usf, tfi);
/* next TBF to handle ressource is the next one */
pdch->next_ul_tfi = (tfi + 1) & 31;
break;
@@ -111,8 +118,11 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
}
/* Prio 1: select control message */
- for (tfi = 0; tfi < 32; tfi++) {
- tbf = pdch->tbf[tfi];
+ for (i = 0; i < 64; i++) {
+ if (i < 32)
+ tbf = pdch->ul_tbf[i];
+ else
+ tbf = pdch->dl_tbf[i & 31];
/* no TBF for this tfi, go next */
if (!tbf)
continue;
@@ -131,7 +141,9 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
msg = gprs_rlcmac_send_uplink_ack(tbf, fn);
if (msg) {
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling control "
- "message at RTS for TBF=%d\n", tfi);
+ "message at RTS for %s TBF=%d\n",
+ (tbf->direction == GPRS_RLCMAC_UL_TBF)
+ ? "UL" : "DL", tbf->tfi);
break;
}
}
@@ -141,7 +153,7 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
/* select downlink ressource */
for (i = 0, tfi = pdch->next_dl_tfi; i < 32;
i++, tfi = (tfi + 1) & 31) {
- tbf = pdch->tbf[tfi];
+ tbf = pdch->dl_tbf[tfi];
/* no TBF for this tfi, go next */
if (!tbf)
continue;
@@ -154,7 +166,7 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
continue;
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling data "
- "message at RTS for TBF=%d\n", tfi);
+ "message at RTS for DL TBF=%d\n", tfi);
/* next TBF to handle ressource is the next one */
pdch->next_dl_tfi = (tfi + 1) & 31;
/* generate DL data block */
diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp
index d0f2e325..a58a1221 100644
--- a/src/pcu_l1_if.cpp
+++ b/src/pcu_l1_if.cpp
@@ -182,8 +182,8 @@ static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind)
switch (data_ind->sapi) {
case PCU_IF_SAPI_PDTCH:
- rc = gprs_rlcmac_rcv_block(data_ind->data, data_ind->len,
- data_ind->fn);
+ rc = gprs_rlcmac_rcv_block(data_ind->trx_nr, data_ind->ts_nr,
+ data_ind->data, data_ind->len, data_ind->fn);
break;
default:
LOGP(DL1IF, LOGL_ERROR, "Received PCU data indication with "
@@ -265,7 +265,10 @@ bssgp_failed:
bts->trx[trx].arfcn = info_ind->trx[trx].arfcn;
for (ts = 0; ts < 8; ts++) {
for (tfi = 0; tfi < 32; tfi++) {
- tbf = bts->trx[trx].pdch[ts].tbf[tfi];
+ tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi];
+ if (tbf)
+ tbf_free(tbf);
+ tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi];
if (tbf)
tbf_free(tbf);
}
@@ -369,9 +372,12 @@ bssgp_failed:
if (bts->trx[trx].pdch[ts].enable)
pcu_tx_act_req(trx, ts, 0);
bts->trx[trx].pdch[ts].enable = 0;
- /* kick all tbf FIXME: multislot */
+ /* kick all TBF on slot */
for (tfi = 0; tfi < 32; tfi++) {
- tbf = bts->trx[trx].pdch[ts].tbf[tfi];
+ tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi];
+ if (tbf)
+ tbf_free(tbf);
+ tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi];
if (tbf)
tbf_free(tbf);
}
@@ -384,8 +390,6 @@ bssgp_failed:
static int pcu_rx_time_ind(struct gsm_pcu_if_time_ind *time_ind)
{
- struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
- int trx, ts, tfi;
struct gprs_rlcmac_tbf *tbf;
uint32_t elapsed;
uint8_t fn13 = time_ind->fn % 13;
@@ -400,19 +404,18 @@ static int pcu_rx_time_ind(struct gsm_pcu_if_time_ind *time_ind)
set_current_fn(time_ind->fn);
/* check for poll timeout */
- for (trx = 0; trx < 8; trx++) {
- for (ts = 0; ts < 8; ts++) {
- for (tfi = 0; tfi < 32; tfi++) {
- tbf = bts->trx[trx].pdch[ts].tbf[tfi];
- if (!tbf)
- continue;
- if (tbf->poll_state != GPRS_RLCMAC_POLL_SCHED)
- continue;
- elapsed = (frame_number - tbf->poll_fn)
- % 2715648;
- if (elapsed >= 20 && elapsed < 200)
- gprs_rlcmac_poll_timeout(tbf);
- }
+ llist_for_each_entry(tbf, &gprs_rlcmac_ul_tbfs, list) {
+ if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED) {
+ elapsed = (frame_number - tbf->poll_fn) % 2715648;
+ if (elapsed >= 20 && elapsed < 200)
+ gprs_rlcmac_poll_timeout(tbf);
+ }
+ }
+ llist_for_each_entry(tbf, &gprs_rlcmac_dl_tbfs, list) {
+ if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED) {
+ elapsed = (frame_number - tbf->poll_fn) % 2715648;
+ if (elapsed >= 20 && elapsed < 200)
+ gprs_rlcmac_poll_timeout(tbf);
}
}
diff --git a/src/sysmo_sock.cpp b/src/sysmo_sock.cpp
index 390f3f69..6b390edc 100644
--- a/src/sysmo_sock.cpp
+++ b/src/sysmo_sock.cpp
@@ -97,7 +97,10 @@ static void pcu_sock_close(struct pcu_sock_state *state)
for (ts = 0; ts < 8; ts++) {
bts->trx[trx].pdch[ts].enable = 0;
for (tfi = 0; tfi < 32; tfi++) {
- tbf = bts->trx[trx].pdch[ts].tbf[tfi];
+ tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi];
+ if (tbf)
+ tbf_free(tbf);
+ tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi];
if (tbf)
tbf_free(tbf);
}
diff --git a/src/tbf.txt b/src/tbf.txt
index 3c06b39c..57254ea3 100644
--- a/src/tbf.txt
+++ b/src/tbf.txt
@@ -109,3 +109,33 @@ Polling:
- The received frame is bad (BFI).
- The GSM indicates that the block should have been already received.
+Data structures of TBFs and PDCHs:
+
+ There is a global structure for BTS.
+
+ The BTS structure has 8 TRX structures.
+
+ Each TRX structure has 8 PDCH structures, one for each timeslot.
+
+ There are two linked lists of TBF instances:
+ - uplink TBFs
+ - downlink TBFs
+
+ Each TBF instance also has:
+ - a direction
+ - a TFI of range 0..31
+ - an array of 8 PDCH structures, one for each assigned timeslot
+ - in case of uplink TBF: an array of 8 USFs, one for each assigned timeslot
+
+ Each PDCH structure also has:
+ - an array of 32 uplink TBFs that are assigned to this PDCH
+ - an array of 32 downlink TBFs that are assigned to this PDCH
+
+ On creation of a new TBF, it links to all assigned PDCHs.
+ Each PDCH links to that TBF. The TBF is added to the list of TBFs.
+ In case of uplink TBF: The allocated USFs are stored for each timeslot.
+
+ On release of a TBF, the link to this PDCH is removed from all assigned
+ PDCHs. The TBF is removed from the list of TBFs. The TBF is destroyed.
+
+