diff options
-rw-r--r-- | src/gprs_bssgp_pcu.cpp | 30 | ||||
-rw-r--r-- | src/gprs_rlcmac.cpp | 303 | ||||
-rw-r--r-- | src/gprs_rlcmac.h | 55 | ||||
-rw-r--r-- | src/gprs_rlcmac_data.cpp | 103 | ||||
-rw-r--r-- | src/gprs_rlcmac_sched.cpp | 58 | ||||
-rw-r--r-- | src/pcu_l1_if.cpp | 43 | ||||
-rw-r--r-- | src/sysmo_sock.cpp | 5 | ||||
-rw-r--r-- | src/tbf.txt | 30 |
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. + + |