aboutsummaryrefslogtreecommitdiffstats
path: root/src/gprs_rlcmac_data.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gprs_rlcmac_data.cpp')
-rw-r--r--src/gprs_rlcmac_data.cpp465
1 files changed, 1 insertions, 464 deletions
diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp
index 324e2b9..f2887b2 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)
{