aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gprs_bssgp_pcu.cpp41
-rw-r--r--src/gprs_rlcmac.cpp674
-rw-r--r--src/gprs_rlcmac.h79
3 files changed, 561 insertions, 233 deletions
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp
index 82e483c3..8924e5b2 100644
--- a/src/gprs_bssgp_pcu.cpp
+++ b/src/gprs_bssgp_pcu.cpp
@@ -28,22 +28,17 @@ struct bssgp_bvc_ctx *bctx = btsctx_alloc(BVCI, NSEI);
int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
{
struct bssgp_ud_hdr *budh;
- int tfi;
int i = 0;
budh = (struct bssgp_ud_hdr *)msgb_bssgph(msg);
+
struct gprs_rlcmac_tbf *tbf;
- // Create new TBF
- tfi = tfi_alloc();
- if (tfi < 0) {
- return tfi;
- }
- tbf = tbf_alloc(tfi);
- tbf->direction = GPRS_RLCMAC_DL_TBF;
- tbf->state = GPRS_RLCMAC_WAIT_DATA_SEQ_START;
- tbf->tlli = ntohl(budh->tlli);
- LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] START TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli);
+ tbf = tbf_alloc(GPRS_RLCMAC_DL_TBF, ntohl(budh->tlli));
+ if (!tbf)
+ {
+ return -1;
+ }
/* LLC_PDU is mandatory IE */
if (!TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU))
{
@@ -51,18 +46,8 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
}
- uint8_t *llc_pdu = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_LLC_PDU);
- tbf->data_index = TLVP_LEN(tp, BSSGP_IE_LLC_PDU);
-
- LOGP(DBSSGP, LOGL_NOTICE, "LLC PDU = ");
- for (i = 0; i < tbf->data_index; i++)
- {
- tbf->rlc_data[i] = llc_pdu[i];
- LOGPC(DBSSGP, LOGL_NOTICE, "%02x", tbf->rlc_data[i]);
- }
-
uint16_t imsi_len = 0;
- uint8_t *imsi;
+ uint8_t *imsi = NULL;
if (TLVP_PRESENT(tp, BSSGP_IE_IMSI))
{
imsi_len = TLVP_LEN(tp, BSSGP_IE_IMSI);
@@ -73,12 +58,18 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
{
LOGPC(DBSSGP, LOGL_NOTICE, "%02x", imsi[i]);
}
- LOGPC(DBSSGP, LOGL_NOTICE, "\n");
+ LOGP(DBSSGP, LOGL_NOTICE, "\n");
}
+
+ tbf_dl_establish(tbf, imsi);
- gprs_rlcmac_packet_downlink_assignment(tbf);
-
+ uint8_t *llc_pdu = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_LLC_PDU);
+ uint16_t llc_pdu_len = TLVP_LEN(tp, BSSGP_IE_LLC_PDU);
+
+ tbf_dl_data_transfer(tbf, llc_pdu, llc_pdu_len);
}
+
+
/* Receive a BSSGP PDU from a BSS on a PTP BVCI */
int gprs_bssgp_pcu_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *bctx)
{
diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp
index 7e9a0321..f20fd2f3 100644
--- a/src/gprs_rlcmac.cpp
+++ b/src/gprs_rlcmac.cpp
@@ -47,47 +47,416 @@ int tfi_alloc()
}
/* lookup TBF Entity (by TFI) */
-static struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi)
+static struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, gprs_rlcmac_tbf_direction dir)
{
struct gprs_rlcmac_tbf *tbf;
llist_for_each_entry(tbf, &gprs_rlcmac_tbfs, list) {
- if (tbf->tfi == tfi)
+ if ((tbf->tfi == tfi)&&(tbf->direction == dir))
return tbf;
}
return NULL;
}
-static struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli)
+static struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, gprs_rlcmac_tbf_direction dir)
{
struct gprs_rlcmac_tbf *tbf;
llist_for_each_entry(tbf, &gprs_rlcmac_tbfs, list) {
- if ((tbf->tlli == tlli)&&(tbf->direction == GPRS_RLCMAC_UL_TBF))
+ if ((tbf->tlli == tlli)&&(tbf->direction == dir))
return tbf;
}
return NULL;
}
-struct gprs_rlcmac_tbf *tbf_alloc(uint8_t tfi)
+static void tbf_free(struct gprs_rlcmac_tbf *tbf)
+{
+ llist_del(&tbf->list);
+ talloc_free(tbf);
+}
+
+/* Lookup LLC PDU in TBF list of LLC PDUs by number. */
+static struct tbf_llc_pdu *tbf_llc_pdu_by_num(struct llist_head llc_pdus, uint8_t num)
+{
+ struct tbf_llc_pdu *llc_pdu;
+
+ llist_for_each_entry(llc_pdu, &llc_pdus, list) {
+ if (llc_pdu->num == num)
+ return llc_pdu;
+ }
+ return NULL;
+}
+
+/* Add new LLC PDU to the TBF list of LLC PDUs. */
+int tbf_add_llc_pdu(struct gprs_rlcmac_tbf *tbf, uint8_t *data, uint16_t llc_pdu_len)
+{
+ struct tbf_llc_pdu *llc_pdu;
+
+ llc_pdu = talloc_zero(rlcmac_tall_ctx, struct tbf_llc_pdu);
+ if (!llc_pdu)
+ return 0;
+
+ llc_pdu->num = tbf->llc_pdu_list_len;
+ llc_pdu->len = llc_pdu_len;
+
+ LOGP(DBSSGP, LOGL_NOTICE, "LLC PDU = ");
+ for (unsigned i = 0; i < llc_pdu_len; i++)
+ {
+ llc_pdu->data[i] = data[i];
+ LOGPC(DBSSGP, LOGL_NOTICE, "%02x", llc_pdu->data[i]);
+ }
+ LOGP(DBSSGP, LOGL_NOTICE, "\n");
+
+ llist_add(&llc_pdu->list, &tbf->llc_pdus);
+ tbf->llc_pdu_list_len++;
+ return 1;
+}
+
+struct gprs_rlcmac_tbf *tbf_alloc(gprs_rlcmac_tbf_direction dir, uint32_t tlli)
{
+ struct gprs_rlcmac_tbf *exist_tbf;
struct gprs_rlcmac_tbf *tbf;
+ uint8_t tfi;
- tbf = talloc_zero(rlcmac_tall_ctx, struct gprs_rlcmac_tbf);
- if (!tbf)
- return NULL;
+ // Downlink TDF allocation
+ if (dir == GPRS_RLCMAC_DL_TBF)
+ {
+ // Try to find already exist DL TBF
+ exist_tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_DL_TBF);
+ if (exist_tbf)
+ {
+ // if DL TBF is in establish or data transfer state,
+ // send additional LLC PDU during current DL TBF.
+ if (exist_tbf->stage != TBF_RELEASE)
+ {
+ if (exist_tbf->state != FINISH_DATA_TRANSFER)
+ {
+ return exist_tbf;
+ }
+ }
+ }
+
+ //Try to find already exist UL TBF
+ exist_tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF);
+ if (exist_tbf)
+ {
+ // if UL TBF is in data transfer state,
+ // establish new DL TBF during current UL TBF.
+ if (exist_tbf->stage == TBF_DATA_TRANSFER && !(exist_tbf->next_tbf))
+ {
+ tbf = talloc_zero(rlcmac_tall_ctx, struct gprs_rlcmac_tbf);
+ if (tbf)
+ {
+ // Create new TBF
+ tfi = tfi_alloc();
+ if (tfi < 0) {
+ return NULL;
+ }
+ tbf->tfi = tfi;
+ tbf->llc_pdus = LLIST_HEAD_INIT(tbf->llc_pdus);
+ tbf->llc_pdu_list_len = 0;
+ tbf->direction = GPRS_RLCMAC_DL_TBF;
+ tbf->stage = TBF_ESTABLISH;
+ tbf->state = WAIT_ESTABLISH;
+ tbf->tlli = tlli;
+ llist_add(&tbf->list, &gprs_rlcmac_tbfs);
+ exist_tbf->next_tbf = tbf;
+ return tbf;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+ }
+
+ // No UL and DL TBFs for current TLLI are found.
+ if (!exist_tbf)
+ {
+ tbf = talloc_zero(rlcmac_tall_ctx, struct gprs_rlcmac_tbf);
+ if (tbf)
+ {
+ // Create new TBF
+ tfi = tfi_alloc();
+ if (tfi < 0) {
+ return NULL;
+ }
+ tbf->tfi = tfi;
+ tbf->llc_pdus = LLIST_HEAD_INIT(tbf->llc_pdus);
+ tbf->llc_pdu_list_len = 0;
+ tbf->direction = GPRS_RLCMAC_DL_TBF;
+ tbf->stage = TBF_ESTABLISH;
+ tbf->state = CCCH_ESTABLISH;
+ tbf->tlli = tlli;
+ llist_add(&tbf->list, &gprs_rlcmac_tbfs);
+ return tbf;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+ }
+ else
+ {
+ // Uplink TBF allocation
+ tbf = talloc_zero(rlcmac_tall_ctx, struct gprs_rlcmac_tbf);
+ if (tbf)
+ {
+ // Create new TBF
+ tfi = tfi_alloc();
+ if (tfi < 0) {
+ return NULL;
+ }
+ tbf->tfi = tfi;
+ tbf->llc_pdus = LLIST_HEAD_INIT(tbf->llc_pdus);
+ tbf->llc_pdu_list_len = 0;
+ tbf->direction = GPRS_RLCMAC_UL_TBF;
+ tbf->stage = TBF_ESTABLISH;
+ tbf->state = WAIT_ESTABLISH;
+ tbf->next_tbf = NULL;
+ llist_add(&tbf->list, &gprs_rlcmac_tbfs);
+ return tbf;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+}
+
+/* Management of uplink TBF establishment. */
+int tbf_ul_establish(struct gprs_rlcmac_tbf *tbf, uint8_t ra, uint32_t Fn, uint16_t ta)
+{
+ if (tbf->direction != GPRS_RLCMAC_UL_TBF)
+ {
+ return -1;
+ }
+
+ if (tbf->stage == TBF_ESTABLISH)
+ {
+ switch (tbf->state) {
+ case WAIT_ESTABLISH:
+ {
+ LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [UPLINK] START TFI: %u\n", tbf->tfi);
+ LOGP(DRLCMAC, LOGL_NOTICE, "RX: [PCU <- BTS] TFI: %u RACH\n", tbf->tfi);
+ LOGP(DRLCMAC, LOGL_NOTICE, "TX: [PCU -> BTS] TFI: %u Packet Immidiate Assignment\n", tbf->tfi);
+ bitvec *immediate_assignment = bitvec_alloc(23);
+ bitvec_unhex(immediate_assignment, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
+ int len = write_immediate_assignment(immediate_assignment, 0, ra, Fn, ta, tbf->tfi);
+ pcu_l1if_tx(immediate_assignment, GsmL1_Sapi_Agch, len);
+ bitvec_free(immediate_assignment);
+ tbf->state = FINISH_ESTABLISH;
+ }
+ break;
+ default:
+ LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [UPLINK] TFI: %u Unexpected TBF state = %u for stage = %u \n",
+ tbf->tfi, tbf->state, tbf->stage);
+ break;
+ }
+ }
+ else
+ {
+ return -1;
+ }
- tbf->tfi = tfi;
- llist_add(&tbf->list, &gprs_rlcmac_tbfs);
+ return 1;
+}
- return tbf;
+/* Management of downlink TBF establishment. */
+int tbf_dl_establish(struct gprs_rlcmac_tbf *tbf, uint8_t *imsi)
+{
+ if (tbf->direction != GPRS_RLCMAC_DL_TBF)
+ {
+ return -1;
+ }
+
+ if (tbf->stage == TBF_ESTABLISH)
+ {
+ switch (tbf->state) {
+ case WAIT_ESTABLISH:
+ // Wait while UL TBF establishes DL TBF.
+ LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] TFI: Wait DL TBF establishment by UL TBF", tbf->tfi);
+ break;
+ case CCCH_ESTABLISH:
+ if (imsi)
+ {
+ // Downlink TBF Establishment on CCCH ( Paging procedure )
+ // TODO: Implement paging procedure on CCCH.
+ LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] TFI: Paging procedure on CCCH : Not implemented yet", tbf->tfi);
+ }
+ else
+ {
+ // Downlink TBF Establishment on CCCH ( Immediate Assignment )
+ gprs_rlcmac_downlink_assignment(tbf);
+ }
+ tbf->state = FINISH_ESTABLISH;
+ break;
+ case PACCH_ESTABLISH:
+ // Downlink TBF Establishment on PACCH ( Packet Immediate Assignment )
+ gprs_rlcmac_packet_downlink_assignment(tbf);
+ tbf->state = FINISH_ESTABLISH;
+ break;
+ default:
+ LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] TFI: %u Unexpected TBF state = %u for stage = %u \n",
+ tbf->tfi, tbf->state, tbf->stage);
+ break;
+ }
+ }
+ return 1;
}
-static void tbf_free(struct gprs_rlcmac_tbf *tbf)
+/* Management of uplink TBF data transfer. */
+int tbf_ul_data_transfer(struct gprs_rlcmac_tbf *tbf, RlcMacUplinkDataBlock_t * ul_data_block)
{
- llist_del(&tbf->list);
- talloc_free(tbf);
+ if ((tbf->stage == TBF_RELEASE)||(tbf->direction != GPRS_RLCMAC_UL_TBF))
+ {
+ return -1;
+ }
+
+ if (tbf->stage == TBF_ESTABLISH)
+ {
+ tbf->stage = TBF_DATA_TRANSFER;
+ tbf->state = WAIT_DATA_TRANSFER;
+ }
+
+ if (ul_data_block->TI == 1)
+ {
+ tbf->tlli = ul_data_block->TLLI;
+ // TODO: Kill all other UL TBFs with this TLLI.
+ }
+
+ switch (tbf->state) {
+ case WAIT_DATA_TRANSFER:
+ if (ul_data_block->BSN == 0)
+ {
+ tbf->data_index = 0;
+ gprs_rlcmac_data_block_parse(tbf, ul_data_block);
+ gprs_rlcmac_tx_ul_ack(tbf->tfi, tbf->tlli, ul_data_block);
+ if (ul_data_block->CV == 0)
+ {
+ // Recieved last Data Block in this sequence.
+ tbf->state = FINISH_DATA_TRANSFER;
+ gprs_rlcmac_tx_ul_ud(tbf);
+ }
+ else
+ {
+ tbf->bsn = ul_data_block->BSN;
+ tbf->state = DATA_TRANSFER;
+ }
+ }
+ break;
+ case DATA_TRANSFER:
+ if (tbf->bsn == (ul_data_block->BSN - 1))
+ {
+ gprs_rlcmac_data_block_parse(tbf, ul_data_block);
+ gprs_rlcmac_tx_ul_ack(tbf->tfi, tbf->tlli, ul_data_block);
+ if (ul_data_block->CV == 0)
+ {
+ // Recieved last Data Block in this sequence.
+ tbf->state = FINISH_DATA_TRANSFER;
+ gprs_rlcmac_tx_ul_ud(tbf);
+ }
+ else
+ {
+ tbf->bsn = ul_data_block->BSN;
+ }
+ }
+ break;
+ case FINISH_DATA_TRANSFER:
+ // Now we just ignore all Data Blocks and wait release of TBF.
+ break;
+ default:
+ LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [UPLINK] TFI: %u Unexpected TBF state = %u for stage = %u \n",
+ tbf->tfi, tbf->state, tbf->stage);
+ break;
+ }
+
+ if ((tbf->state == FINISH_DATA_TRANSFER) && (tbf->next_tbf))
+ {
+ // Establish DL TBF, if it is required.
+ if ((tbf->next_tbf)->state == WAIT_ESTABLISH)
+ {
+ (tbf->next_tbf)->state = PACCH_ESTABLISH;
+ tbf_dl_establish(tbf->next_tbf);
+ }
+ }
+
+ return 1;
}
+/* Management of downlink TBF data transfer. */
+int tbf_dl_data_transfer(struct gprs_rlcmac_tbf *tbf, uint8_t *llc_pdu, uint16_t llc_pdu_len)
+{
+ if ((tbf->stage == TBF_RELEASE) || (tbf->direction != GPRS_RLCMAC_DL_TBF))
+ {
+ return -1;
+ }
+
+ if (llc_pdu_len > 0)
+ {
+ tbf_add_llc_pdu(tbf, llc_pdu, llc_pdu_len);
+ }
+
+ if (tbf->stage == TBF_ESTABLISH)
+ {
+ if (tbf->state == FINISH_ESTABLISH)
+ {
+ tbf->stage = TBF_DATA_TRANSFER;
+ tbf->state = DATA_TRANSFER;
+ }
+ }
+
+ if (tbf->stage == TBF_DATA_TRANSFER)
+ {
+ switch (tbf->state) {
+ case DATA_TRANSFER:
+ gprs_rlcmac_tx_llc_pdus(tbf);
+ tbf->state = FINISH_DATA_TRANSFER;
+ break;
+ default:
+ LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] TFI: %u Unexpected TBF state = %u for stage = %u \n",
+ tbf->tfi, tbf->state, tbf->stage);
+ break;
+ }
+ }
+
+ return 1;
+}
+
+/* Management of uplink TBF release. */
+int tbf_ul_release(struct gprs_rlcmac_tbf *tbf)
+{
+ if (tbf->direction != GPRS_RLCMAC_UL_TBF)
+ {
+ return -1;
+ }
+
+ if (tbf->next_tbf)
+ {
+ // UL TBF data transfer is finished, start DL TBF data transfer.
+ tbf_dl_data_transfer(tbf->next_tbf);
+ }
+ tbf->stage = TBF_RELEASE;
+ tbf->state = RELEASE;
+ LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [UPLINK] END TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli);
+ tbf_free(tbf);
+ return 1;
+}
+
+/* Management of downlink TBF release. */
+int tbf_dl_release(struct gprs_rlcmac_tbf *tbf)
+{
+ if (tbf->direction != GPRS_RLCMAC_DL_TBF)
+ {
+ return -1;
+ }
+
+ tbf->stage = TBF_RELEASE;
+ tbf->state = RELEASE;
+ LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] END TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli);
+ tbf_free(tbf);
+ return 1;
+}
static void tbf_timer_cb(void *_tbf)
{
@@ -109,7 +478,6 @@ static void tbf_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int T,
{
if (osmo_timer_pending(&tbf->timer))
LOGP(DRLCMAC, LOGL_NOTICE, "Starting TBF timer %u while old timer %u pending \n", T, tbf->T);
-
tbf->T = T;
tbf->num_T_exp = 0;
@@ -128,11 +496,8 @@ static void tbf_gsm_timer_cb(void *_tbf)
tbf->num_fT_exp++;
switch (tbf->fT) {
- case 0:
- // This is timer for delay RLC/MAC data sending after Downlink Immediate Assignment on CCCH.
- gprs_rlcmac_segment_llc_pdu(tbf);
- LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] END TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli);
- tbf_free(tbf);
+ case 2:
+ tbf_dl_data_transfer(tbf);
break;
default:
LOGP(DRLCMAC, LOGL_NOTICE, "Timer expired in unknown mode: %u \n", tbf->fT);
@@ -256,10 +621,9 @@ void write_packet_uplink_assignment(bitvec * dest, uint8_t tfi, uint32_t tlli)
// bitvec_write_field(dest, wp,0x0,1); // Measurement Mapping struct not present
}
-
// GSM 04.08 9.1.18 Immediate assignment
int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, uint32_t fn,
- uint8_t ta, uint8_t tfi = 0, uint32_t tlli = 0)
+ uint8_t ta, uint8_t tfi, uint32_t tlli)
{
unsigned wp = 0;
@@ -524,63 +888,22 @@ void gprs_rlcmac_data_block_parse(gprs_rlcmac_tbf* tbf, RlcMacUplinkDataBlock_t
int gprs_rlcmac_rcv_data_block(bitvec *rlc_block)
{
struct gprs_rlcmac_tbf *tbf;
+ int rc = 0;
LOGP(DRLCMAC, LOGL_NOTICE, "RX: [PCU <- BTS] Uplink Data Block\n");
RlcMacUplinkDataBlock_t * ul_data_block = (RlcMacUplinkDataBlock_t *)malloc(sizeof(RlcMacUplinkDataBlock_t));
LOGP(DRLCMAC, LOGL_NOTICE, "+++++++++++++++++++++++++ RX : Uplink Data Block +++++++++++++++++++++++++\n");
decode_gsm_rlcmac_uplink_data(rlc_block, ul_data_block);
LOGP(DRLCMAC, LOGL_NOTICE, "------------------------- RX : Uplink Data Block -------------------------\n");
- tbf = tbf_by_tfi(ul_data_block->TFI);
- if (!tbf) {
- return 0;
- }
- if (ul_data_block->TI == 1)
- {
- tbf->tlli = ul_data_block->TLLI;
- }
-
- switch (tbf->state) {
- case GPRS_RLCMAC_WAIT_DATA_SEQ_START:
- if (ul_data_block->BSN == 0) {
- tbf->data_index = 0;
- gprs_rlcmac_data_block_parse(tbf, ul_data_block);
- gprs_rlcmac_tx_ul_ack(tbf->tfi, tbf->tlli, ul_data_block);
- if (ul_data_block->CV == 0) {
- // Recieved last Data Block in this sequence.
- tbf->state = GPRS_RLCMAC_WAIT_NEXT_DATA_SEQ;
- gprs_rlcmac_tx_ul_ud(tbf);
- } else {
- tbf->bsn = ul_data_block->BSN;
- tbf->state = GPRS_RLCMAC_WAIT_NEXT_DATA_BLOCK;
- }
- }
- break;
- case GPRS_RLCMAC_WAIT_NEXT_DATA_BLOCK:
- if (tbf->bsn == (ul_data_block->BSN - 1)) {
- gprs_rlcmac_data_block_parse(tbf, ul_data_block);
- gprs_rlcmac_tx_ul_ack(tbf->tfi, tbf->tlli, ul_data_block);
- if (ul_data_block->CV == 0) {
- // Recieved last Data Block in this sequence.
- tbf->state = GPRS_RLCMAC_WAIT_NEXT_DATA_SEQ;
- gprs_rlcmac_tx_ul_ud(tbf);
- } else {
- tbf->bsn = ul_data_block->BSN;
- tbf->state = GPRS_RLCMAC_WAIT_NEXT_DATA_BLOCK;
- }
- } else {
- // Recieved Data Block with unexpected BSN.
- // We should try to find nesessary Data Block.
- tbf->state = GPRS_RLCMAC_WAIT_NEXT_DATA_BLOCK;
- }
- break;
- case GPRS_RLCMAC_WAIT_NEXT_DATA_SEQ:
- // Now we just ignore all Data Blocks and wait next Uplink TBF
- break;
+ tbf = tbf_by_tfi(ul_data_block->TFI, GPRS_RLCMAC_UL_TBF);
+ if (!tbf) {
+ return -1;
}
-
+
+ rc = tbf_ul_data_transfer(tbf, ul_data_block);
free(ul_data_block);
- return 1;
+ return rc;
}
/* Received Uplink RLC control block. */
@@ -589,7 +912,6 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block)
uint8_t tfi = 0;
uint32_t tlli = 0;
struct gprs_rlcmac_tbf *tbf;
- struct gprs_rlcmac_tbf *ul_tbf;
RlcMacUplink_t * ul_control_block = (RlcMacUplink_t *)malloc(sizeof(RlcMacUplink_t));
LOGP(DRLCMAC, LOGL_NOTICE, "+++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++\n");
@@ -599,24 +921,21 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block)
switch (ul_control_block->u.MESSAGE_TYPE) {
case MT_PACKET_CONTROL_ACK:
tlli = ul_control_block->u.Packet_Control_Acknowledgement.TLLI;
- tbf = tbf_by_tlli(tlli);
+ tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF);
if (!tbf) {
return 0;
}
LOGP(DRLCMAC, LOGL_NOTICE, "RX: [PCU <- BTS] TFI: %u TLLI: 0x%08x Packet Control Ack\n", tbf->tfi, tbf->tlli);
- LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [UPLINK] END TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli);
- tbf_free(tbf);
+ tbf_ul_release(tbf);
break;
case MT_PACKET_DOWNLINK_ACK_NACK:
tfi = ul_control_block->u.Packet_Downlink_Ack_Nack.DOWNLINK_TFI;
- tbf = tbf_by_tfi(tfi);
+ tbf = tbf_by_tfi(tfi, GPRS_RLCMAC_DL_TBF);
if (!tbf) {
return 0;
}
LOGP(DRLCMAC, LOGL_NOTICE, "RX: [PCU <- BTS] TFI: %u TLLI: 0x%08x Packet Downlink Ack/Nack\n", tbf->tfi, tbf->tlli);
- tlli = tbf->tlli;
- LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] END TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli);
- tbf_free(tbf);
+ tbf_dl_release(tbf);
break;
}
free(ul_control_block);
@@ -646,139 +965,116 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, uint16_t ta)
{
struct gprs_rlcmac_tbf *tbf;
- // Create new TBF
- int tfi = tfi_alloc();
- if (tfi < 0) {
- return tfi;
- }
- tbf = tbf_alloc(tfi);
- tbf->direction = GPRS_RLCMAC_UL_TBF;
- tbf->state = GPRS_RLCMAC_WAIT_DATA_SEQ_START;
- LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [UPLINK] START TFI: %u\n", tbf->tfi);
- LOGP(DRLCMAC, LOGL_NOTICE, "RX: [PCU <- BTS] TFI: %u RACH\n", tbf->tfi);
- LOGP(DRLCMAC, LOGL_NOTICE, "TX: [PCU -> BTS] TFI: %u Packet Immidiate Assignment\n", tbf->tfi);
- bitvec *immediate_assignment = bitvec_alloc(23);
- bitvec_unhex(immediate_assignment, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
- int len = write_immediate_assignment(immediate_assignment, 0, ra, Fn, ta, tbf->tfi);
- pcu_l1if_tx(immediate_assignment, GsmL1_Sapi_Agch, len);
- bitvec_free(immediate_assignment);
-}
+ static uint8_t prev_ra = 0;
-// Send RLC data to OpenBTS.
-void gprs_rlcmac_tx_dl_data_block(uint32_t tlli, uint8_t tfi, uint8_t *pdu, int start_index, int end_index, uint8_t bsn, uint8_t fbi)
-{
- int spare_len = 0;
- bitvec *data_block_vector = bitvec_alloc(BLOCK_LEN);
- bitvec_unhex(data_block_vector, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
- RlcMacDownlinkDataBlock_t * data_block = (RlcMacDownlinkDataBlock_t *)malloc(sizeof(RlcMacDownlinkDataBlock_t));
- data_block->PAYLOAD_TYPE = 0;
- data_block->RRBP = 0;
- data_block->SP = 1;
- data_block->USF = 1;
- data_block->PR = 0;
- data_block->TFI = tfi;
- data_block->FBI = fbi;
- data_block->BSN = bsn;
-
- // Last RLC data block of current LLC PDU
- if (fbi == 1)
+ if (prev_ra == ra)
{
- data_block->E_1 = 0;
- data_block->M[0] = 0;
- data_block->E[0] = 1;
- // Singular case, TS 44.060 10.4.14
- if ((end_index - start_index) == (BLOCK_LEN - 3))
- {
- data_block->FBI = 0;
- data_block->LENGTH_INDICATOR[0] = 0;
- spare_len = 0;
- end_index--;
- }
- else
- {
- data_block->LENGTH_INDICATOR[0] = end_index-start_index;
- spare_len = BLOCK_LEN - 4 - data_block->LENGTH_INDICATOR[0];
- }
- }
- else
- {
- data_block->E_1 = 1;
- }
-
- int data_oct_num = 0;
- int i = 0;
- // Pack LLC PDU into RLC data field
- for(i = start_index; i < end_index; i++) {
- data_block->RLC_DATA[data_oct_num] = pdu[i];
- data_oct_num++;
- }
- // Fill spare bits
- for(i = data_oct_num; i < data_oct_num + spare_len; i++) {
- data_block->RLC_DATA[i] = 0x2b;
- }
- LOGP(DRLCMAC, LOGL_NOTICE, "TX: [PCU -> BTS] Downlink Data Block\n");
- LOGP(DRLCMAC, LOGL_NOTICE, "+++++++++++++++++++++++++ TX : Downlink Data Block +++++++++++++++++++++++++\n");
- encode_gsm_rlcmac_downlink_data(data_block_vector, data_block);
- LOGP(DRLCMAC, LOGL_NOTICE, "------------------------- TX : Downlink Data Block -------------------------\n");
- free(data_block);
- pcu_l1if_tx(data_block_vector, GsmL1_Sapi_Pdtch);
- bitvec_free(data_block_vector);
-
- // Singular case, TS 44.060 10.4.14
- if ((fbi == 1)&&((end_index + 1 - start_index) == (BLOCK_LEN - 3)))
- {
- gprs_rlcmac_tx_dl_data_block(tlli, tfi, pdu, end_index, end_index+1, bsn+1, fbi);
+ return -1;
}
+
+ tbf = tbf_alloc(GPRS_RLCMAC_UL_TBF);
+
+ return tbf_ul_establish(tbf, ra, Fn, ta);
}
-int gprs_rlcmac_segment_llc_pdu(struct gprs_rlcmac_tbf *tbf)
+int gprs_rlcmac_tx_llc_pdus(struct gprs_rlcmac_tbf *tbf)
{
int fbi = 0;
int bsn = 0;
- int num_blocks = 0; // number of RLC data blocks necessary for LLC PDU transmission
- // LLC PDU fits into one RLC data block with optional LI field.
- if (tbf->data_index < BLOCK_LEN - 4)
+ if (tbf->llc_pdu_list_len == 0)
{
- fbi = 1;
- gprs_rlcmac_tx_dl_data_block(tbf->tlli, tbf->tfi, tbf->rlc_data, 0, tbf->data_index, bsn, fbi);
+ return -1;
}
- // Necessary several RLC data blocks for transmit LLC PDU.
- else
+
+ bitvec *data_block_vector = bitvec_alloc(BLOCK_LEN);
+ bitvec_unhex(data_block_vector, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
+ RlcMacDownlinkDataBlock_t * data_block = (RlcMacDownlinkDataBlock_t *)malloc(sizeof(RlcMacDownlinkDataBlock_t));
+
+ struct tbf_llc_pdu *llc_pdu;
+
+ int data_block_ready = 0;
+ unsigned data_oct_num = 0;
+ int llc_pdu_index;
+ for (unsigned i = 0; i < tbf->llc_pdu_list_len; i++)
{
- // length of RLC data field in block (no optional octets)
- int block_data_len = BLOCK_LEN - 3;
-
- // number of blocks with 20 octets length RLC data field
- num_blocks = tbf->data_index/block_data_len;
-
- // rest of LLC PDU, which doesn't fit into data blocks with 20 octets RLC data field
- int rest_len = tbf->data_index%BLOCK_DATA_LEN;
- if (rest_len > 0)
+ llc_pdu = tbf_llc_pdu_by_num(tbf->llc_pdus, i);
+ if (!llc_pdu)
{
- // add one block for transmission rest of LLC PDU
- num_blocks++;
+ return -1;
}
- int start_index = 0;
- int end_index = 0;
+ llc_pdu_index = 0;
- // Transmit all RLC data blocks of current LLC PDU to MS
- for (bsn = 0; bsn < num_blocks; bsn++)
+ do
{
- if (bsn == num_blocks-1)
+ data_block->PAYLOAD_TYPE = 0;
+ data_block->RRBP = 0;
+ data_block->SP = 1;
+ data_block->USF = 1;
+ data_block->PR = 0;
+ data_block->TFI = tbf->tfi;
+ data_block->BSN = bsn;
+
+ // Write LLC PDU to Data Block
+ int j;
+ for(j = llc_pdu_index; j < llc_pdu->len; j++)
{
- if (rest_len > 0)
+ data_block->RLC_DATA[data_oct_num] = llc_pdu->data[j];
+ data_oct_num++;
+ llc_pdu_index++;
+ // RLC data field is completely filled.
+ if (data_oct_num == BLOCK_LEN - 3)
{
- block_data_len = rest_len;
+ fbi = 0;
+ data_block->E_1 = 1;
+ data_block_ready = 1;
+ break;
}
- fbi = 1;
}
- end_index = start_index + block_data_len;
- gprs_rlcmac_tx_dl_data_block(tbf->tlli, tbf->tfi, tbf->rlc_data, start_index, end_index, bsn, fbi);
- start_index += block_data_len;
+ if(!data_block_ready)
+ {
+ data_block->E_1 = 0;
+ data_block->LENGTH_INDICATOR[0] = data_oct_num;
+ if ((i+1) == tbf->llc_pdu_list_len)
+ {
+ // Current LLC PDU is last in TBF.
+ data_block->M[0] = 0;
+ data_block->E[0] = 1;
+ fbi = 1;
+ for(unsigned k = data_oct_num; k < BLOCK_LEN - 4; k++)
+ {
+ data_block->RLC_DATA[k] = 0x2b;
+ }
+ data_block_ready = 1;
+ }
+ else
+ {
+ // More LLC PDUs should be transmited in this TBF.
+ data_block->M[0] = 1;
+ data_block->E[0] = 1;
+ data_block_ready = 1;
+ break;
+ }
+ }
+
+ data_block->FBI = fbi;
+
+ if(data_block_ready)
+ {
+ LOGP(DRLCMAC, LOGL_NOTICE, "TX: [PCU -> BTS] Downlink Data Block\n");
+ LOGP(DRLCMAC, LOGL_NOTICE, "+++++++++++++++++++++++++ TX : Downlink Data Block +++++++++++++++++++++++++\n");
+ encode_gsm_rlcmac_downlink_data(data_block_vector, data_block);
+ LOGP(DRLCMAC, LOGL_NOTICE, "------------------------- TX : Downlink Data Block -------------------------\n");
+ pcu_l1if_tx(data_block_vector, GsmL1_Sapi_Pdtch);
+ bitvec_unhex(data_block_vector, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
+ bsn++;
+ data_block_ready = 0;
+ data_oct_num = 0;
+ }
}
+ while(llc_pdu->len != llc_pdu_index);
}
}
@@ -815,7 +1111,6 @@ void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf)
int len = write_immediate_assignment(immediate_assignment, 1, 125, get_current_fn(), (l1fh->fl1h)->channel_info.ta, tbf->tfi, tbf->tlli);
pcu_l1if_tx(immediate_assignment, GsmL1_Sapi_Agch, len);
bitvec_free(immediate_assignment);
- tbf_gsm_timer_start(tbf, 0, 120);
}
void gprs_rlcmac_packet_downlink_assignment(gprs_rlcmac_tbf *tbf)
@@ -833,5 +1128,4 @@ void gprs_rlcmac_packet_downlink_assignment(gprs_rlcmac_tbf *tbf)
free(packet_downlink_assignment);
pcu_l1if_tx(packet_downlink_assignment_vec, GsmL1_Sapi_Pacch);
bitvec_free(packet_downlink_assignment_vec);
- tbf_gsm_timer_start(tbf, 0, 120);
}
diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h
index eb651c61..7f9e3d7d 100644
--- a/src/gprs_rlcmac.h
+++ b/src/gprs_rlcmac.h
@@ -32,10 +32,21 @@ extern "C" {
#define LLC_MAX_LEN 1543
#define UL_RLC_DATA_BLOCK_LEN 23
+enum gprs_rlcmac_tbf_stage {
+ TBF_ESTABLISH,
+ TBF_DATA_TRANSFER,
+ TBF_RELEASE
+};
+
enum gprs_rlcmac_tbf_state {
- GPRS_RLCMAC_WAIT_DATA_SEQ_START,
- GPRS_RLCMAC_WAIT_NEXT_DATA_BLOCK,
- GPRS_RLCMAC_WAIT_NEXT_DATA_SEQ
+ WAIT_ESTABLISH,
+ CCCH_ESTABLISH,
+ PACCH_ESTABLISH,
+ FINISH_ESTABLISH,
+ WAIT_DATA_TRANSFER,
+ DATA_TRANSFER,
+ FINISH_DATA_TRANSFER,
+ RELEASE
};
enum gprs_rlcmac_tbf_direction {
@@ -43,12 +54,25 @@ enum gprs_rlcmac_tbf_direction {
GPRS_RLCMAC_UL_TBF
};
+struct tbf_llc_pdu {
+ struct llist_head list;
+ uint8_t num;
+ uint8_t data[LLC_MAX_LEN];
+ uint16_t len;
+};
+
struct gprs_rlcmac_tbf {
struct llist_head list;
enum gprs_rlcmac_tbf_state state;
+ enum gprs_rlcmac_tbf_stage stage;
enum gprs_rlcmac_tbf_direction direction;
+ struct gprs_rlcmac_tbf *next_tbf;
uint8_t tfi;
uint32_t tlli;
+
+ struct llist_head llc_pdus;
+ struct tbf_llc_pdu llc_pdu;
+ uint8_t llc_pdu_list_len;
uint8_t rlc_data[LLC_MAX_LEN];
uint16_t data_index;
uint8_t bsn;
@@ -62,25 +86,47 @@ struct gprs_rlcmac_tbf {
unsigned int num_fT_exp; /* number of consecutive fT expirations */
};
+/* TS 44.060 Section 10.4.7 Table 10.4.7.1: Payload Type field */
+enum gprs_rlcmac_block_type {
+ GPRS_RLCMAC_DATA_BLOCK = 0x0,
+ GPRS_RLCMAC_CONTROL_BLOCK = 0x1,
+ GPRS_RLCMAC_CONTROL_BLOCK_OPT = 0x2,
+ GPRS_RLCMAC_RESERVED = 0x3
+};
+
extern struct llist_head gprs_rlcmac_tbfs;
int tfi_alloc();
-struct gprs_rlcmac_tbf *tbf_alloc(uint8_t tfi);
+static struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, gprs_rlcmac_tbf_direction dir);
-static struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi);
-
-static struct gprs_rlcmac_tbf *tbf_by_tlli(uint8_t tlli);
+static struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, gprs_rlcmac_tbf_direction dir);
static void tbf_free(struct gprs_rlcmac_tbf *tbf);
-/* TS 44.060 Section 10.4.7 Table 10.4.7.1: Payload Type field */
-enum gprs_rlcmac_block_type {
- GPRS_RLCMAC_DATA_BLOCK = 0x0,
- GPRS_RLCMAC_CONTROL_BLOCK = 0x1,
- GPRS_RLCMAC_CONTROL_BLOCK_OPT = 0x2,
- GPRS_RLCMAC_RESERVED = 0x3
-};
+static struct tbf_llc_pdu *tbf_llc_pdu_by_num(struct llist_head llc_pdus, uint8_t num);
+
+int tbf_add_llc_pdu(struct gprs_rlcmac_tbf *tbf, uint8_t *data, uint16_t llc_pdu_len);
+
+struct gprs_rlcmac_tbf *tbf_alloc(gprs_rlcmac_tbf_direction dir, uint32_t tlli = 0);
+
+int tbf_ul_establish(struct gprs_rlcmac_tbf *tbf, uint8_t ra, uint32_t Fn, uint16_t ta);
+
+int tbf_dl_establish(struct gprs_rlcmac_tbf *tbf, uint8_t *imsi = NULL);
+
+int tbf_ul_data_transfer(struct gprs_rlcmac_tbf *tbf, RlcMacUplinkDataBlock_t * ul_data_block);
+
+int tbf_dl_data_transfer(struct gprs_rlcmac_tbf *tbf, uint8_t *llc_pdu = NULL, uint16_t llc_pdu_len = 0);
+
+int tbf_ul_release(struct gprs_rlcmac_tbf *tbf);
+
+int tbf_dl_release(struct gprs_rlcmac_tbf *tbf);
+
+static void tbf_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int T, unsigned int seconds);
+
+static void tbf_gsm_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int fT, int frames);
+
+int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, uint32_t fn, uint8_t ta, uint8_t tfi, uint32_t tlli = 0);
void gprs_rlcmac_tx_ul_ack(uint8_t tfi, uint32_t tlli, RlcMacUplinkDataBlock_t * ul_data_block);
@@ -94,9 +140,7 @@ void gprs_rlcmac_rcv_block(bitvec *rlc_block);
int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, uint16_t ta);
-void gprs_rlcmac_tx_dl_data_block(uint32_t tlli, uint8_t tfi, uint8_t *pdu, int start_index, int end_index, uint8_t bsn, uint8_t fbi);
-
-int gprs_rlcmac_segment_llc_pdu(struct gprs_rlcmac_tbf *tbf);
+int gprs_rlcmac_tx_llc_pdus(struct gprs_rlcmac_tbf *tbf);
void gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf);
@@ -104,5 +148,4 @@ void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf);
void gprs_rlcmac_packet_downlink_assignment(gprs_rlcmac_tbf *tbf);
-
#endif // GPRS_RLCMAC_H