diff options
Diffstat (limited to 'src/gprs_rlcmac_data.cpp')
-rw-r--r-- | src/gprs_rlcmac_data.cpp | 465 |
1 files changed, 1 insertions, 464 deletions
diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 324e2b96..f2887b2a 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -24,6 +24,7 @@ #include <bts.h> #include <encoding.h> #include <tbf.h> +#include <rlc.h> static struct gprs_rlcmac_cs gprs_rlcmac_cs[] = { /* frame length data block max payload */ @@ -37,9 +38,6 @@ static struct gprs_rlcmac_cs gprs_rlcmac_cs[] = { extern void *tall_pcu_ctx; -/* After receiving these frames, we send ack/nack. */ -#define SEND_ACK_AFTER_FRAMES 20 - /* After sending these frames, we poll for ack/nack. */ #define POLL_ACK_AFTER_FRAMES 20 @@ -47,39 +45,6 @@ extern void *tall_pcu_ctx; #define POLLING_ASSIGNMENT_DL 1 #define POLLING_ASSIGNMENT_UL 1 -extern "C" { -/* TS 04.60 10.2.2 */ -struct rlc_ul_header { - uint8_t r:1, - si:1, - cv:4, - pt:2; - uint8_t ti:1, - tfi:5, - pi:1, - spare:1; - uint8_t e:1, - bsn:7; -} __attribute__ ((packed)); - -struct rlc_dl_header { - uint8_t usf:3, - s_p:1, - rrbp:2, - pt:2; - uint8_t fbi:1, - tfi:5, - pr:2; - uint8_t e:1, - bsn:7; -} __attribute__ ((packed)); - -struct rlc_li_field { - uint8_t e:1, - m:1, - li:6; -} __attribute__ ((packed)); -} static void gprs_rlcmac_downlink_assignment( gprs_rlcmac_tbf *tbf, uint8_t poll, @@ -469,212 +434,6 @@ int gprs_rlcmac_rcv_control_block(struct gprs_rlcmac_bts *bts, * UL data block flow */ -/* get TLLI from received UL data block */ -static int tlli_from_ul_data(uint8_t *data, uint8_t len, uint32_t *tlli) -{ - struct rlc_ul_header *rh = (struct rlc_ul_header *)data; - struct rlc_li_field *li; - uint8_t e; - uint32_t _tlli; - - if (!rh->ti) - return -EINVAL; - - data += 3; - len -= 3; - e = rh->e; - /* if E is not set (LI follows) */ - while (!e) { - if (!len) { - LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, " - "but no more data\n"); - return -EINVAL; - } - /* get new E */ - li = (struct rlc_li_field *)data; - if (li->e == 0) /* if LI==0, E is interpreted as '1' */ - e = 1; - else - e = li->e; - data++; - len--; - } - if (len < 4) { - LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TLLI out of frame " - "border\n"); - return -EINVAL; - } - memcpy(&_tlli, data, 4); - *tlli = ntohl(_tlli); - - return 0; -} - -/* Store received block data in LLC message(s) and forward to SGSN if complete. - */ -static int gprs_rlcmac_assemble_llc(struct gprs_rlcmac_tbf *tbf, uint8_t *data, - uint8_t len) -{ - struct rlc_ul_header *rh = (struct rlc_ul_header *)data; - uint8_t e, m; - struct rlc_li_field *li; - uint8_t frame_offset[16], offset = 0, chunk; - int i, frames = 0; - - LOGP(DRLCMACUL, LOGL_DEBUG, "- Assembling frames: (len=%d)\n", len); - - data += 3; - len -= 3; - e = rh->e; /* if extended */ - m = 1; /* more frames, that means: the first frame */ - - /* Parse frame offsets from length indicator(s), if any. */ - while (1) { - if (frames == (int)sizeof(frame_offset)) { - LOGP(DRLCMACUL, LOGL_ERROR, "Too many frames in " - "block\n"); - return -EINVAL; - } - frame_offset[frames++] = offset; - LOGP(DRLCMACUL, LOGL_DEBUG, "-- Frame %d starts at offset " - "%d\n", frames, offset); - if (!len) - break; - /* M == 0 and E == 0 is not allowed in this version. */ - if (!m && !e) { - LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TBF=%d " - "ignored, because M='0' and E='0'.\n", - tbf->tfi); - return 0; - } - /* no more frames in this segment */ - if (e) { - break; - } - /* There is a new frame and an LI that delimits it. */ - if (m) { - li = (struct rlc_li_field *)data; - LOGP(DRLCMACUL, LOGL_DEBUG, "-- Delimiter len=%d\n", - li->li); - /* Special case: LI == 0 - * If the last segment would fit precisely into the - * rest of the RLC MAC block, there would be no way - * to delimit that this segment ends and is not - * continued in the next block. - * The special LI (0) is used to force the segment to - * extend into the next block, so it is delimited there. - * This LI must be skipped. Also it is the last LI. - */ - if (li->li == 0) { - data++; - len--; - m = 1; /* M is ignored, we know there is more */ - break; /* handle E as '1', so we break! */ - } - e = li->e; - m = li->m; - offset += li->li; - data++; - len--; - continue; - } - } - if (!m) { - LOGP(DRLCMACUL, LOGL_DEBUG, "- Last frame carries spare " - "data\n"); - } - - LOGP(DRLCMACUL, LOGL_DEBUG, "- Data length after length fields: %d\n", - len); - /* TLLI */ - if (rh->ti) { - if (len < 4) { - LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TLLI out of " - "frame border\n"); - return -EINVAL; - } - data += 4; - len -= 4; - LOGP(DRLCMACUL, LOGL_DEBUG, "- Length after skipping TLLI: " - "%d\n", len); - } - - /* PFI */ - if (rh->pi) { - LOGP(DRLCMACUL, LOGL_ERROR, "ERROR: PFI not supported, " - "please disable in SYSTEM INFORMATION\n"); - if (len < 1) { - LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA PFI out of " - "frame border\n"); - return -EINVAL; - } - data++; - len--; - LOGP(DRLCMACUL, LOGL_DEBUG, "- Length after skipping PFI: " - "%d\n", len); - } - - /* Now we have: - * - a list of frames offsets: frame_offset[] - * - number of frames: i - * - m == 0: Last frame carries spare data (end of TBF). - */ - - /* Check if last offset would exceed frame. */ - if (offset > len) { - LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TBF=%d ignored, " - "because LI delimits data that exceeds block size.\n", - tbf->tfi); - return -EINVAL; - } - - /* create LLC frames */ - for (i = 0; i < frames; i++) { - /* last frame ? */ - if (i == frames - 1) { - /* no more data in last frame */ - if (!m) - break; - /* data until end of frame */ - chunk = len - frame_offset[i]; - } else { - /* data until next frame */ - chunk = frame_offset[i + 1] - frame_offset[i]; - } - LOGP(DRLCMACUL, LOGL_DEBUG, "-- Appending chunk (len=%d) to " - "frame at %d.\n", chunk, tbf->llc_index); - if (tbf->llc_index + chunk > LLC_MAX_LEN) { - LOGP(DRLCMACUL, LOGL_NOTICE, "LLC frame exceeds " - "maximum size.\n"); - chunk = LLC_MAX_LEN - tbf->llc_index; - } - memcpy(tbf->llc_frame + tbf->llc_index, data + frame_offset[i], - chunk); - tbf->llc_index += chunk; - /* not last frame. */ - if (i != frames - 1) { - /* send frame to SGSN */ - LOGP(DRLCMACUL, LOGL_INFO, "Complete UL frame for " - "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 - * block precisely, then it is also complete. normally the - * frame would be extended into the next block with a 0-length - * delimiter added to this block. */ - } else if (rh->cv == 0) { - /* send frame to SGSN */ - LOGP(DRLCMACUL, LOGL_INFO, "Complete UL frame for " - "TBF=%d that fits precisely in last block: " - "len=%d\n", tbf->tfi, tbf->llc_index); - gprs_rlcmac_tx_ul_ud(tbf); - tbf->llc_index = 0; /* reset frame space */ - } - } - - return 0; -} - struct msgb *gprs_rlcmac_send_uplink_ack( struct gprs_rlcmac_tbf *tbf, uint32_t fn) @@ -731,228 +490,6 @@ struct msgb *gprs_rlcmac_send_uplink_ack( return msg; } -/* receive UL data block - * - * The blocks are defragmented and forwarded as LLC frames, if complete. - */ -int gprs_rlcmac_rcv_data_block_acknowledged(struct gprs_rlcmac_bts *bts, - uint8_t trx, uint8_t ts, - uint8_t *data, uint8_t len, int8_t rssi) -{ - struct gprs_rlcmac_tbf *tbf; - struct rlc_ul_header *rh = (struct rlc_ul_header *)data; - uint16_t mod_sns, mod_sns_half, offset_v_q, offset_v_r, index; - int rc; - - switch (len) { - case 54: - /* omitting spare bits */ - len = 53; - break; - case 40: - /* omitting spare bits */ - len = 39; - break; - case 34: - /* omitting spare bits */ - len = 33; - break; - case 23: - break; - default: - LOGP(DRLCMACUL, LOGL_ERROR, "Dropping data block with invalid" - "length: %d)\n", len); - return -EINVAL; - } - - /* find TBF inst from given TFI */ - tbf = tbf_by_tfi(bts, rh->tfi, trx, GPRS_RLCMAC_UL_TBF); - if (!tbf) { - LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA unknown TBF=%d\n", - rh->tfi); - return 0; - } - tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_UL_DATA); - - 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); - - /* process RSSI */ - gprs_rlcmac_rssi(tbf, rssi); - - /* get TLLI */ - if (!tbf->tlli_valid) { - struct gprs_rlcmac_tbf *dl_tbf, *ul_tbf; - - /* no TLLI yet */ - if (!rh->ti) { - LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TBF=%d without " - "TLLI, but no TLLI received yet\n", rh->tfi); - return 0; - } - rc = tlli_from_ul_data(data, len, &tbf->tlli); - if (rc) { - LOGP(DRLCMACUL, LOGL_NOTICE, "Failed to decode TLLI " - "of UL DATA TBF=%d.\n", rh->tfi); - return 0; - } - LOGP(DRLCMACUL, LOGL_INFO, "Decoded premier TLLI=0x%08x of " - "UL DATA TBF=%d.\n", tbf->tlli, rh->tfi); - if ((dl_tbf = bts->bts->tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_DL_TBF))) { - LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from " - "TLLI=0x%08x while DL TBF=%d still exists. " - "Killing pending DL TBF\n", tbf->tlli, - dl_tbf->tfi); - tbf_free(dl_tbf); - } - /* tbf_by_tlli will not find your TLLI, because it is not - * yet marked valid */ - if ((ul_tbf = bts->bts->tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_UL_TBF))) { - LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from " - "TLLI=0x%08x while UL TBF=%d still exists. " - "Killing pending UL TBF\n", tbf->tlli, - ul_tbf->tfi); - tbf_free(ul_tbf); - } - /* mark TLLI valid now */ - tbf->tlli_valid = 1; - /* store current timing advance */ - bts->bts->timing_advance()->remember(tbf->tlli, tbf->ta); - /* already have TLLI, but we stille get another one */ - } else if (rh->ti) { - uint32_t tlli; - rc = tlli_from_ul_data(data, len, &tlli); - if (rc) { - LOGP(DRLCMACUL, LOGL_NOTICE, "Failed to decode TLLI " - "of UL DATA TBF=%d.\n", rh->tfi); - return 0; - } - if (tlli != tbf->tlli) { - LOGP(DRLCMACUL, LOGL_NOTICE, "TLLI mismatch on UL " - "DATA TBF=%d. (Ignoring due to contention " - "resolution)\n", rh->tfi); - return 0; - } - } - - mod_sns = tbf->sns - 1; - mod_sns_half = (tbf->sns >> 1) - 1; - - /* restart T3169 */ - tbf_timer_start(tbf, 3169, bts->t3169, 0); - - /* Increment RX-counter */ - tbf->dir.ul.rx_counter++; - - /* current block relative to lowest unreceived block */ - offset_v_q = (rh->bsn - tbf->dir.ul.v_q) & mod_sns; - /* If out of window (may happen if blocks below V(Q) are received - * again. */ - if (offset_v_q >= tbf->ws) { - LOGP(DRLCMACUL, LOGL_DEBUG, "- BSN %d out of window " - "%d..%d (it's normal)\n", rh->bsn, tbf->dir.ul.v_q, - (tbf->dir.ul.v_q + tbf->ws - 1) & mod_sns); - return 0; - } - /* Write block to buffer and set receive state array. */ - index = rh->bsn & mod_sns_half; /* memory index of block */ - memcpy(tbf->rlc_block[index], data, len); /* Copy block. */ - tbf->rlc_block_len[index] = len; - tbf->dir.ul.v_n[index] = 'R'; /* Mark received block. */ - LOGP(DRLCMACUL, LOGL_DEBUG, "- BSN %d storing in window (%d..%d)\n", - rh->bsn, tbf->dir.ul.v_q, - (tbf->dir.ul.v_q + tbf->ws - 1) & mod_sns); - /* Raise V(R) to highest received sequence number not received. */ - offset_v_r = (rh->bsn + 1 - tbf->dir.ul.v_r) & mod_sns; - if (offset_v_r < (tbf->sns >> 1)) { /* Positive offset, so raise. */ - while (offset_v_r--) { - if (offset_v_r) /* all except the received block */ - tbf->dir.ul.v_n[tbf->dir.ul.v_r & mod_sns_half] - = 'N'; /* Mark block as not received */ - tbf->dir.ul.v_r = (tbf->dir.ul.v_r + 1) & mod_sns; - /* Inc V(R). */ - } - LOGP(DRLCMACUL, LOGL_DEBUG, "- Raising V(R) to %d\n", - tbf->dir.ul.v_r); - } - - /* Raise V(Q) if possible, and retrieve LLC frames from blocks. - * This is looped until there is a gap (non received block) or - * the window is empty.*/ - while (tbf->dir.ul.v_q != tbf->dir.ul.v_r && tbf->dir.ul.v_n[ - (index = tbf->dir.ul.v_q & mod_sns_half)] == 'R') { - LOGP(DRLCMACUL, LOGL_DEBUG, "- Taking block %d out, raising " - "V(Q) to %d\n", tbf->dir.ul.v_q, - (tbf->dir.ul.v_q + 1) & mod_sns); - /* get LLC data from block */ - gprs_rlcmac_assemble_llc(tbf, tbf->rlc_block[index], - tbf->rlc_block_len[index]); - /* raise V(Q), because block already received */ - tbf->dir.ul.v_q = (tbf->dir.ul.v_q + 1) & mod_sns; - } - - /* Check CV of last frame in buffer */ - if (tbf->state_is(GPRS_RLCMAC_FLOW) /* still in flow state */ - && tbf->dir.ul.v_q == tbf->dir.ul.v_r) { /* if complete */ - struct rlc_ul_header *last_rh = (struct rlc_ul_header *) - tbf->rlc_block[(tbf->dir.ul.v_r - 1) & mod_sns_half]; - LOGP(DRLCMACUL, LOGL_DEBUG, "- No gaps in received block, " - "last block: BSN=%d CV=%d\n", last_rh->bsn, - last_rh->cv); - if (last_rh->cv == 0) { - LOGP(DRLCMACUL, LOGL_DEBUG, "- Finished with UL " - "TBF\n"); - tbf_new_state(tbf, GPRS_RLCMAC_FINISHED); - /* Reset N3103 counter. */ - tbf->dir.ul.n3103 = 0; - } - } - - /* If TLLI is included or if we received half of the window, we send - * an ack/nack */ - if (rh->si || rh->ti || tbf->state_is(GPRS_RLCMAC_FINISHED) - || (tbf->dir.ul.rx_counter % SEND_ACK_AFTER_FRAMES) == 0) { - if (rh->si) { - LOGP(DRLCMACUL, LOGL_NOTICE, "- Scheduling Ack/Nack, " - "because MS is stalled.\n"); - } - if (rh->ti) { - LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, " - "because TLLI is included.\n"); - } - if (tbf->state_is(GPRS_RLCMAC_FINISHED)) { - LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, " - "because last block has CV==0.\n"); - } - if ((tbf->dir.ul.rx_counter % SEND_ACK_AFTER_FRAMES) == 0) { - LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, " - "because %d frames received.\n", - SEND_ACK_AFTER_FRAMES); - } - if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_NONE) { -#ifdef DEBUG_DIAGRAM - if (rh->si) - debug_diagram(bts->bts, tbf->diag, "sched UL-ACK stall"); - if (rh->ti) - debug_diagram(bts->bts, tbf->diag, "sched UL-ACK TLLI"); - if (tbf->state_is(GPRS_RLCMAC_FINISHED)) - debug_diagram(bts->bts, tbf->diag, "sched UL-ACK CV==0"); - if ((tbf->dir.ul.rx_counter % SEND_ACK_AFTER_FRAMES) == 0) - debug_diagram(bts->bts, tbf->diag, "sched UL-ACK n=%d", - tbf->dir.ul.rx_counter); -#endif - /* trigger sending at next RTS */ - tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_SEND_ACK; - } else { - /* already triggered */ - LOGP(DRLCMACUL, LOGL_DEBUG, "- Sending Ack/Nack is " - "already triggered, don't schedule!\n"); - } - } - - return 0; -} - struct msgb *gprs_rlcmac_send_packet_uplink_assignment( struct gprs_rlcmac_tbf *tbf, uint32_t fn) { |