diff options
author | Andreas Eversberg <jolly@eversberg.eu> | 2012-07-03 13:36:03 +0200 |
---|---|---|
committer | Andreas Eversberg <jolly@eversberg.eu> | 2012-07-03 13:36:03 +0200 |
commit | e6228b34a75efcb6b0700ac29672d62539860fbf (patch) | |
tree | fb63787c14638347a13c6e42b203ae956e23c5e5 /src | |
parent | 83ced4978ab2d58a4b8bf68be922adc0671db747 (diff) |
TBF acknowledged mode finished for both link directions
Diffstat (limited to 'src')
-rw-r--r-- | src/gprs_bssgp_pcu.cpp | 78 | ||||
-rw-r--r-- | src/gprs_debug.cpp | 6 | ||||
-rw-r--r-- | src/gprs_debug.h | 2 | ||||
-rw-r--r-- | src/gprs_rlcmac.cpp | 850 | ||||
-rw-r--r-- | src/gprs_rlcmac.h | 130 | ||||
-rw-r--r-- | src/gprs_rlcmac_data.cpp | 1106 | ||||
-rw-r--r-- | src/gprs_rlcmac_sched.cpp | 76 | ||||
-rw-r--r-- | src/pcu_l1_if.cpp | 4 | ||||
-rw-r--r-- | src/pcu_l1_if.h | 1 | ||||
-rw-r--r-- | src/pcu_main.cpp | 1 | ||||
-rw-r--r-- | src/sysmo_l1_if.cpp | 51 | ||||
-rw-r--r-- | src/tbf.txt | 111 |
12 files changed, 1618 insertions, 798 deletions
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index 85fef64d..8d391f23 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -29,40 +29,31 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) { struct bssgp_ud_hdr *budh; int tfi; + uint32_t tlli; int i = 0; uint8_t trx, ts; + uint8_t *data; + uint16_t len; + struct gprs_rlcmac_tbf *tbf; budh = (struct bssgp_ud_hdr *)msgb_bssgph(msg); - struct gprs_rlcmac_tbf *tbf; - // Create new TBF - tfi = tfi_alloc(&trx, &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; - tbf->state = GPRS_RLCMAC_FLOW; - tbf->tlli = ntohl(budh->tlli); - LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] START TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli); + tlli = ntohl(budh->tlli); /* LLC_PDU is mandatory IE */ if (!TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU)) { - LOGP(DBSSGP, LOGL_ERROR, "BSSGP TLLI=0x%08x Rx UL-UD missing mandatory IE\n", tbf->tlli); + LOGP(DBSSGP, LOGL_ERROR, "BSSGP TLLI=0x%08x Rx UL-UD missing mandatory IE\n", tlli); 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->llc_index = TLVP_LEN(tp, BSSGP_IE_LLC_PDU); - - LOGP(DBSSGP, LOGL_NOTICE, "LLC PDU = "); - for (i = 0; i < tbf->llc_index; i++) + data = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_LLC_PDU); + len = TLVP_LEN(tp, BSSGP_IE_LLC_PDU); + if (len > sizeof(tbf->llc_frame)) { - tbf->llc_frame[i] = llc_pdu[i]; - LOGPC(DBSSGP, LOGL_NOTICE, "%02x", tbf->llc_frame[i]); + LOGP(DBSSGP, LOGL_ERROR, "BSSGP TLLI=0x%08x Rx UL-UD IE_LLC_PDU too large\n", tlli); + return bssgp_tx_status(BSSGP_CAUSE_COND_IE_ERR, NULL, msg); } + LOGP(DBSSGP, LOGL_NOTICE, "LLC PDU = (TLLI=0x%08x) %s\n", tlli, osmo_hexdump(data, len)); uint16_t imsi_len = 0; uint8_t *imsi; @@ -79,7 +70,50 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) LOGPC(DBSSGP, LOGL_NOTICE, "\n"); } - gprs_rlcmac_packet_downlink_assignment(tbf); + /* check for existing TBF */ + if ((tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_DL_TBF))) { + LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] APPEND TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli); + if (tbf->state == GPRS_RLCMAC_WAIT_RELEASE) { + LOGP(DRLCMAC, LOGL_NOTICE, "TBF in WAIT RELEASE state " + "(T3193), so reuse TBF\n"); + memcpy(tbf->llc_frame, data, len); + tbf->llc_length = len; + memset(&tbf->dir.dl, 0, sizeof(tbf->dir.dl)); /* reset + rlc states */ + gprs_rlcmac_trigger_downlink_assignment(tbf, 1); + } else { + /* the TBF exists, so we must write it in the queue */ + struct msgb *llc_msg = msgb_alloc(len, "llc_pdu_queue"); + if (!llc_msg) + return -ENOMEM; + memcpy(msgb_put(llc_msg, len), data, len); + msgb_enqueue(&tbf->llc_queue, llc_msg); + } + } else { + // Create new TBF + tfi = tfi_alloc(&trx, &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; + tbf->tlli = tlli; + tbf->tlli_valid = 1; + + LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] START TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli); + + /* new TBF, so put first frame */ + memcpy(tbf->llc_frame, data, len); + tbf->llc_length = len; + + /* trigger downlink assignment and set state to ASSIGN. + * we don't use old_downlink, so the possible uplink is used + * to trigger downlink assignment. if there is no uplink, + * AGCH is used. */ + gprs_rlcmac_trigger_downlink_assignment(tbf, 0); + } return 0; } diff --git a/src/gprs_debug.cpp b/src/gprs_debug.cpp index 6bf472f6..4bb9107a 100644 --- a/src/gprs_debug.cpp +++ b/src/gprs_debug.cpp @@ -37,8 +37,10 @@ static const struct log_info_cat default_categories[] = { {"DCSN1", "\033[1;31m", "Concrete Syntax Notation One (CSN1)", LOGL_NOTICE, 1}, {"DL1IF", "\033[1;32m", "GPRS PCU L1 interface (L1IF)", LOGL_NOTICE, 1}, - {"DRLCMAC", "\033[1;33m", "GPRS RLC/MAC layer (RLCMAC)", LOGL_DEBUG, 1}, - {"DRLCMACDATA", "\033[1;36m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMAC", "\033[0;33m", "GPRS RLC/MAC layer (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACDATA", "\033[0;33m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACDL", "\033[1;33m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_DEBUG, 1}, + {"DRLCMACUL", "\033[1;36m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_DEBUG, 1}, {"DRLCMACSCHED", "\033[0;36m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_DEBUG, 1}, {"DBSSGP", "\033[1;34m", "GPRS BSS Gateway Protocol (BSSGP)", LOGL_NOTICE , 1}, {"DPCU", "\033[1;35m", "GPRS Packet Control Unit (PCU)", LOGL_NOTICE, 1}, diff --git a/src/gprs_debug.h b/src/gprs_debug.h index 5d0c6042..b5b42767 100644 --- a/src/gprs_debug.h +++ b/src/gprs_debug.h @@ -31,6 +31,8 @@ enum { DL1IF, DRLCMAC, DRLCMACDATA, + DRLCMACDL, + DRLCMACUL, DRLCMACSCHED, DBSSGP, DPCU, diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index 3353462e..a9f4d134 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -25,7 +25,6 @@ LLIST_HEAD(gprs_rlcmac_tbfs); void *rlcmac_tall_ctx; -LLIST_HEAD(block_queue); /* FIXME: spread ressources on multiple TRX */ int tfi_alloc(uint8_t *_trx, uint8_t *_ts) @@ -104,22 +103,40 @@ int find_free_usf(uint8_t trx, uint8_t ts) /* 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) +struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, int direction) { struct gprs_rlcmac_tbf *tbf; llist_for_each_entry(tbf, &gprs_rlcmac_tbfs, list) { - if (tbf->tfi == tfi) + if (tbf->state != GPRS_RLCMAC_RELEASING + && tbf->tfi == tfi + && tbf->direction == direction) return tbf; } return NULL; } -struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli) +/* search for active downlink or uplink tbf */ +struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, int direction) { 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->state != GPRS_RLCMAC_RELEASING + && tbf->tlli == tlli + && tbf->direction == direction) + 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; + llist_for_each_entry(tbf, &gprs_rlcmac_tbfs, list) { + if (tbf->state != GPRS_RLCMAC_RELEASING + && tbf->poll_state == GPRS_RLCMAC_POLL_SCHED + && tbf->poll_fn == fn) return tbf; } return NULL; @@ -147,8 +164,10 @@ struct gprs_rlcmac_tbf *tbf_alloc(uint8_t tfi, uint8_t trx, uint8_t ts) tbf->ts = ts; tbf->arfcn = bts->trx[trx].arfcn; tbf->tsc = bts->trx[trx].pdch[ts].tsc; + tbf->pdch = pdch; tbf->ws = 64; tbf->sns = 128; + INIT_LLIST_HEAD(&tbf->llc_queue); llist_add(&tbf->list, &gprs_rlcmac_tbfs); pdch->tbf[tfi] = tbf; @@ -159,62 +178,46 @@ void tbf_free(struct gprs_rlcmac_tbf *tbf) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_pdch *pdch; + struct msgb *msg; - LOGP(DRLCMAC, LOGL_INFO, "Free TBF with TFI=%d.\n", tbf->tfi); - LOGP(DRLCMAC, LOGL_INFO, "********** TBF ends here **********\n"); + LOGP(DRLCMAC, LOGL_INFO, "Free TBF=%d with TLLI=0x%08x.\n", tbf->tfi, + tbf->tlli); 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; llist_del(&tbf->list); + LOGP(DRLCMAC, LOGL_INFO, "********** TBF ends here **********\n"); talloc_free(tbf); } - -static void tbf_timer_cb(void *_tbf) +const char *tbf_state_name[] = { + "NULL", + "ASSIGN", + "FLOW", + "FINISHED", + "WAIT RELEASE", + "RELEASING", +}; + +void tbf_new_state(struct gprs_rlcmac_tbf *tbf, + enum gprs_rlcmac_tbf_state state) { - struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)_tbf; - - LOGP(DRLCMAC, LOGL_DEBUG, "TBF timer %u expired.\n", tbf->T); - - tbf->num_T_exp++; - - switch (tbf->T) { - case 3169: - LOGP(DRLCMAC, LOGL_DEBUG, "TBF will be freed due to timeout\n"); - /* free TBF */ - tbf_free(tbf); - break; - case 3103: - if (++tbf->dir.ul.n3103 == N3103_MAX) { - LOGP(DRLCMAC, LOGL_DEBUG, "Final ACK will be resent " - "due to timeout\n"); - /* timeout for polling with final ack message, */ - /* trigger sending at next RTS */ - tbf->dir.ul.substate = GPRS_RLCMAC_UL_SEND_ACK; - } else { - LOGP(DRLCMAC, LOGL_DEBUG, "Too many timeouts on final " - "ACK, starting T3169\n"); - /* restart T3169, so we can be sure that after expiry, - * the mobile has timed out and wiil not transmit - * anymore */ - tbf->state = GPRS_RLCMAC_RELEASING; - tbf_timer_start(tbf, 3169, T3169); - } - break; - default: - LOGP(DRLCMAC, LOGL_ERROR, "Timer expired in unknown mode: %u\n", - tbf->T); - } + LOGP(DRLCMAC, LOGL_INFO, "TBF=%d changes state from %s to %s\n", + tbf->tfi, tbf_state_name[tbf->state], tbf_state_name[state]); + tbf->state = state; } void tbf_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int T, - unsigned int seconds) + unsigned int seconds, unsigned int microseconds) { if (!osmo_timer_pending(&tbf->timer)) - LOGP(DRLCMAC, LOGL_DEBUG, "Starting TBF timer %u.\n", T); + LOGP(DRLCMAC, LOGL_DEBUG, "Starting TBF=%d timer %u.\n", + tbf->tfi, T); else - LOGP(DRLCMAC, LOGL_DEBUG, "Restarting TBF timer %u while old " - "timer %u pending \n", T, tbf->T); + LOGP(DRLCMAC, LOGL_DEBUG, "Restarting TBF=%d timer %u while " + "old timer %u pending \n", tbf->tfi, T, tbf->T); tbf->T = T; tbf->num_T_exp = 0; @@ -223,17 +226,19 @@ void tbf_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int T, tbf->timer.data = tbf; tbf->timer.cb = &tbf_timer_cb; - osmo_timer_schedule(&tbf->timer, seconds, 0); + osmo_timer_schedule(&tbf->timer, seconds, microseconds); } void tbf_timer_stop(struct gprs_rlcmac_tbf *tbf) { if (osmo_timer_pending(&tbf->timer)) { - LOGP(DRLCMAC, LOGL_DEBUG, "Stopping TBF timer %u.\n", tbf->T); + LOGP(DRLCMAC, LOGL_DEBUG, "Stopping TBF=%d timer %u.\n", + tbf->tfi, tbf->T); osmo_timer_del(&tbf->timer); } } +#if 0 static void tbf_gsm_timer_cb(void *_tbf) { struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)_tbf; @@ -242,6 +247,7 @@ static void tbf_gsm_timer_cb(void *_tbf) switch (tbf->fT) { case 0: +hier alles überdenken // 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); @@ -267,114 +273,53 @@ static void tbf_gsm_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int fT, osmo_gsm_timer_schedule(&tbf->gsm_timer, frames); } +eine stop-funktion, auch im tbf_free aufrufen + +#endif + +#if 0 void gprs_rlcmac_enqueue_block(bitvec *block, int len) { struct msgb *msg = msgb_alloc(len, "rlcmac_dl"); bitvec_pack(block, msgb_put(msg, len)); msgb_enqueue(&block_queue, msg); } +#endif -void write_packet_downlink_assignment(bitvec * dest, uint8_t tfi, uint32_t tlli, uint16_t arfcn, uint8_t tn, uint8_t ta, uint8_t tsc) -{ - // TODO We should use our implementation of encode RLC/MAC Control messages. - unsigned wp = 0; - int i; - bitvec_write_field(dest, wp,0x1,2); // Payload Type - bitvec_write_field(dest, wp,0x0,2); // Uplink block with TDMA framenumber - bitvec_write_field(dest, wp,0x1,1); // Suppl/Polling Bit - bitvec_write_field(dest, wp,0x1,3); // Uplink state flag - bitvec_write_field(dest, wp,0x2,6); // MESSAGE TYPE - bitvec_write_field(dest, wp,0x0,2); // Page Mode - - bitvec_write_field(dest, wp,0x0,1); // switch PERSIST_LEVEL: off - bitvec_write_field(dest, wp,0x0,1); // switch TFI : on - bitvec_write_field(dest, wp,0x0,1); // switch UPLINK TFI : on - bitvec_write_field(dest, wp,tfi-1,5); // TFI - - bitvec_write_field(dest, wp,0x0,1); // Message escape - bitvec_write_field(dest, wp,0x0,2); // Medium Access Method: Dynamic Allocation - bitvec_write_field(dest, wp,0x0,1); // RLC acknowledged mode - - bitvec_write_field(dest, wp,0x0,1); // the network establishes no new downlink TBF for the mobile station - bitvec_write_field(dest, wp,0x80 >> tn,8); // timeslot(s) - - 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,0x0,1); // switch TIMING_ADVANCE_INDEX = off - - bitvec_write_field(dest, wp,0x0,1); // switch POWER CONTROL = off - bitvec_write_field(dest, wp,0x1,1); // Frequency Parameters information elements = present - - bitvec_write_field(dest, wp,tsc,3); // Training Sequence Code (TSC) = 2 - bitvec_write_field(dest, wp,0x0,2); // ARFCN = present - bitvec_write_field(dest, wp,arfcn,10); // ARFCN - - bitvec_write_field(dest, wp,0x1,1); // switch TFI : on - bitvec_write_field(dest, wp,tfi,5);// TFI - - bitvec_write_field(dest, wp,0x1,1); // Power Control Parameters IE = present - bitvec_write_field(dest, wp,0x0,4); // ALPHA power control parameter - for (i = 0; i < 8; i++) - bitvec_write_field(dest, wp,(tn == i),1); // switch GAMMA_TN[i] = on or off - bitvec_write_field(dest, wp,0x0,5); // GAMMA_TN[tn] - - bitvec_write_field(dest, wp,0x0,1); // TBF Starting TIME IE not present - bitvec_write_field(dest, wp,0x0,1); // Measurement Mapping struct not present - bitvec_write_field(dest, wp,0x0,1); -} - -void write_packet_uplink_assignment(bitvec * dest, uint8_t tfi, uint32_t tlli) +/* received RLC/MAC block from L1 */ +int gprs_rlcmac_rcv_block(uint8_t *data, uint8_t len, uint32_t fn) { - // TODO We should use our implementation of encode RLC/MAC Control messages. - unsigned wp = 0; - bitvec_write_field(dest, wp,0x1,2); // Payload Type - bitvec_write_field(dest, wp,0x0,2); // Uplink block with TDMA framenumber - bitvec_write_field(dest, wp,0x1,1); // Suppl/Polling Bit - bitvec_write_field(dest, wp,0x1,3); // Uplink state flag - - - bitvec_write_field(dest, wp,0xa,6); // MESSAGE TYPE - - bitvec_write_field(dest, wp,0x0,2); // Page Mode - - bitvec_write_field(dest, wp,0x0,1); // switch PERSIST_LEVEL: off - bitvec_write_field(dest, wp,0x2,2); // switch TLLI : on - bitvec_write_field(dest, wp,tlli,32); // TLLI - - bitvec_write_field(dest, wp,0x0,1); // Message escape - bitvec_write_field(dest, wp,0x0,2); // CHANNEL_CODING_COMMAND - bitvec_write_field(dest, wp,0x0,1); // TLLI_BLOCK_CHANNEL_CODING - - bitvec_write_field(dest, wp,0x1,1); // switch TIMING_ADVANCE_VALUE = on - bitvec_write_field(dest, wp,0x0,6); // TIMING_ADVANCE_VALUE - bitvec_write_field(dest, wp,0x0,1); // switch TIMING_ADVANCE_INDEX = off - - bitvec_write_field(dest, wp,0x0,1); // Frequency Parameters = off + unsigned payload = data[0] >> 6; + bitvec *block; + int rc = 0; - bitvec_write_field(dest, wp,0x1,2); // Dynamic Allocation = off - - bitvec_write_field(dest, wp,0x0,1); // Dynamic Allocation - bitvec_write_field(dest, wp,0x0,1); // P0 = off - - bitvec_write_field(dest, wp,0x1,0); // USF_GRANULARITY - bitvec_write_field(dest, wp,0x1,1); // switch TFI : on - bitvec_write_field(dest, wp,tfi,5);// TFI + switch (payload) { + case GPRS_RLCMAC_DATA_BLOCK: + rc = gprs_rlcmac_rcv_data_block_acknowledged(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); + bitvec_free(block); + break; + case GPRS_RLCMAC_CONTROL_BLOCK_OPT: + LOGP(DRLCMAC, LOGL_NOTICE, "GPRS_RLCMAC_CONTROL_BLOCK_OPT block payload is not supported.\n"); + default: + LOGP(DRLCMAC, LOGL_NOTICE, "Unknown RLCMAC block payload.\n"); + rc = -EINVAL; + } - 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 - - bitvec_write_field(dest, wp,0x0,5); // USF_TN 0 - 4 - bitvec_write_field(dest, wp,0x1,1); // USF_TN 5 - bitvec_write_field(dest, wp,0x1,3); // USF_TN 5 - bitvec_write_field(dest, wp,0x0,2); // USF_TN 6 - 7 -// bitvec_write_field(dest, wp,0x0,1); // Measurement Mapping struct not present + return rc; } - // 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, uint16_t arfcn, uint8_t ts, uint8_t tsc, uint8_t tfi = 0, uint8_t usf = 0, uint32_t tlli = 0) +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, + uint8_t tfi, uint8_t usf, uint32_t tlli, + uint8_t polling, uint32_t poll_fn) { unsigned wp = 0; @@ -420,16 +365,23 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, uint bitvec_write_field(dest, wp,0x1,1); // switch TFI : on bitvec_write_field(dest, wp,tfi,5); // TFI bitvec_write_field(dest, wp,0x0,1); // RLC acknowledged mode - bitvec_write_field(dest, wp,0x0,1); // ALPHA = present + bitvec_write_field(dest, wp,0x0,1); // ALPHA = not present bitvec_write_field(dest, wp,0x0,5); // GAMMA power control parameter - bitvec_write_field(dest, wp,0x0,1); // Polling Bit - bitvec_write_field(dest, wp,0x1,1); // TA_VALID ??? + bitvec_write_field(dest, wp,polling,1); // Polling Bit + bitvec_write_field(dest, wp,!polling,1); // TA_VALID ??? bitvec_write_field(dest, wp,0x1,1); // switch TIMING_ADVANCE_INDEX = on bitvec_write_field(dest, wp,0x0,4); // TIMING_ADVANCE_INDEX - bitvec_write_field(dest, wp,0x0,1); // TBF Starting TIME present + if (polling) { + bitvec_write_field(dest, wp,0x1,1); // TBF Starting TIME present + bitvec_write_field(dest, wp,(poll_fn / (26 * 51)) % 32,5); // T1' + bitvec_write_field(dest, wp,poll_fn % 51,6); // T3 + bitvec_write_field(dest, wp,poll_fn % 26,5); // T2 + } else { + bitvec_write_field(dest, wp,0x0,1); // TBF Starting TIME present + } bitvec_write_field(dest, wp,0x0,1); // P0 not present - bitvec_write_field(dest, wp,0x1,1); // P0 not present - bitvec_write_field(dest, wp,0xb,4); +// bitvec_write_field(dest, wp,0x1,1); // P0 not present +// bitvec_write_field(dest, wp,0xb,4); } else { @@ -458,464 +410,181 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra, uint return wp/8; } - -void write_ia_rest_octets_downlink_assignment(bitvec * dest, uint8_t tfi, uint32_t tlli) +/* 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) { - // GSM 04.08 10.5.2.16 + // TODO We should use our implementation of encode RLC/MAC Control messages. unsigned wp = 0; - bitvec_write_field(dest, wp, 3, 2); // "HH" - bitvec_write_field(dest, wp, 1, 2); // "01" Packet Downlink Assignment - bitvec_write_field(dest, wp,tlli,32); // TLLI - bitvec_write_field(dest, wp,0x1,1); // switch TFI : on - bitvec_write_field(dest, wp,tfi,5); // TFI - bitvec_write_field(dest, wp,0x0,1); // RLC acknowledged mode - bitvec_write_field(dest, wp,0x0,1); // ALPHA = present - bitvec_write_field(dest, wp,0x0,5); // GAMMA power control parameter - bitvec_write_field(dest, wp,0x0,1); // Polling Bit - bitvec_write_field(dest, wp,0x1,1); // TA_VALID ??? - bitvec_write_field(dest, wp,0x1,1); // switch TIMING_ADVANCE_INDEX = on - bitvec_write_field(dest, wp,0x0,4); // TIMING_ADVANCE_INDEX - bitvec_write_field(dest, wp,0x0,1); // TBF Starting TIME present - bitvec_write_field(dest, wp,0x0,1); // P0 not present - bitvec_write_field(dest, wp,0x1,1); // P0 not present - bitvec_write_field(dest, wp,0xb,4); -} + int i; -#if 0 -void gprs_rlcmac_tx_ul_ack(uint8_t tfi, uint32_t tlli, RlcMacUplinkDataBlock_t * ul_data_block) -{ - bitvec *packet_uplink_ack_vec = bitvec_alloc(23); - bitvec_unhex(packet_uplink_ack_vec, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); - write_packet_uplink_ack(packet_uplink_ack_vec, tfi, tlli, ul_data_block->CV, ul_data_block->BSN); - LOGP(DRLCMAC, LOGL_NOTICE, "TX: [PCU -> BTS] TFI: %u TLLI: 0x%08x Packet Uplink Ack\n", tfi, tlli); - RlcMacDownlink_t * packet_uplink_ack = (RlcMacDownlink_t *)malloc(sizeof(RlcMacDownlink_t)); - LOGP(DRLCMAC, LOGL_NOTICE, "+++++++++++++++++++++++++ TX : Packet Uplink Ack +++++++++++++++++++++++++\n"); - decode_gsm_rlcmac_downlink(packet_uplink_ack_vec, packet_uplink_ack); - LOGPC(DRLCMAC, LOGL_NOTICE, "\n"); - LOGP(DRLCMAC, LOGL_NOTICE, "------------------------- TX : Packet Uplink Ack -------------------------\n"); - free(packet_uplink_ack); - gprs_rlcmac_enqueue_block(packet_uplink_ack_vec, 23); - bitvec_free(packet_uplink_ack_vec); -} + bitvec_write_field(dest, wp,0x1,2); // Payload Type + bitvec_write_field(dest, wp,0x0,2); // Uplink block with TDMA framenumber (N+13) + bitvec_write_field(dest, wp,poll,1); // Suppl/Polling Bit + bitvec_write_field(dest, wp,0x0,3); // Uplink state flag + bitvec_write_field(dest, wp,0xa,6); // MESSAGE TYPE -void gprs_rlcmac_data_block_parse(gprs_rlcmac_tbf* tbf, RlcMacUplinkDataBlock_t * ul_data_block) -{ - // 1. Count the number of octets in header and number of LLC PDU in uplink data block. - unsigned data_block_hdr_len = 3; // uplink data block header length: 3 mandatory octets - unsigned llc_pdu_num = 0; // number of LLC PDU in data block + bitvec_write_field(dest, wp,0x0,2); // Page Mode - - if (ul_data_block->E_1 == 0) // Extension octet follows immediately - { - unsigned i = -1; - do - { - i++; - data_block_hdr_len += 1; - llc_pdu_num++; - - // Singular case, TS 44.060 10.4.14 - if (ul_data_block->LENGTH_INDICATOR[i] == 0) - { - break; - } - - // New LLC PDU starts after the current LLC PDU and continues until - // the end of the RLC information field, no more extension octets. - if ((ul_data_block->M[i] == 1)&&(ul_data_block->E[i] == 1)) - { - llc_pdu_num++; - } - } while(ul_data_block->E[i] == 0); // there is another extension octet, which delimits the new LLC PDU - } - else - { - llc_pdu_num++; - } - if(ul_data_block->TI == 1) // TLLI field is present - { - tbf->tlli = ul_data_block->TLLI; - data_block_hdr_len += 4; // TLLI length : 4 octets - if (ul_data_block->PI == 1) // PFI is present if TI field indicates presence of TLLI - { - data_block_hdr_len += 1; // PFI length : 1 octet - } + bitvec_write_field(dest, wp,0x0,1); // switch PERSIST_LEVEL: off + if (use_tlli) { + bitvec_write_field(dest, wp,0x2,2); // switch TLLI : on + bitvec_write_field(dest, wp,tlli,32); // TLLI + } else { + bitvec_write_field(dest, wp,0x0,1); // switch TFI : on + bitvec_write_field(dest, wp,old_downlink,1); // 0=UPLINK TFI, 1=DL TFI + bitvec_write_field(dest, wp,old_tfi,5); // TFI } - - // 2. Extract all LLC PDU from uplink data block and send them to SGSN. - unsigned llc_pdu_len = 0; - unsigned data_octet_num = 0; - for (unsigned num = 0; num < llc_pdu_num; num ++) - { - if (ul_data_block->E_1 == 0) // Extension octet follows immediately - { - // Singular case, TS 44.060 10.4.14 - if (ul_data_block->LENGTH_INDICATOR[num] == 0) - { - llc_pdu_len = UL_RLC_DATA_BLOCK_LEN - data_block_hdr_len; - } - else - { - llc_pdu_len = ul_data_block->LENGTH_INDICATOR[num]; - } - } - else - { - llc_pdu_len = UL_RLC_DATA_BLOCK_LEN - data_block_hdr_len; - } - - for (unsigned i = tbf->llc_index; i < tbf->llc_index + llc_pdu_len; i++) - { - tbf->llc_frame[i] = ul_data_block->RLC_DATA[data_octet_num]; - data_octet_num++; - } - tbf->llc_index += llc_pdu_len; - - if (ul_data_block->E_1 == 0) // Extension octet follows immediately - { - // New LLC PDU starts after the current LLC PDU - if (ul_data_block->M[num] == 1) - { - gprs_rlcmac_tx_ul_ud(tbf); - tbf->llc_index = 0; - // New LLC PDU continues until the end of the RLC information field, no more extension octets. - if ((ul_data_block->E[num] == 1)) - { - llc_pdu_len = UL_RLC_DATA_BLOCK_LEN - data_block_hdr_len - data_octet_num; - for (unsigned i = tbf->llc_index; i < tbf->llc_index + llc_pdu_len; i++) - { - tbf->llc_frame[i] = ul_data_block->RLC_DATA[data_octet_num]; - data_octet_num++; - } - tbf->llc_index += llc_pdu_len; - num++; - } - } - } - } -} + bitvec_write_field(dest, wp,0x0,1); // Message escape + bitvec_write_field(dest, wp,0x0,2); // CHANNEL_CODING_COMMAND + bitvec_write_field(dest, wp,0x0,1); // TLLI_BLOCK_CHANNEL_CODING -/* Received Uplink RLC data block. */ -int gprs_rlcmac_rcv_data_block(bitvec *rlc_block) -{ - struct gprs_rlcmac_tbf *tbf; + 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,0x0,1); // switch TIMING_ADVANCE_INDEX = off - 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 1 + bitvec_write_field(dest, wp,0x1,1); // Frequency Parameters information elements = present + bitvec_write_field(dest, wp,tsc,3); // Training Sequence Code (TSC) = 2 + bitvec_write_field(dest, wp,0x0,2); // ARFCN = present + bitvec_write_field(dest, wp,arfcn,10); // ARFCN +#else + bitvec_write_field(dest, wp,0x0,1); // Frequency Parameters = off +#endif - if (ul_data_block->TI == 1) - { - tbf->tlli = ul_data_block->TLLI; - } + bitvec_write_field(dest, wp,0x1,2); // Dynamic Allocation + + bitvec_write_field(dest, wp,0x0,1); // Extended Dynamic Allocation = off + bitvec_write_field(dest, wp,0x0,1); // P0 = off + + 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 - switch (tbf->state) { - case GPRS_RLCMAC_WAIT_DATA_SEQ_START: - if (ul_data_block->BSN == 0) { - tbf->llc_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; + 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) { + bitvec_write_field(dest, wp,0x1,1); // USF_TN(i): on + bitvec_write_field(dest, wp,usf,3); // USF_TN(i) + } else + bitvec_write_field(dest, wp,0x0,1); // USF_TN(i): off } - - free(ul_data_block); - return 1; +// bitvec_write_field(dest, wp,0x0,1); // Measurement Mapping struct not present } -#endif -/* Received Uplink RLC control block. */ -int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint32_t fn) +/* generate downlink assignment */ +void write_packet_downlink_assignment(bitvec * dest, 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 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"); - decode_gsm_rlcmac_uplink(rlc_block, ul_control_block); - LOGPC(DRLCMAC, LOGL_NOTICE, "\n"); - LOGP(DRLCMAC, LOGL_NOTICE, "------------------------- RX : Uplink Control Block -------------------------\n"); - 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); - if (!tbf) { - LOGP(DRLCMAC, LOGL_NOTICE, "PACKET CONTROL ACK with " - "unknown TLLI=0x%x\n", tlli); - return 0; - } - if (tbf->poll_fn != fn) { - LOGP(DRLCMAC, LOGL_NOTICE, "PACKET CONTROL ACK for " - "TFI=%d received at FN=%d, but was requested " - "for FN=%d\n", tbf->tfi, fn, tbf->poll_fn); - } else { - LOGP(DRLCMAC, LOGL_NOTICE, "PACKET CONTROL ACK received on FN=%d as expected\n", fn); - } - 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); - break; - case MT_PACKET_DOWNLINK_ACK_NACK: - tfi = ul_control_block->u.Packet_Downlink_Ack_Nack.DOWNLINK_TFI; - tbf = tbf_by_tfi(tfi); - 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); - break; - } - free(ul_control_block); - return 1; -} + // TODO We should use our implementation of encode RLC/MAC Control messages. + unsigned wp = 0; + int i; + bitvec_write_field(dest, wp,0x1,2); // Payload Type + bitvec_write_field(dest, wp,0x0,2); // Uplink block with TDMA framenumber (FN+13) + bitvec_write_field(dest, wp,poll,1); // Suppl/Polling Bit + bitvec_write_field(dest, wp,0x0,3); // Uplink state flag + bitvec_write_field(dest, wp,0x2,6); // MESSAGE TYPE + bitvec_write_field(dest, wp,0x0,2); // Page Mode -int gprs_rlcmac_rcv_block(uint8_t *data, uint8_t len, uint32_t fn) -{ - unsigned payload = data[0] >> 6; - bitvec *block; - int rc = 0; + bitvec_write_field(dest, wp,0x0,1); // switch PERSIST_LEVEL: off + bitvec_write_field(dest, wp,0x0,1); // switch TFI : on + bitvec_write_field(dest, wp,old_downlink,1); // 0=UPLINK TFI, 1=DL TFI + bitvec_write_field(dest, wp,old_tfi,5); // TFI - switch (payload) { - case GPRS_RLCMAC_DATA_BLOCK: - rc = gprs_rlcmac_rcv_data_block_acknowledged(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); - bitvec_free(block); - break; - case GPRS_RLCMAC_CONTROL_BLOCK_OPT: - LOGP(DRLCMAC, LOGL_NOTICE, "GPRS_RLCMAC_CONTROL_BLOCK_OPT block payload is not supported.\n"); - default: - LOGP(DRLCMAC, LOGL_NOTICE, "Unknown RLCMAC block payload.\n"); - rc = -EINVAL; - } + bitvec_write_field(dest, wp,0x0,1); // Message escape + bitvec_write_field(dest, wp,0x0,2); // Medium Access Method: Dynamic Allocation + bitvec_write_field(dest, wp,0x0,1); // RLC acknowledged mode - return rc; -} + bitvec_write_field(dest, wp,old_downlink,1); // the network establishes no new downlink TBF for the mobile station + bitvec_write_field(dest, wp,0x80 >> tn,8); // timeslot(s) -#if 0 -int select_pdch(uint8_t *_trx, uint8_t *_ts) -{ - struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; - uint8_t trx, ts; + 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,0x0,1); // switch TIMING_ADVANCE_INDEX = off - for (trx = 0; trx < 8; trx++) { - for (ts = 0; ts < 8; ts++) { - if (bts->trx[trx].pdch[ts].enable) { - *_trx = trx; - *_ts = ts; - return 0; - } - } - } + bitvec_write_field(dest, wp,0x0,1); // switch POWER CONTROL = off + bitvec_write_field(dest, wp,0x1,1); // Frequency Parameters information elements = present - return -EBUSY; -} -#endif + bitvec_write_field(dest, wp,tsc,3); // Training Sequence Code (TSC) = 2 + bitvec_write_field(dest, wp,0x0,2); // ARFCN = present + bitvec_write_field(dest, wp,arfcn,10); // ARFCN -int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta) -{ - struct gprs_rlcmac_tbf *tbf; - uint8_t trx, ts; - int tfi, usf; /* must be signed */ - - // Create new TBF - tfi = tfi_alloc(&trx, &ts); - 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"); - /* 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->state = GPRS_RLCMAC_FLOW; - tbf_timer_start(tbf, 3169, T3169); - LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [UPLINK] START TFI: %u\n", tbf->tfi); - LOGP(DRLCMAC, LOGL_NOTICE, "RX: [PCU <- BTS] TFI: %u RACH qbit-ta=%d ra=%d, Fn=%d (%d,%d,%d)\n", tbf->tfi, qta, ra, Fn, (Fn / (26 * 51)) % 32, Fn % 51, Fn % 26); - 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, tbf->ta, tbf->arfcn, tbf->ts, tbf->tsc, tbf->tfi, usf); - pcu_l1if_tx_agch(immediate_assignment, len); - bitvec_free(immediate_assignment); - - return 0; -} + bitvec_write_field(dest, wp,0x1,1); // switch TFI : on + bitvec_write_field(dest, wp,new_tfi,5);// TFI -// 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) - { - 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; - } + bitvec_write_field(dest, wp,0x1,1); // Power Control Parameters IE = present + bitvec_write_field(dest, wp,0x0,4); // ALPHA power control parameter + for (i = 0; i < 8; i++) + bitvec_write_field(dest, wp,(tn == i),1); // switch GAMMA_TN[i] = on or off + bitvec_write_field(dest, wp,0x0,5); // GAMMA_TN[tn] - 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); - gprs_rlcmac_enqueue_block(data_block_vector, BLOCK_LEN); - 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); - } + bitvec_write_field(dest, wp,0x0,1); // TBF Starting TIME IE not present + bitvec_write_field(dest, wp,0x0,1); // Measurement Mapping struct not present + bitvec_write_field(dest, wp,0x0,1); } -int gprs_rlcmac_segment_llc_pdu(struct gprs_rlcmac_tbf *tbf) +/* generate uplink ack */ +void write_packet_uplink_ack(bitvec * dest, struct gprs_rlcmac_tbf *tbf, + uint8_t final) { - int fbi = 0; - int bsn = 0; - int num_blocks = 0; // number of RLC data blocks necessary for LLC PDU transmission + char show_v_n[65]; + // TODO We should use our implementation of encode RLC/MAC Control messages. + unsigned wp = 0; + uint16_t i, bbn; + uint16_t mod_sns_half = (tbf->sns >> 1) - 1; + char bit; - // LLC PDU fits into one RLC data block with optional LI field. - if (tbf->llc_index < BLOCK_LEN - 4) - { - fbi = 1; - gprs_rlcmac_tx_dl_data_block(tbf->tlli, tbf->tfi, tbf->llc_frame, 0, tbf->llc_index, bsn, fbi); - } - // Necessary several RLC data blocks for transmit LLC PDU. - else - { - // 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->llc_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->llc_index%BLOCK_DATA_LEN; - if (rest_len > 0) - { - // add one block for transmission rest of LLC PDU - num_blocks++; - } + LOGP(DRLCMACUL, LOGL_DEBUG, "Sending Ack/Nack for TBF=%d " + "(final=%d)\n", tbf->tfi, final); - int start_index = 0; - int end_index = 0; - - // Transmit all RLC data blocks of current LLC PDU to MS - for (bsn = 0; bsn < num_blocks; bsn++) - { - if (bsn == num_blocks-1) - { - if (rest_len > 0) - { - block_data_len = rest_len; - } - fbi = 1; - } - end_index = start_index + block_data_len; - gprs_rlcmac_tx_dl_data_block(tbf->tlli, tbf->tfi, tbf->llc_frame, start_index, end_index, bsn, fbi); - start_index += block_data_len; - } - } + bitvec_write_field(dest, wp,0x1,2); // payload + bitvec_write_field(dest, wp,0x0,2); // Uplink block with TDMA framenumber (N+13) + bitvec_write_field(dest, wp,final,1); // Suppl/Polling Bit + bitvec_write_field(dest, wp,0x0,3); // Uplink state flag + + //bitvec_write_field(dest, wp,0x0,1); // Reduced block sequence number + //bitvec_write_field(dest, wp,BSN+6,5); // Radio transaction identifier + //bitvec_write_field(dest, wp,0x1,1); // Final segment + //bitvec_write_field(dest, wp,0x1,1); // Address control + + //bitvec_write_field(dest, wp,0x0,2); // Power reduction: 0 + //bitvec_write_field(dest, wp,TFI,5); // Temporary flow identifier + //bitvec_write_field(dest, wp,0x1,1); // Direction - return 0; + bitvec_write_field(dest, wp,0x09,6); // MESSAGE TYPE + bitvec_write_field(dest, wp,0x0,2); // Page Mode + + bitvec_write_field(dest, wp,0x0,2); + bitvec_write_field(dest, wp,tbf->tfi,5); // Uplink TFI + bitvec_write_field(dest, wp,0x0,1); + + bitvec_write_field(dest, wp,0x0,2); // CS1 + bitvec_write_field(dest, wp,final,1); // FINAL_ACK_INDICATION + bitvec_write_field(dest, wp,tbf->dir.ul.v_r,7); // STARTING_SEQUENCE_NUMBER + // RECEIVE_BLOCK_BITMAP + for (i = 0, bbn = (tbf->dir.ul.v_r - 64) & mod_sns_half; i < 64; + i++, bbn = (bbn + 1) & mod_sns_half) { + bit = tbf->dir.ul.v_n[bbn]; + if (bit == 0) + bit = ' '; + show_v_n[i] = bit; + bitvec_write_field(dest, wp,(bit == 'R'),1); + } + show_v_n[64] = '\0'; + LOGP(DRLCMACUL, LOGL_DEBUG, "- V(N): \"%s\" R=Received " + "N=Not-Received\n", show_v_n); + bitvec_write_field(dest, wp,0x1,1); // CONTENTION_RESOLUTION_TLLI = present + bitvec_write_field(dest, wp,tbf->tlli,8*4); + bitvec_write_field(dest, wp,0x00,4); //spare + bitvec_write_field(dest, wp,0x5,4); //0101 } /* Send Uplink unit-data to SGSN. */ @@ -925,7 +594,7 @@ void 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_NOTICE, "TX: [PCU -> SGSN ] TFI: %u TLLI: 0x%08x DataLen: %u", tbf->tfi, tbf->tlli, tbf->llc_index); + LOGP(DBSSGP, LOGL_NOTICE, "TX: [PCU -> SGSN ] TFI: %u TLLI: 0x%08x DataLen: %u\n", tbf->tfi, tbf->tlli, tbf->llc_index); //LOGP(DBSSGP, LOGL_NOTICE, " Data = "); //for (unsigned i = 0; i < tbf->llc_index; i++) // LOGPC(DBSSGP, LOGL_NOTICE, "%02x ", tbf->llc_frame[i]); @@ -943,30 +612,3 @@ void gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf) bssgp_tx_ul_ud(bctx, tbf->tlli, &qos_profile, llc_pdu); } -void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf) -{ - LOGP(DRLCMAC, LOGL_NOTICE, "TX: [PCU -> BTS] TFI: %u TLLI: 0x%08x Immidiate Assignment (CCCH)\n", tbf->tfi, tbf->tlli); - bitvec *immediate_assignment = bitvec_alloc(23); - bitvec_unhex(immediate_assignment, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); - int len = write_immediate_assignment(immediate_assignment, 1, 125, get_current_fn(), tbf->ta, tbf->arfcn, tbf->ts, tbf->tsc, tbf->tfi, 0, tbf->tlli); - pcu_l1if_tx_agch(immediate_assignment, len); - bitvec_free(immediate_assignment); - tbf_gsm_timer_start(tbf, 0, 120); -} - -void gprs_rlcmac_packet_downlink_assignment(gprs_rlcmac_tbf *tbf) -{ - LOGP(DRLCMAC, LOGL_NOTICE, "TX: [PCU -> BTS] TFI: %u TLLI: 0x%08x Packet DL Assignment\n", tbf->tfi, tbf->tlli); - bitvec *packet_downlink_assignment_vec = bitvec_alloc(23); - bitvec_unhex(packet_downlink_assignment_vec, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); - write_packet_downlink_assignment(packet_downlink_assignment_vec, tbf->tfi, tbf->tlli, tbf->arfcn, tbf->ts, tbf->ta, tbf->tsc); - RlcMacDownlink_t * packet_downlink_assignment = (RlcMacDownlink_t *)malloc(sizeof(RlcMacDownlink_t)); - LOGP(DRLCMAC, LOGL_NOTICE, "+++++++++++++++++++++++++ TX : Packet Downlink Assignment +++++++++++++++++++++++++\n"); - decode_gsm_rlcmac_downlink(packet_downlink_assignment_vec, packet_downlink_assignment); - LOGPC(DRLCMAC, LOGL_NOTICE, "\n"); - LOGP(DRLCMAC, LOGL_NOTICE, "------------------------- TX : Packet Downlink Assignment -------------------------\n"); - free(packet_downlink_assignment); - gprs_rlcmac_enqueue_block(packet_downlink_assignment_vec, 23); - 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 50d2e84c..8c69ed7c 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -29,6 +29,12 @@ extern "C" { #include <osmocom/core/timer.h> } +/* This special feature will delay assignment of downlink TBF by one second, + * in case there is already a TBF. + * This is usefull to debug downlink establishment during packet idle mode. + */ +//#define DEBUG_DL_ASS_IDLE + /* * PDCH instanc */ @@ -41,6 +47,7 @@ struct gprs_rlcmac_pdch { 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 */ + uint32_t last_rts_fn; /* store last frame number of RTS */ }; struct gprs_rlcmac_trx { @@ -49,6 +56,8 @@ struct gprs_rlcmac_trx { }; struct gprs_rlcmac_bts { + uint8_t cs; /* block length 1=CS-1, 2=CS-2, 3=CS-3, 4=CS-4 */ + uint16_t t3192_msec; struct gprs_rlcmac_trx trx[8]; }; @@ -61,16 +70,25 @@ extern struct gprs_rlcmac_bts *gprs_rlcmac_bts; #define LLC_MAX_LEN 1543 #define RLC_MAX_SNS 128 /* GPRS, must be power of 2 */ #define RLC_MAX_WS 64 /* max window size */ -#define RLC_MAX_LEN 52 /* CS-4 */ -#define UL_RLC_DATA_BLOCK_LEN 23 +#define RLC_MAX_LEN 54 /* CS-4 including spare bits */ -#define T3169 6 /* 5 seconds + one second, because we don't use +#define Tassign_agch 0,500000/* wait for assignment, before transmitting DL */ +#define Tassign_pacch 0,100000/* wait for assignment, before transmitting DL */ +#define T3169 6,0 /* 5 seconds + one second, because we don't use * counters before starting timer. */ +#define T3191 5,0 /* 5 Seconds */ +#define T3193 2,0 /* >T3192, which can be max 1,5s */ +#define T3195 5,0 /* 5 Seconds */ +//#define N3101_MAX 12 /* how many missed uplink blocks */ #define N3103_MAX 4 /* how many tries to poll PACKET CONTROL ACK */ +#define N3105_MAX 4 /* how many tries to poll PACKET DOWNLINK ACK */ enum gprs_rlcmac_tbf_state { + GPRS_RLCMAC_NULL = 0, /* new created TBF */ + GPRS_RLCMAC_ASSIGN, /* wait for downlink assignment */ GPRS_RLCMAC_FLOW, /* RLC/MAC flow, ressource needed */ GPRS_RLCMAC_FINISHED, /* flow finished, wait for release */ + GPRS_RLCMAC_WAIT_RELEASE,/* wait for release or restart of DL TBF */ GPRS_RLCMAC_RELEASING, /* releasing, wait to free TBI/USF */ }; @@ -79,10 +97,22 @@ enum gprs_rlcmac_tbf_poll_state { GPRS_RLCMAC_POLL_SCHED, /* a polling was scheduled */ }; -enum gprs_rlcmac_tbf_ul_substate { - GPRS_RLCMAC_UL_NONE = 0, - GPRS_RLCMAC_UL_SEND_ACK, /* send acknowledge on next RTS */ - GPRS_RLCMAC_UL_WAIT_POLL, /* wait for PACKET CONTROL ACK */ +enum gprs_rlcmac_tbf_dl_ass_state { + GPRS_RLCMAC_DL_ASS_NONE = 0, + GPRS_RLCMAC_DL_ASS_SEND_ASS, /* send downlink assignment on next RTS */ + GPRS_RLCMAC_DL_ASS_WAIT_ACK, /* wait for PACKET CONTROL ACK */ +}; + +enum gprs_rlcmac_tbf_ul_ass_state { + GPRS_RLCMAC_UL_ASS_NONE = 0, + GPRS_RLCMAC_UL_ASS_SEND_ASS, /* send uplink assignment on next RTS */ + GPRS_RLCMAC_UL_ASS_WAIT_ACK, /* wait for PACKET CONTROL ACK */ +}; + +enum gprs_rlcmac_tbf_ul_ack_state { + GPRS_RLCMAC_UL_ACK_NONE = 0, + GPRS_RLCMAC_UL_ACK_SEND_ACK, /* send acknowledge on next RTS */ + GPRS_RLCMAC_UL_ACK_WAIT_ACK, /* wait for PACKET CONTROL ACK */ }; enum gprs_rlcmac_tbf_direction { @@ -98,30 +128,45 @@ struct gprs_rlcmac_tbf { uint32_t tlli; uint8_t tlli_valid; uint8_t trx, ts, tsc; + struct gprs_rlcmac_pdch *pdch; uint16_t arfcn, ta; - uint8_t llc_frame[LLC_MAX_LEN]; - uint16_t llc_index; + 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 */ + llist_head llc_queue; /* queued LLC DL data */ + + enum gprs_rlcmac_tbf_dl_ass_state dl_ass_state; + enum gprs_rlcmac_tbf_ul_ass_state ul_ass_state; + enum gprs_rlcmac_tbf_ul_ack_state ul_ack_state; enum gprs_rlcmac_tbf_poll_state poll_state; uint32_t poll_fn; - uint16_t bsn; /* block sequence number */ uint16_t ws; /* window size */ uint16_t sns; /* sequence number space */ + + /* Please note that all variables here will be reset when changing + * from WAIT RELEASE back to FLOW state (re-use of TBF). + * All states that need reset must be in this struct, so this is why + * variables are in both (dl and ul) structs and not outside union. + */ union { struct { + uint16_t bsn; /* block sequence number */ uint16_t v_s; /* send state */ uint16_t v_a; /* ack state */ char v_b[RLC_MAX_SNS/2]; /* acknowledge state array */ + int32_t tx_counter; /* count all transmitted blocks */ + uint8_t n3105; /* N3105 counter */ } dl; struct { + uint16_t bsn; /* block sequence number */ uint16_t v_r; /* receive state */ uint16_t v_q; /* receive window state */ char v_n[RLC_MAX_SNS/2]; /* receive state array */ int32_t rx_counter; /* count all received blocks */ - enum gprs_rlcmac_tbf_ul_substate substate; - uint8_t usf; /* USF */ uint8_t n3103; /* N3103 counter */ + uint8_t usf; /* USF */ } ul; } dir; uint8_t rlc_block[RLC_MAX_SNS/2][RLC_MAX_LEN]; /* block history */ @@ -142,14 +187,21 @@ int tfi_alloc(uint8_t *_trx, uint8_t *_ts); struct gprs_rlcmac_tbf *tbf_alloc(uint8_t tfi, uint8_t trx, uint8_t ts); -struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi); +struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, int direction); -struct gprs_rlcmac_tbf *tbf_by_tlli(uint8_t tlli); +struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, int direction); + +struct gprs_rlcmac_tbf *tbf_by_poll_fn(uint32_t fn); + +int find_free_usf(uint8_t trx, uint8_t ts); void tbf_free(struct gprs_rlcmac_tbf *tbf); +void tbf_new_state(struct gprs_rlcmac_tbf *tbf, + enum gprs_rlcmac_tbf_state state); + void tbf_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int T, - unsigned int seconds); + unsigned int seconds, unsigned int microseconds); void tbf_timer_stop(struct gprs_rlcmac_tbf *tbf); @@ -161,36 +213,56 @@ enum gprs_rlcmac_block_type { GPRS_RLCMAC_RESERVED = 0x3 }; -void gprs_rlcmac_tx_ul_ack(uint8_t tfi, uint32_t tlli, RlcMacUplinkDataBlock_t * ul_data_block); +int gprs_rlcmac_rcv_block(uint8_t *data, uint8_t len, uint32_t fn); -void gprs_rlcmac_data_block_parse(gprs_rlcmac_tbf* tbf, RlcMacUplinkDataBlock_t * ul_data_block); +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, + uint8_t tfi, uint8_t usf, uint32_t tlli, uint8_t polling, + uint32_t poll_fn); -int gprs_rlcmac_rcv_data_block(bitvec *rlc_block); +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); -int gprs_rlcmac_rcv_control_block(bitvec *rlc_block); +void write_packet_downlink_assignment(bitvec * dest, 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); -int gprs_rlcmac_rcv_block(uint8_t *data, uint8_t len, uint32_t fn); +void write_packet_uplink_ack(bitvec * dest, struct gprs_rlcmac_tbf *tbf, + uint8_t final); -int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, - uint32_t fn, uint8_t block_nr); +void gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf); -int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta); +void tbf_timer_cb(void *_tbf); -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_poll_timeout(struct gprs_rlcmac_tbf *tbf); -int gprs_rlcmac_segment_llc_pdu(struct gprs_rlcmac_tbf *tbf); +int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta); -void gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf); +int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint32_t fn); + +struct msgb *gprs_rlcmac_send_packet_uplink_assignment( + struct gprs_rlcmac_tbf *tbf, uint32_t fn); -void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf); +struct msgb *gprs_rlcmac_send_packet_downlink_assignment( + struct gprs_rlcmac_tbf *tbf, uint32_t fn); -void gprs_rlcmac_packet_downlink_assignment(gprs_rlcmac_tbf *tbf); +void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf, + uint8_t old_downlink); -void gprs_rlcmac_enqueue_block(bitvec *block, int len); +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); +struct msgb *gprs_rlcmac_send_data_block_acknowledged( + struct gprs_rlcmac_tbf *tbf, uint32_t fn); + struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf, uint32_t fn); +int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, + uint32_t fn, uint8_t block_nr); + #endif // GPRS_RLCMAC_H diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index ce90c47e..018ef3ee 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -20,13 +20,17 @@ #include <gprs_bssgp_pcu.h> #include <gprs_rlcmac.h> +#include <pcu_l1_if.h> /* After receiving these framess, we send ack/nack. */ #define ACK_AFTER_FRAMES 20 +/* If acknowledgement to uplink/downlin assignmentshould be polled */ +#define POLLING_ASSIGNMENT 0 + extern "C" { /* TS 04.60 10.2.2 */ -struct rlc_dl_header { +struct rlc_ul_header { uint8_t r:1, si:1, cv:4, @@ -39,6 +43,18 @@ struct rlc_dl_header { 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, @@ -46,10 +62,249 @@ struct rlc_li_field { } __attribute__ ((packed)); } +int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf) +{ + LOGP(DRLCMAC, LOGL_NOTICE, "Poll timeout for TBF=%d\n", tbf->tfi); + + tbf->poll_state = GPRS_RLCMAC_POLL_NONE; + + if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_WAIT_ACK) { + LOGP(DRLCMAC, LOGL_DEBUG, "- Timeout for polling PACKET " + "CONTROL ACK for PACKET UPLINK ACK\n"); + tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_NONE; + if (tbf->state == GPRS_RLCMAC_FINISHED) { + tbf->dir.ul.n3103++; + if (tbf->dir.ul.n3103 == N3103_MAX) { + LOGP(DRLCMAC, LOGL_DEBUG, "- N3103 exceeded\n"); + tbf_new_state(tbf, GPRS_RLCMAC_RELEASING); + tbf_timer_start(tbf, 3169, T3169); + return 0; + } + /* reschedule UL ack */ + tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_SEND_ACK; + } + } else + if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_WAIT_ACK) { + LOGP(DRLCMAC, LOGL_DEBUG, "- Timeout for polling PACKET " + "CONTROL ACK for PACKET UPLINK ASSIGNMENT.\n"); + tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE; + } else + if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_WAIT_ACK) { + LOGP(DRLCMAC, LOGL_DEBUG, "- Timeout for polling PACKET " + "CONTROL ACK for PACKET DOWNLINK ASSIGNMENT.\n"); + tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; + /* in case out downlink assigment failed: */ + if (tbf->state == GPRS_RLCMAC_ASSIGN) { + LOGP(DRLCMAC, LOGL_DEBUG, "- Assignment failed\n"); + tbf_free(tbf); + } + } else + if (tbf->direction == GPRS_RLCMAC_DL_TBF) + { + LOGP(DRLCMAC, LOGL_DEBUG, "- Timeout for polling PACKET " + " DOWNLINK ACK.\n"); + tbf->dir.dl.n3105++; + if (tbf->dir.dl.n3105 == N3105_MAX) { + LOGP(DRLCMAC, LOGL_DEBUG, "- N3105 exceeded\n"); + tbf_new_state(tbf, GPRS_RLCMAC_RELEASING); + tbf_timer_start(tbf, 3195, T3195); + return 0; + } + } + + return 0; +} + +/* Received Uplink RLC control block. */ +int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint32_t fn) +{ + uint8_t tfi = 0; + uint32_t tlli = 0; + struct gprs_rlcmac_tbf *tbf; + + RlcMacUplink_t * ul_control_block = (RlcMacUplink_t *)malloc(sizeof(RlcMacUplink_t)); + LOGP(DRLCMAC, LOGL_NOTICE, "+++++++++++++++++++++++++ RX : Uplink Control Block +++++++++++++++++++++++++\n"); + decode_gsm_rlcmac_uplink(rlc_block, ul_control_block); + LOGPC(DRLCMAC, LOGL_NOTICE, "\n"); + LOGP(DRLCMAC, LOGL_NOTICE, "------------------------- RX : Uplink Control Block -------------------------\n"); + 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); + if (!tbf) { + LOGP(DRLCMAC, LOGL_NOTICE, "PACKET CONTROL ACK with " + "unknown FN=%u TLL=0x%08x\n", fn, tlli); + break; + } + tfi = tbf->tfi; + if (tlli != tbf->tlli) { + LOGP(DRLCMAC, LOGL_NOTICE, "Phone changed TLLI to " + "0x%08x\n", tlli); + tbf->tlli = tlli; + } + LOGP(DRLCMAC, LOGL_NOTICE, "RX: [PCU <- BTS] TFI: %u TLLI: 0x%08x Packet Control Ack\n", tbf->tfi, tbf->tlli); + tbf->poll_state = GPRS_RLCMAC_POLL_NONE; + + /* check if this control ack belongs to packet uplink ack */ + if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_WAIT_ACK) { + LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [UPLINK] END TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli); + tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_NONE; + tbf_free(tbf); + break; + } + if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_WAIT_ACK) { + LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [UPLINK] DOWNLINK ASSIGNED TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli); + tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; + break; + } + if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_WAIT_ACK) { + LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] UPLINK ASSIGNED TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli); + tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE; + break; + } + LOGP(DRLCMAC, LOGL_ERROR, "Error: received PACET CONTROL ACK " + "at no request\n"); + break; + case MT_PACKET_DOWNLINK_ACK_NACK: + tfi = ul_control_block->u.Packet_Downlink_Ack_Nack.DOWNLINK_TFI; + tbf = tbf_by_poll_fn(fn); + if (!tbf) { + LOGP(DRLCMAC, LOGL_NOTICE, "PACKET DOWNLINK ACK with " + "unknown FN=%u TFI=%d\n", fn, tfi); + break; + } + /* reset N3105 */ + tbf->dir.dl.n3105 = 0; + /* stop timer T3191 */ + tbf_timer_stop(tbf); + tlli = tbf->tlli; + LOGP(DRLCMAC, LOGL_NOTICE, "RX: [PCU <- BTS] TFI: %u TLLI: 0x%08x Packet Downlink Ack/Nack\n", tbf->tfi, tbf->tlli); + tbf->poll_state = GPRS_RLCMAC_POLL_NONE; + + gprs_rlcmac_downlink_ack(tbf, + ul_control_block->u.Packet_Downlink_Ack_Nack.Ack_Nack_Description.FINAL_ACK_INDICATION, + ul_control_block->u.Packet_Downlink_Ack_Nack.Ack_Nack_Description.STARTING_SEQUENCE_NUMBER, + 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; + struct gprs_rlcmac_tbf *ul_tbf; + + 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); + 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: 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, T3169); + LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [UPLINK] START TFI: %u\n", ul_tbf->tfi); + /* schedule uplink assignment */ + tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS; + } + break; + case MT_PACKET_RESOURCE_REQUEST: + if (ul_control_block->u.Packet_Resource_Request.ID.UnionType) { + tlli = ul_control_block->u.Packet_Resource_Request.ID.u.TLLI; + tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF); + if (!tbf) { + LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESSOURCE REQ unknown uplink TLLI=0x%08x\n", tlli); + break; + } + tfi = tbf->tfi; + } 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); + if (!tbf) { + LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESSOURCE REQ unknown downlink TFI=%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); + if (!tbf) { + LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESSOURCE REQ unknown uplink TFI=%d\n", tlli); + break; + } + } + tlli = tbf->tlli; + } + LOGP(DRLCMAC, LOGL_NOTICE, "RX: [PCU <- BTS] TFI: %u TLLI: 0x%08x Packet ressource request\n", tbf->tfi, tbf->tlli); +#warning FIXME +puts("FIXME: UL request during UL request"); exit(0); + + + break; + default: + LOGP(DRLCMAC, LOGL_ERROR, "RX: [PCU <- BTS] unknown control block received\n"); + } + free(ul_control_block); + return 1; +} + + +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, + tbf->T); + + tbf->num_T_exp++; + + switch (tbf->T) { +#ifdef DEBUG_DL_ASS_IDLE + case 1234: + gprs_rlcmac_trigger_downlink_assignment(tbf, 0); + break; +#endif + case 0: /* assignment */ + /* change state to FLOW, so scheduler will start transmission */ + if (tbf->state == GPRS_RLCMAC_ASSIGN) + tbf_new_state(tbf, GPRS_RLCMAC_FLOW); + else + LOGP(DRLCMAC, LOGL_ERROR, "Error: TBF is not in assign " + "state\n"); + break; + case 3169: + case 3191: + case 3193: + case 3195: + LOGP(DRLCMAC, LOGL_DEBUG, "TBF will be freed due to timeout\n"); + /* free TBF */ + tbf_free(tbf); + break; + default: + LOGP(DRLCMAC, LOGL_ERROR, "Timer expired in unknown mode: %u\n", + tbf->T); + } +} + +/* + * 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_dl_header *rh = (struct rlc_dl_header *)data; + struct rlc_ul_header *rh = (struct rlc_ul_header *)data; struct rlc_li_field *li; uint8_t e; @@ -62,7 +317,7 @@ static int tlli_from_ul_data(uint8_t *data, uint8_t len, uint32_t *tlli) /* if E is not set (LI follows) */ while (!e) { if (!len) { - LOGP(DRLCMACDATA, LOGL_NOTICE, "UL DATA LI extended, " + LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, " "but no more data\n"); return -EINVAL; } @@ -76,7 +331,7 @@ static int tlli_from_ul_data(uint8_t *data, uint8_t len, uint32_t *tlli) len--; } if (len < 4) { - LOGP(DRLCMACDATA, LOGL_NOTICE, "UL DATA TLLI out of frame " + LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TLLI out of frame " "border\n"); return -EINVAL; } @@ -90,13 +345,13 @@ static int tlli_from_ul_data(uint8_t *data, uint8_t len, uint32_t *tlli) static int gprs_rlcmac_assemble_llc(struct gprs_rlcmac_tbf *tbf, uint8_t *data, uint8_t len) { - struct rlc_dl_header *rh = (struct rlc_dl_header *)data; + 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(DRLCMACDATA, LOGL_DEBUG, "- Assembling frames: (len=%d)\n", len); + LOGP(DRLCMACUL, LOGL_DEBUG, "- Assembling frames: (len=%d)\n", len); data += 3; len -= 3; @@ -106,18 +361,18 @@ static int gprs_rlcmac_assemble_llc(struct gprs_rlcmac_tbf *tbf, uint8_t *data, /* Parse frame offsets from length indicator(s), if any. */ while (1) { if (frames == (int)sizeof(frame_offset)) { - LOGP(DRLCMACDATA, LOGL_ERROR, "Too many frames in " + LOGP(DRLCMACUL, LOGL_ERROR, "Too many frames in " "block\n"); return -EINVAL; } frame_offset[frames++] = offset; - LOGP(DRLCMACDATA, LOGL_DEBUG, "-- Frame %d starts at 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(DRLCMACDATA, LOGL_NOTICE, "UL DATA TFI=%d " + LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TFI=%d " "ignored, because M='0' and E='0'.\n", tbf->tfi); return 0; @@ -129,6 +384,8 @@ static int gprs_rlcmac_assemble_llc(struct gprs_rlcmac_tbf *tbf, uint8_t *data, /* 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 @@ -153,16 +410,37 @@ static int gprs_rlcmac_assemble_llc(struct gprs_rlcmac_tbf *tbf, uint8_t *data, } } if (!m) { - LOGP(DRLCMACDATA, LOGL_DEBUG, "- Last frame carries spare " + LOGP(DRLCMACUL, LOGL_DEBUG, "- Last frame carries spare " "data\n"); } - LOGP(DRLCMACDATA, LOGL_DEBUG, "- Data length after length fields: %d\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(DRLCMACDATA, LOGL_DEBUG, "- Length after skipping TLLI: " + 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); } @@ -174,7 +452,7 @@ static int gprs_rlcmac_assemble_llc(struct gprs_rlcmac_tbf *tbf, uint8_t *data, /* Check if last offset would exceed frame. */ if (offset > len) { - LOGP(DRLCMACDATA, LOGL_NOTICE, "UL DATA TFI=%d ignored, " + LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TFI=%d ignored, " "because LI exceeds frame length.\n", tbf->tfi); return -EINVAL; } @@ -192,91 +470,55 @@ static int gprs_rlcmac_assemble_llc(struct gprs_rlcmac_tbf *tbf, uint8_t *data, /* data until next frame */ chunk = frame_offset[i + 1] - frame_offset[i]; } - LOGP(DRLCMACDATA, LOGL_DEBUG, "-- Appending chunk (len=%d) to " + 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(DRLCMACDATA, LOGL_NOTICE, "LLC frame exceeds " + 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 ? */ + /* not last frame. */ if (i != frames - 1) { /* send frame to SGSN */ - LOGP(DRLCMACDATA, LOGL_INFO, "Complete UL frame for " + LOGP(DRLCMACUL, LOGL_INFO, "Complete UL frame for " "TFI=%d: %s\n", tbf->tfi, osmo_hexdump(tbf->llc_frame, tbf->llc_index)); gprs_rlcmac_tx_ul_ud(tbf); - tbf->llc_index = 0; + 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 " + "TFI=%d that fits precisely in last block: " + "%s\n", tbf->tfi, + osmo_hexdump(tbf->llc_frame, tbf->llc_index)); + gprs_rlcmac_tx_ul_ud(tbf); + tbf->llc_index = 0; /* reset frame space */ } } return 0; } -/* * generate uplink ack - */ -void write_packet_uplink_ack(bitvec * dest, struct gprs_rlcmac_tbf *tbf, - uint8_t final) -{ - // TODO We should use our implementation of encode RLC/MAC Control messages. - unsigned wp = 0; - uint16_t i, bbn; - uint16_t mod_sns_half = (tbf->sns >> 1) - 1; - char bit; - - LOGP(DRLCMACDATA, LOGL_DEBUG, "Sending Ack/Nack for TBF=%d " - "(final=%d)\n", tbf->tfi, final); - - bitvec_write_field(dest, wp,0x1,2); // payload - bitvec_write_field(dest, wp,0x0,2); // Uplink block with TDMA framenumber (N+13) - bitvec_write_field(dest, wp,final,1); // Suppl/Polling Bit - bitvec_write_field(dest, wp,0x0,3); // Uplink state flag - - //bitvec_write_field(dest, wp,0x0,1); // Reduced block sequence number - //bitvec_write_field(dest, wp,BSN+6,5); // Radio transaction identifier - //bitvec_write_field(dest, wp,0x1,1); // Final segment - //bitvec_write_field(dest, wp,0x1,1); // Address control - - //bitvec_write_field(dest, wp,0x0,2); // Power reduction: 0 - //bitvec_write_field(dest, wp,TFI,5); // Temporary flow identifier - //bitvec_write_field(dest, wp,0x1,1); // Direction - - bitvec_write_field(dest, wp,0x09,6); // MESSAGE TYPE - bitvec_write_field(dest, wp,0x0,2); // Page Mode - - bitvec_write_field(dest, wp,0x0,2); - bitvec_write_field(dest, wp,tbf->tfi,5); // Uplink TFI - bitvec_write_field(dest, wp,0x0,1); - - bitvec_write_field(dest, wp,0x0,2); // CS1 - bitvec_write_field(dest, wp,final,1); // FINAL_ACK_INDICATION - bitvec_write_field(dest, wp,tbf->dir.ul.v_r,7); // STARTING_SEQUENCE_NUMBER - // RECEIVE_BLOCK_BITMAP - LOGP(DRLCMACDATA, LOGL_DEBUG, "- ack bitmap: \""); - for (i = 0, bbn = (tbf->dir.ul.v_r - 1) & mod_sns_half; i < 64; - i++, bbn = (bbn - 1) & mod_sns_half) { - bit = tbf->dir.ul.v_n[bbn]; - if (bit == 0) - bit = ' '; - LOGPC(DRLCMACDATA, LOGL_DEBUG, "%c", bit); - bitvec_write_field(dest, wp,(bit == 'R'),1); - } - LOGPC(DRLCMACDATA, LOGL_DEBUG, "\"\n"); - bitvec_write_field(dest, wp,0x1,1); // CONTENTION_RESOLUTION_TLLI = present - bitvec_write_field(dest, wp,tbf->tlli,8*4); - bitvec_write_field(dest, wp,0x00,4); //spare - bitvec_write_field(dest, wp,0x5,4); //0101 -} - struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf, uint32_t fn) { int final = (tbf->state == GPRS_RLCMAC_FINISHED); struct msgb *msg; + if (final && tbf->poll_state != GPRS_RLCMAC_POLL_NONE) { + LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already " + "sheduled for TBF=%d, so we must wait for final uplink " + "ack...\n", tbf->tfi); + return NULL; + } + msg = msgb_alloc(23, "rlcmac_ul_ack"); if (!msg) return NULL; @@ -292,14 +534,12 @@ struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf, bitvec_free(ack_vec); if (final) { - if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED) - LOGP(DRLCMACDATA, LOGL_ERROR, "Polling is already " - "sheduled for TBF=%d\n", tbf->tfi); tbf->poll_state = GPRS_RLCMAC_POLL_SCHED; tbf->poll_fn = (fn + 13) % 2715648; - tbf->dir.ul.substate = GPRS_RLCMAC_UL_WAIT_POLL; + /* waiting for final acknowledge */ + tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_WAIT_ACK; } else - tbf->dir.ul.substate = GPRS_RLCMAC_UL_NONE; + tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_NONE; return msg; } @@ -311,61 +551,61 @@ struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf, int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t *data, uint8_t len) { struct gprs_rlcmac_tbf *tbf; - struct rlc_dl_header *rh = (struct rlc_dl_header *)data; + 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; if (len < 23) { - LOGP(DRLCMACDATA, LOGL_ERROR, "Dropping short frame " + LOGP(DRLCMACUL, LOGL_ERROR, "Dropping short frame " "(len = %d)\n", len); return -EINVAL; } /* find TBF inst from given TFI */ - tbf = tbf_by_tfi(rh->tfi); + tbf = tbf_by_tfi(rh->tfi, GPRS_RLCMAC_UL_TBF); if (!tbf) { - LOGP(DRLCMACDATA, LOGL_NOTICE, "UL DATA unknown TFI=%d\n", + LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA unknown TFI=%d\n", rh->tfi); return 0; } if (tbf->direction != GPRS_RLCMAC_UL_TBF) { - LOGP(DRLCMACDATA, LOGL_NOTICE, "UL DATA TFI=%d not Uplink " + LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TFI=%d not Uplink " "tbf\n", rh->tfi); return 0; } - LOGP(DRLCMACDATA, LOGL_INFO, "UL DATA TFI=%d received (V(Q)=%d .. " + LOGP(DRLCMACUL, LOGL_INFO, "UL DATA TFI=%d received (V(Q)=%d .. " "V(R)=%d)\n", rh->tfi, tbf->dir.ul.v_q, tbf->dir.ul.v_r); /* get TLLI */ if (!tbf->tlli_valid) { /* no TLLI yet */ if (!rh->ti) { - LOGP(DRLCMACDATA, LOGL_NOTICE, "UL DATA TFI=%d without " + LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TFI=%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(DRLCMACDATA, LOGL_NOTICE, "Failed to decode TLLI " + LOGP(DRLCMACUL, LOGL_NOTICE, "Failed to decode TLLI " "of UL DATA TFI=%d.\n", rh->tfi); return 0; } tbf->tlli_valid = 1; - LOGP(DRLCMACDATA, LOGL_DEBUG, " Decoded premier TLLI=0x%08x of " + LOGP(DRLCMACUL, LOGL_DEBUG, " Decoded premier TLLI=0x%08x of " "UL DATA TFI=%d.\n", tbf->tlli, rh->tfi); /* 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(DRLCMACDATA, LOGL_NOTICE, "Failed to decode TLLI " + LOGP(DRLCMACUL, LOGL_NOTICE, "Failed to decode TLLI " "of UL DATA TFI=%d.\n", rh->tfi); return 0; } if (tlli != tbf->tlli) { - LOGP(DRLCMACDATA, LOGL_NOTICE, "TLLI mismatch on UL " + LOGP(DRLCMACUL, LOGL_NOTICE, "TLLI mismatch on UL " "DATA TFI=%d. (Ignoring due to contention " "resolution)\n", rh->tfi); return 0; @@ -386,7 +626,7 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t *data, uint8_t len) /* If out of window (may happen if blocks below V(Q) are received * again. */ if (offset_v_q >= tbf->ws) { - LOGP(DRLCMACDATA, LOGL_DEBUG, "- BSN %d out of window " + 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; @@ -396,7 +636,7 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t *data, uint8_t len) 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(DRLCMACDATA, LOGL_DEBUG, "- BSN %d storing in window (%d..%d)\n", + 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. */ @@ -409,7 +649,7 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t *data, uint8_t len) tbf->dir.ul.v_r = (tbf->dir.ul.v_r + 1) & mod_sns; /* Inc V(R). */ } - LOGP(DRLCMACDATA, LOGL_DEBUG, "- Raising V(R) to %d\n", + LOGP(DRLCMACUL, LOGL_DEBUG, "- Raising V(R) to %d\n", tbf->dir.ul.v_r); } @@ -418,7 +658,7 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t *data, uint8_t len) * 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(DRLCMACDATA, LOGL_DEBUG, "- Taking block %d out, raising " + 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 */ @@ -431,43 +671,697 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t *data, uint8_t len) /* Check CV of last frame in buffer */ if (tbf->state == GPRS_RLCMAC_FLOW /* still in flow state */ && tbf->dir.ul.v_q == tbf->dir.ul.v_r) { /* if complete */ - struct rlc_dl_header *last_rh = (struct rlc_dl_header *) + struct rlc_ul_header *last_rh = (struct rlc_ul_header *) tbf->rlc_block[(tbf->dir.ul.v_r - 1) & mod_sns_half]; - LOGP(DRLCMACDATA, LOGL_DEBUG, "- No gaps in received block, " + 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(DRLCMACDATA, LOGL_DEBUG, "- Finished with UL " + LOGP(DRLCMACUL, LOGL_DEBUG, "- Finished with UL " "TBF\n"); - tbf->state = GPRS_RLCMAC_FINISHED; - /* Start special timer instead of N3103 counter. - * If this expires, resend. */ - tbf_timer_start(tbf, 3103, 1); + 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->ti || tbf->state == GPRS_RLCMAC_FINISHED + if (rh->si || rh->ti || tbf->state == GPRS_RLCMAC_FINISHED || (tbf->dir.ul.rx_counter % ACK_AFTER_FRAMES) == 0) { + if (rh->si) { + LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, " + "because MS is stalled.\n"); + } if (rh->ti) { - LOGP(DRLCMACDATA, LOGL_DEBUG, "- Scheduling Ack/Nack, " + LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, " "because TLLI is included.\n"); } if (tbf->state == GPRS_RLCMAC_FINISHED) { - LOGP(DRLCMACDATA, LOGL_DEBUG, "- Scheduling Ack/Nack, " + LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, " "because last block has CV==0.\n"); } if ((tbf->dir.ul.rx_counter % ACK_AFTER_FRAMES) == 0) { - LOGP(DRLCMACDATA, LOGL_DEBUG, "- Scheduling Ack/Nack, " + LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, " "because %d frames received.\n", ACK_AFTER_FRAMES); } - /* trigger sending at next RTS */ - tbf->dir.ul.substate = GPRS_RLCMAC_UL_SEND_ACK; + if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_NONE) { + /* 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) +{ + struct msgb *msg; + struct gprs_rlcmac_tbf *new_tbf; + + 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; + } + + /* on down TBF we get the uplink TBF to be assigned. */ + if (tbf->direction == GPRS_RLCMAC_DL_TBF) + new_tbf = tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_UL_TBF); + else + new_tbf = tbf; + + if (!new_tbf) { + LOGP(DRLCMACUL, LOGL_ERROR, "We have a schedule for uplink " + "assignment at downlink TBF=%d, but there is no uplink " + "TBF\n", tbf->tfi); + tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE; + return NULL; + } + + msg = msgb_alloc(23, "rlcmac_ul_ass"); + if (!msg) + return NULL; + bitvec *ass_vec = bitvec_alloc(23); + if (!ass_vec) { + msgb_free(msg); + return NULL; + } + 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); + bitvec_pack(ass_vec, msgb_put(msg, 23)); + RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)malloc(sizeof(RlcMacDownlink_t)); + LOGP(DRLCMAC, LOGL_NOTICE, "+++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++\n"); + decode_gsm_rlcmac_downlink(ass_vec, mac_control_block); + LOGPC(DRLCMAC, LOGL_NOTICE, "\n"); + LOGP(DRLCMAC, LOGL_NOTICE, "------------------------- TX : Packet Uplink Assignment -------------------------\n"); + bitvec_free(ass_vec); + +#if POLLING_ASSIGNMENT == 1 + 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->ul_ass_state = GPRS_RLCMAC_UL_ASS_WAIT_ACK; +#else + tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE; +#endif + + return msg; +} + +int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta) +{ + struct gprs_rlcmac_tbf *tbf; + uint8_t trx, ts; + int tfi, usf; /* 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); + 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"); + /* 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, T3169); + LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [UPLINK] START TFI: %u\n", tbf->tfi); + LOGP(DRLCMAC, LOGL_NOTICE, "RX: [PCU <- BTS] TFI: %u RACH qbit-ta=%d ra=%d, Fn=%d (%d,%d,%d)\n", tbf->tfi, qta, ra, Fn, (Fn / (26 * 51)) % 32, Fn % 51, Fn % 26); + 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, tbf->ta, tbf->arfcn, tbf->ts, tbf->tsc, tbf->tfi, usf, 0, 0, 0); + pcu_l1if_tx_agch(immediate_assignment, len); + bitvec_free(immediate_assignment); + + return 0; +} + + +/* + * DL data block flow + */ + +/* send DL data block + * + * The messages are fragmented and forwarded as data blocks. + */ +struct msgb *gprs_rlcmac_send_data_block_acknowledged( + struct gprs_rlcmac_tbf *tbf, uint32_t fn) +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + struct rlc_dl_header *rh; + struct rlc_li_field *li; + uint8_t block_length; /* total length of block, including spare bits */ + uint8_t block_data; /* usable data of block, w/o spare bits, inc. MAC */ + struct msgb *msg, *dl_msg; + uint8_t bsn; + uint16_t mod_sns = tbf->sns - 1; + uint16_t mod_sns_half = (tbf->sns >> 1) - 1; + uint16_t index; + uint8_t *delimiter, *data, *e_pointer; + uint8_t len; + uint16_t space, chunk; + + LOGP(DRLCMACDL, LOGL_INFO, "DL DATA TFI=%d downlink (V(A)==%d .. " + "V(S)==%d)\n", tbf->tfi, tbf->dir.dl.v_a, tbf->dir.dl.v_s); + +do_resend: + /* check if there is a block with negative acknowledgement */ + for (bsn = tbf->dir.dl.v_a; bsn != tbf->dir.dl.v_s; + bsn = (bsn + 1) & mod_sns) { + index = (bsn & mod_sns_half); + if (tbf->dir.dl.v_b[index] == 'N' + || tbf->dir.dl.v_b[index] == 'X') { + LOGP(DRLCMACDL, LOGL_DEBUG, "- Resending BSN %d\n", + bsn); + /* re-send block with negative aknowlegement */ + tbf->dir.dl.v_b[index] = 'U'; /* unacked */ + goto tx_block; + } + } + + /* if the window has stalled, or transfer is complete, + * send an unacknowledged block */ + if (tbf->state == GPRS_RLCMAC_FINISHED + || ((tbf->dir.dl.v_s - tbf->dir.dl.v_a) & mod_sns) == tbf->ws) { + int resend = 0; + + if (tbf->state == GPRS_RLCMAC_FINISHED) + LOGP(DRLCMACDL, LOGL_DEBUG, "- Restarting at BSN %d, " + "because all blocks have been transmitted.\n", + tbf->dir.dl.v_a); + else + LOGP(DRLCMACDL, LOGL_DEBUG, "- Restarting at BSN %d, " + "because all window is stalled.\n", + tbf->dir.dl.v_a); + /* If V(S) == V(A) and finished state, we would have received + * acknowledgement of all transmitted block. In this case we + * would have transmitted the final block, and received ack + * from MS. But in this case we did not receive the final ack + * indication from MS. This should never happen if MS works + * correctly. */ + if (tbf->dir.dl.v_s == tbf->dir.dl.v_a) { + LOGP(DRLCMACDL, LOGL_ERROR, "- MS acked all block " + "(including final block), but did not include " + "FINAL_ACK_INDICATION!\n"); + /* we just send final block again */ + index = ((tbf->dir.dl.v_s - 1) & mod_sns_half); + goto tx_block; + } + + /* cycle through all unacked blocks */ + for (bsn = tbf->dir.dl.v_a; bsn != tbf->dir.dl.v_s; + bsn = (bsn + 1) & mod_sns) { + index = (bsn & mod_sns_half); + if (tbf->dir.dl.v_b[index] == 'U') { + /* mark to be re-send */ + tbf->dir.dl.v_b[index] = 'X'; + resend++; + } + } + /* At this point there should be at leasst one unacked block + * to be resent. If not, this is an software error. */ + if (resend == 0) { + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "There are no unacknowledged blocks, but V(A) " + " != V(S). PLEASE FIX!\n"); + /* we just send final block again */ + index = ((tbf->dir.dl.v_s - 1) & mod_sns_half); + goto tx_block; + } + goto do_resend; + } + + LOGP(DRLCMACDL, LOGL_DEBUG, "- Sending new block at BSN %d\n", + tbf->dir.dl.v_s); + + /* now we still have untransmitted LLC data, so we fill mac block */ + index = tbf->dir.dl.v_s & mod_sns_half; + data = tbf->rlc_block[index]; + switch (bts->cs) { + case 2: /* CS-2 */ + block_length = 34; + block_data = 33; + break; + case 3: /* CS-3 */ + block_length = 40; + block_data = 39; + break; + case 4: /* CS-4 */ + block_length = 54; + block_data = 53; + break; + default: /* CS-1 */ + block_length = 23; + block_data = 23; + } + memset(data, 0x2b, block_data); /* spare bits will be left 0 */ + rh = (struct rlc_dl_header *)data; + rh->pt = 0; /* Data Block */ + rh->rrbp = rh->s_p = 0; /* Polling, set later, if required */ + rh->usf = 7; /* will be set at scheduler */ + rh->pr = 0; /* FIXME: power reduction */ + rh->tfi = tbf->tfi; /* TFI */ + rh->fbi = 0; /* Final Block Indicator, set late, if true */ + rh->bsn = tbf->dir.dl.v_s; /* Block Sequence Number */ + rh->e = 0; /* Extension bit, maybe set later */ + e_pointer = data + 2; /* points to E of current chunk */ + data += 3; + delimiter = data; /* where next length header would be stored */ + space = block_data - 3; + while (1) { + chunk = tbf->llc_length - tbf->llc_index; + /* if chunk will exceed block limit */ + if (chunk > space) { + LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d " + "larger than space (%d) left in block: copy " + "only remaining space, and we are done\n", + chunk, space); + /* block is filled, so there is no extension */ + *e_pointer |= 0x01; + /* fill only space */ + memcpy(data, tbf->llc_frame + tbf->llc_index, space); + /* incement index */ + tbf->llc_index += space; + /* return data block as message */ + break; + } + /* if FINAL chunk would fit precisely in space left */ + if (chunk == space && llist_empty(&tbf->llc_queue)) { + LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d " + "would exactly fit into space (%d): because " + "this is a final block, we don't add length " + "header, and we are done\n", chunk, space); + /* block is filled, so there is no extension */ + *e_pointer |= 0x01; + /* fill space */ + memcpy(data, tbf->llc_frame + tbf->llc_index, space); + /* reset LLC frame */ + tbf->llc_index = tbf->llc_length = 0; + /* final block */ + rh->fbi = 1; /* we indicate final block */ + tbf_new_state(tbf, GPRS_RLCMAC_FINISHED); + /* return data block as message */ + break; + } + /* if chunk would fit exactly in space left */ + if (chunk == space) { + LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d " + "would exactly fit into space (%d): add length " + "header with LI=0, to make frame extend to " + "next block, and we are done\n", chunk, space); + /* make space for delimiter */ + if (delimiter != data) + memcpy(delimiter + 1, delimiter, + data - delimiter); + data++; + space--; + /* add LI with 0 length */ + li = (struct rlc_li_field *)delimiter; + li->e = 1; /* not more extension */ + li->m = 0; /* shall be set to 0, in case of li = 0 */ + li->li = 0; /* chunk fills the complete space */ + // no need to set e_pointer nor increase delimiter + /* fill only space, which is 1 octet less than chunk */ + memcpy(data, tbf->llc_frame + tbf->llc_index, space); + /* incement index */ + tbf->llc_index += space; + /* return data block as message */ + break; + } + LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d is less " + "than remaining space (%d): add length header to " + "to delimit LLC frame\n", chunk, space); + /* the LLC frame chunk ends in this block */ + /* make space for delimiter */ + if (delimiter != data) + memcpy(delimiter + 1, delimiter, data - delimiter); + data++; + space--; + /* add LI to delimit frame */ + li = (struct rlc_li_field *)delimiter; + li->e = 0; /* Extension bit, maybe set later */ + li->m = 0; /* will be set later, if there is more LLC data */ + li->li = chunk; /* length of chunk */ + e_pointer = delimiter; /* points to E of current delimiter */ + delimiter++; + /* copy (rest of) LLC frame to space */ + memcpy(data, tbf->llc_frame + tbf->llc_index, chunk); + data += chunk; + space -= chunk; + /* reset LLC frame */ + tbf->llc_index = tbf->llc_length = 0; + /* dequeue next LLC frame, if any */ + msg = msgb_dequeue(&tbf->llc_queue); + if (msg) { + LOGP(DRLCMACDL, LOGL_INFO, "- Dequeue next LLC " + "(len=%d)\n", msg->len); + memcpy(tbf->llc_frame, msg->data, msg->len); + tbf->llc_length = msg->len; + msgb_free(msg); + } + /* if we have more data and we have space left */ + if (space > 0 && tbf->llc_length) { + li->m = 1; /* we indicate more frames to follow */ + continue; + } + /* if we don't have more LLC frames */ + if (!tbf->llc_length) { + LOGP(DRLCMACDL, LOGL_INFO, "-- Final block, so we " + "done.\n"); + li->e = 1; /* we cannot extend */ + rh->fbi = 1; /* we indicate final block */ + tbf_new_state(tbf, GPRS_RLCMAC_FINISHED); + break; + } + /* we have no space left */ + LOGP(DRLCMACDL, LOGL_INFO, "-- No space left, so we are " + "done.\n"); + li->e = 1; /* we cannot extend */ + break; + } + LOGP(DRLCMACDL, LOGL_DEBUG, "data block: %s\n", + osmo_hexdump(tbf->rlc_block[index], block_length)); + tbf->rlc_block_len[index] = block_length; + /* raise send state and set ack state array */ + tbf->dir.dl.v_b[index] = 'U'; /* unacked */ + tbf->dir.dl.v_s = (tbf->dir.dl.v_s + 1) & mod_sns; /* inc send state */ + +tx_block: + /* from this point on, new block is sent or old block is resent */ + + /* get data and header from current block */ + data = tbf->rlc_block[index]; + len = tbf->rlc_block_len[index]; + rh = (struct rlc_dl_header *)data; + + /* Increment TX-counter */ + tbf->dir.dl.tx_counter++; + + /* Clear Polling, if still set in history buffer */ + rh->s_p = 0; + + /* poll after ACK_AFTER_FRAMES frames, or when final block is tx. */ + if (rh->fbi == 1 || (tbf->dir.dl.tx_counter % ACK_AFTER_FRAMES) == 0) { + if (rh->fbi == 1) { + LOGP(DRLCMACDL, LOGL_DEBUG, "- Scheduling Ack/Nack " + "polling, because final block sent.\n"); + } + if ((tbf->dir.dl.tx_counter % ACK_AFTER_FRAMES) == 0) { + LOGP(DRLCMACDL, LOGL_DEBUG, "- Scheduling Ack/Nack " + "polling, because %d blocks sent.\n", + ACK_AFTER_FRAMES); + } + if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE) + LOGP(DRLCMACDL, LOGL_NOTICE, "Polling is already " + "sheduled for TBF=%d, so we must wait for " + "requesting downlink ack\n", tbf->tfi); + else { + /* start timer whenever we send the final block */ + if (rh->fbi == 1) + tbf_timer_start(tbf, 3191, T3191); + + /* schedule polling */ + tbf->poll_state = GPRS_RLCMAC_POLL_SCHED; + tbf->poll_fn = (fn + 13) % 2715648; + + /* set polling in header */ + rh->rrbp = 0; /* N+13 */ + rh->s_p = 1; /* Polling */ + } } + /* return data block as message */ + dl_msg = msgb_alloc(len, "rlcmac_dl_data"); + if (!dl_msg) + return NULL; + memcpy(msgb_put(dl_msg, len), data, len); + + return dl_msg; +} + +int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final, + uint8_t ssn, uint8_t *rbb) +{ + char show_rbb[65], show_v_b[RLC_MAX_SNS + 1]; + uint16_t mod_sns = tbf->sns - 1; + uint16_t mod_sns_half = (tbf->sns >> 1) - 1; + int i; /* must be signed */ + int16_t dist; /* must be signed */ + uint8_t bit; + uint16_t bsn; + struct msgb *msg; + + LOGP(DRLCMACDL, LOGL_INFO, "TFI=%d downlink acknowledge\n", + tbf->tfi); + + if (!final) { + /* show received array in debug (bit 64..1) */ + for (i = 63; i >= 0; i--) { + bit = (rbb[i >> 3] >> (7 - (i&7))) & 1; + show_rbb[i] = (bit) ? '1' : 'o'; + } + show_rbb[64] = '\0'; + LOGP(DRLCMACDL, LOGL_DEBUG, "- ack: (BSN=%d)\"%s\"" + "(BSN=%d) 1=ACK o=NACK\n", ssn - 64, show_rbb, + ssn - 1); + + /* apply received array to receive state (SSN-64..SSN-1) */ + /* calculate distance of ssn from V(S) */ + dist = (tbf->dir.dl.v_s - ssn) & mod_sns; + /* check if distance is less than distance V(A)..V(S) */ + if (dist < ((tbf->dir.dl.v_s - tbf->dir.dl.v_a) & mod_sns)) { + /* SSN - 1 is in range V(A)..V(S)-1 */ + for (i = 63, bsn = (ssn - 1) & mod_sns; + i >= 0 && bsn != ((tbf->dir.dl.v_a - 1) & mod_sns); + i--, bsn = (bsn - 1) & mod_sns) { + bit = (rbb[i >> 3] >> (7 - (i&7))) & 1; + if (bit) { + LOGP(DRLCMACDL, LOGL_DEBUG, "- got " + "ack for BSN=%d\n", bsn); + tbf->dir.dl.v_b[bsn & mod_sns_half] + = 'A'; + } else { + LOGP(DRLCMACDL, LOGL_DEBUG, "- got " + "NACK for BSN=%d\n", bsn); + tbf->dir.dl.v_b[bsn & mod_sns_half] + = 'N'; + } + } + } else { + LOGP(DRLCMACDL, LOGL_DEBUG, "- ack range is out of " + "V(A)..V(S) range\n"); + } + + /* raise V(A), if possible */ + for (i = 0, bsn = tbf->dir.dl.v_a; bsn != tbf->dir.dl.v_s; + i++, bsn = (bsn + 1) & mod_sns) { + if (tbf->dir.dl.v_b[bsn & mod_sns_half] == 'A') { + tbf->dir.dl.v_b[bsn & mod_sns_half] = 'I'; + /* mark invalid */ + tbf->dir.dl.v_a = (tbf->dir.dl.v_a + 1) + & mod_sns; + } else + break; + } + + /* show receive state array in debug (V(A)..V(S)-1) */ + for (i = 0, bsn = tbf->dir.dl.v_a; bsn != tbf->dir.dl.v_s; + i++, bsn = (bsn + 1) & mod_sns) { + show_v_b[i] = tbf->dir.dl.v_b[bsn & mod_sns_half]; + if (show_v_b[i] == 0) + show_v_b[i] = ' '; + } + show_v_b[i] = '\0'; + LOGP(DRLCMACDL, LOGL_DEBUG, "- V(B): (V(A)=%d)\"%s\"" + "(V(S)-1=%d) A=Acked N=Nacked U=Unacked " + "X=Resend-Unacked\n", tbf->dir.dl.v_a, show_v_b, + (tbf->dir.dl.v_s - 1) & mod_sns); + + return 0; + } + + LOGP(DRLCMACDL, LOGL_DEBUG, "- Final ACK received.\n"); + + /* check for LLC PDU in the LLC Queue */ + msg = msgb_dequeue(&tbf->llc_queue); + if (!msg) { + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + + /* no message, start T3193, change state to RELEASE */ + LOGP(DRLCMACDL, LOGL_DEBUG, "- No new message, so we " + "release.\n"); + /* use T3192 for T3193 */ + if (bts->t3192_msec) + tbf_timer_start(tbf, 3193, bts->t3192_msec / 1000, + bts->t3192_msec & 1000); + else + tbf_timer_start(tbf, 3193, T3193); /* max T3192 */ + tbf_new_state(tbf, GPRS_RLCMAC_WAIT_RELEASE); + + return 0; + } + memcpy(tbf->llc_frame, msg->data, msg->len); + tbf->llc_length = msg->len; + msgb_free(msg); + + /* we have a message, so we trigger downlink assignment, and there + * set the state to ASSIGN. also we set old_downlink, because we + * re-use this tbf. */ + LOGP(DRLCMAC, LOGL_DEBUG, "Trigger dowlink assignment on PACCH, " + "because another LLC PDU has arrived in between\n"); + memset(&tbf->dir.dl, 0, sizeof(tbf->dir.dl)); /* reset RLC states */ + gprs_rlcmac_trigger_downlink_assignment(tbf, 1); + return 0; } + +struct msgb *gprs_rlcmac_send_packet_downlink_assignment( + struct gprs_rlcmac_tbf *tbf, uint32_t fn) +{ + struct msgb *msg; + struct gprs_rlcmac_tbf *new_tbf; + + if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE) { + LOGP(DRLCMACDL, LOGL_DEBUG, "Polling is already " + "sheduled for TBF=%d, so we must wait for downlink " + "assignment...\n", tbf->tfi); + return NULL; + } + + /* on uplink TBF we get the downlink TBF to be assigned. */ + if (tbf->direction == GPRS_RLCMAC_UL_TBF) + new_tbf = tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_DL_TBF); + else + new_tbf = tbf; + if (!new_tbf) { + LOGP(DRLCMACDL, LOGL_ERROR, "We have a schedule for downlink " + "assignment at uplink TBF=%d, but there is no downlink " + "TBF\n", tbf->tfi); + tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; + return NULL; + } + + msg = msgb_alloc(23, "rlcmac_dl_ass"); + if (!msg) + return NULL; + bitvec *ass_vec = bitvec_alloc(23); + if (!ass_vec) { + msgb_free(msg); + return NULL; + } + bitvec_unhex(ass_vec, + "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); + write_packet_downlink_assignment(ass_vec, tbf->tfi, + (tbf->direction == GPRS_RLCMAC_DL_TBF), new_tbf->tfi, + new_tbf->arfcn, new_tbf->ts, new_tbf->ta, new_tbf->tsc, + POLLING_ASSIGNMENT); + bitvec_pack(ass_vec, msgb_put(msg, 23)); + RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)malloc(sizeof(RlcMacDownlink_t)); + LOGP(DRLCMAC, LOGL_NOTICE, "+++++++++++++++++++++++++ TX : Packet Downlink Assignment +++++++++++++++++++++++++\n"); + decode_gsm_rlcmac_downlink(ass_vec, mac_control_block); + LOGPC(DRLCMAC, LOGL_NOTICE, "\n"); + LOGP(DRLCMAC, LOGL_NOTICE, "------------------------- TX : Packet Downlink Assignment -------------------------\n"); + bitvec_free(ass_vec); + +#if POLLING_ASSIGNMENT == 1 + tbf->poll_state = GPRS_RLCMAC_POLL_SCHED; + tbf->poll_fn = (fn + 13) % 2715648; + tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_WAIT_ACK; +#else + tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; +#endif + + return msg; +} + +static void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf, uint8_t poll) +{ + LOGP(DRLCMAC, LOGL_NOTICE, "TX: [PCU -> BTS] TFI: %u TLLI: 0x%08x Immidiate Assignment (CCCH)\n", tbf->tfi, tbf->tlli); + bitvec *immediate_assignment = bitvec_alloc(23); + bitvec_unhex(immediate_assignment, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"); + /* use request reference that has maximum distance to current time, + * so the assignment will not conflict with possible RACH requests. */ + int len = 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); + pcu_l1if_tx_agch(immediate_assignment, len); + bitvec_free(immediate_assignment); +} + +/* depending on the current TBF, we assign on PACCH or AGCH */ +void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf, + uint8_t old_downlink) +{ + gprs_rlcmac_tbf *old_tbf; + +#ifdef DEBUG_DL_ASS_IDLE + LOGP(DRLCMAC, LOGL_ERROR, "**** DEBUGGING DOWNLINK ASSIGNMENT ****\n"); +#endif + + /* stop pending timer */ + tbf_timer_stop(tbf); + + /* check for downlink tbf: */ + if (old_downlink) + old_tbf = tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_DL_TBF); + else + old_tbf = tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_UL_TBF); + if (old_tbf) { +#ifdef DEBUG_DL_ASS_IDLE + LOGP(DRLCMAC, LOGL_ERROR, "We must wait for current TBF to be " + "released.\n"); + /* wait one second until assignment */ + tbf_timer_start(tbf, 1234, 1,0); +#else + LOGP(DRLCMAC, LOGL_DEBUG, "Trigger dowlink assignment on " + "PACCH, because %slink TBF=%d exists for TLLI\n", + (tbf->direction == GPRS_RLCMAC_DL_TBF) ? "down" : "up", + old_tbf->tfi); + old_tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_SEND_ASS; + /* use TA from old TBF */ + tbf->ta = old_tbf->ta; + /* change state */ + tbf_new_state(tbf, GPRS_RLCMAC_ASSIGN); + /* start timer */ + tbf_timer_start(tbf, 0, Tassign_pacch); +#endif + } else { + LOGP(DRLCMAC, LOGL_DEBUG, "Trigger dowlink assignment on AGCH, " + "because no uplink/downlink TBF exists for TLLI. " + "(providing last timing advance)\n"); + /* send immediate assignment */ + gprs_rlcmac_downlink_assignment(tbf, 0); + /* change state */ + tbf_new_state(tbf, GPRS_RLCMAC_ASSIGN); + /* start timer */ + tbf_timer_start(tbf, 0, Tassign_agch); + } + } + diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp index 6ccb26c7..4a4b85ca 100644 --- a/src/gprs_rlcmac_sched.cpp +++ b/src/gprs_rlcmac_sched.cpp @@ -52,6 +52,9 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, return -EIO; } + /* store last frame number of RTS */ + pdch->last_rts_fn = fn; + /* check uplink ressource for polling */ poll_fn = fn + 4; if ((block_nr % 3) == 2) @@ -75,8 +78,6 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, "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); - /* reset poll state */ - tbf->poll_state = GPRS_RLCMAC_POLL_NONE; /* use free USF */ /* else, we search for uplink ressource */ } else { @@ -91,40 +92,47 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, 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 + * for packet control ack. */ if (tbf->state != GPRS_RLCMAC_FLOW) continue; - break; - } - if (i < 32) { + /* use this USF */ usf = tbf->dir.ul.usf; 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 " - "TFB=%d\n", trx, ts, fn, block_nr, usf, tfi); - /* next TFB to handle ressource is the next one */ + "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; } } /* Prio 1: select control message */ - if (!msg) { - for (tfi = 0; tfi < 32; tfi++) { - tbf = pdch->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; - if (tbf->dir.ul.substate == GPRS_RLCMAC_UL_SEND_ACK) - break; - } - if (tfi < 32) { - LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling control " - "message at RTS for TFB=%d\n", tfi); - /* generate ack message */ + for (tfi = 0; tfi < 32; tfi++) { + tbf = pdch->tbf[tfi]; + /* no TBF for this tfi, go next */ + if (!tbf) + continue; + /* schedule PACKET DOWNLINK ASSIGNMENT */ + if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_SEND_ASS) + msg = gprs_rlcmac_send_packet_downlink_assignment(tbf, + fn); + else + /* schedule PACKET UPLINK ASSIGNMENT */ + if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_SEND_ASS) + msg = gprs_rlcmac_send_packet_uplink_assignment(tbf, + fn); + else + /* schedule PACKET UPLINK ACK */ + if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_SEND_ACK) msg = gprs_rlcmac_send_uplink_ack(tbf, fn); + if (msg) { + LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling control " + "message at RTS for TBF=%d\n", tfi); + break; } } @@ -137,22 +145,22 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, /* no TBF for this tfi, go next */ if (!tbf) continue; - /* no DD TBF, go next */ + /* no DL TBF, go next */ if (tbf->direction != GPRS_RLCMAC_DL_TBF) continue; - /* FIXME: */ - } - if (i < 32) { + /* no DL ressources needed, go next */ + if (tbf->state != GPRS_RLCMAC_FLOW + && tbf->state != GPRS_RLCMAC_FINISHED) + continue; + LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling data " - "message at RTS for TFB=%d\n", tfi); - /* next TFB to handle ressource is the next one */ + "message at RTS for TBF=%d\n", tfi); + /* next TBF to handle ressource is the next one */ pdch->next_dl_tfi = (tfi + 1) & 31; - /* generate ack message */ - /* FIXME: */ + /* generate DL data block */ + msg = gprs_rlcmac_send_data_block_acknowledged(tbf, fn); + break; } -/* FIXME: remove that when DL TBF is finished */ -set_current_fn(fn); -msg = msgb_dequeue(&block_queue); } /* Prio 3: send dummy contol message */ diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index c73a789c..0652a1c6 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -216,6 +216,10 @@ int pcu_l1if_handle_l1prim(struct femtol1_hdl *fl1, struct msgb *msg) return rc; } +PCU will currently not work without getting a GSM time or BFI indidication. +In order to fix this, i will discuss this on the mailing list. +Andreas + /* OpenBTS socket functions */ // TODO: We should move this parameters to config file. diff --git a/src/pcu_l1_if.h b/src/pcu_l1_if.h index 5d40cd1d..b8cc5c95 100644 --- a/src/pcu_l1_if.h +++ b/src/pcu_l1_if.h @@ -30,7 +30,6 @@ extern "C" { } int get_current_fn(); -void set_current_fn(int fn); void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, uint32_t fn, uint8_t block_nr); diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index ece78f1a..c3712954 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -58,6 +58,7 @@ int main(int argc, char *argv[]) gprs_rlcmac_bts = talloc_zero(NULL, struct gprs_rlcmac_bts); if (!gprs_rlcmac_bts) return -ENOMEM; + gprs_rlcmac_bts->cs = 1; osmo_init_logging(&gprs_log_info); pcu_l1if_open(); diff --git a/src/sysmo_l1_if.cpp b/src/sysmo_l1_if.cpp index a83f0f81..106d40bf 100644 --- a/src/sysmo_l1_if.cpp +++ b/src/sysmo_l1_if.cpp @@ -242,6 +242,17 @@ static int pcu_rx_info_ind(struct gsm_pcu_if_info_ind *info_ind) if (!(info_ind->flags & PCU_IF_FLAG_ACTIVE)) { LOGP(DL1IF, LOGL_NOTICE, "BTS not available\n"); + /* free all TBF */ + for (trx = 0; trx < 8; trx++) { + 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]; + if (tbf) + tbf_free(tbf); + } + } + } return 0; } LOGP(DL1IF, LOGL_INFO, "BTS available\n"); @@ -280,6 +291,43 @@ static int pcu_rx_info_ind(struct gsm_pcu_if_info_ind *info_ind) return rc; } +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; + + /* omit frame numbers not starting at a MAC block */ + if (fn13 != 0 && fn13 != 4 && fn13 != 8) + return 0; + + LOGP(DL1IF, LOGL_DEBUG, "Time indication received: %d\n", + time_ind->fn % 52); + + 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); + } + } + } + + return 0; +} + static int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim) { int rc = 0; @@ -297,6 +345,9 @@ static int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim) case PCU_IF_MSG_INFO_IND: rc = pcu_rx_info_ind(&pcu_prim->u.info_ind); break; + case PCU_IF_MSG_TIME_IND: + rc = pcu_rx_time_ind(&pcu_prim->u.time_ind); + break; default: LOGP(DL1IF, LOGL_ERROR, "Received unknwon PCU msg type %d\n", msg_type); diff --git a/src/tbf.txt b/src/tbf.txt new file mode 100644 index 00000000..3c06b39c --- /dev/null +++ b/src/tbf.txt @@ -0,0 +1,111 @@ +This document describes the handling of TBFs +-------------------------------------------- + +Notes: + TBF + Instance for one temporary block flow. + + LLC Frame + Current frame to be transmitted or received. If tbf->llc_length is not 0, + the frame exists, if 0, the frame does not exist. If tbf->llc_index is not + 0, parts of the frame have been transmitted or received so far. + + LLC Queue + Queue of next frames to be transmitted. + +States: + GPRS_RLCMAC_ASSIGN + After a downlink TBF is created, it resides in this state until the + block flow can start. This is required to give the mobile time to listen + to connect to downlink PDCH. + + GPRS_RLCMAC_FLOW, + During packet flow, this state indicates downlink and uplink TBF block + flow. + + GPRS_RLCMAC_FINISHED, + Uplink TBF: + After final block is received AND all other blocks are completely + received, the state is entered. The PACKET CONTROL ACK is still not + received. (Counter N3103 is counted on each poll request.) + Downlink TBF: + All blocks including the final block has been transmitted. Not all + downlink blocks are acknowledged yet. (Counter N3015 is counted on each + poll request.) + + GPRS_RLCMAC_WAIT_RELEASE, + The all blocks on downlink TBF have been acked by mobile. The penalty + timer T3192 is running on mobile. + + GPRS_RLCMAC_RELEASING, + Wait for TFI/USF to be re-used. This state is entered when a counter + reaches it's maximum and T3169 is running. + + +When downlink LLC PDU is received: + + If downlink TBF exists for given TLLI, but not in RELEASING state: + If downlink TBF is in FLOW or FINISHED state: + Enqueue PDU to LLC Queue of TBF. + Done. + If downlink TBF is in WAIT RELEASE state: + Attach PDU to LLC Frame of TBF. + Put TBF back into FLOW state. + Done. + If dowlink TBF does not exists for given TLLI, or in RELEASING state: + Create new downlink TBF. + Attach PDU to LLC Frame of TBF. + If uplink TBF exists for given TLLI, but not in RELEASING state: + Assign packet channel PACCH. + Done. + If uplink TBF does not exists for given TLLI, or in RELEASING state: + Assign packet channel AGCH. + Done. + +When channel request for uplink TBF is received: + + Create new uplink TBF. + If channel request was received on RACH + Assign packet channel AGCH. + Done + If channel request was received on PACCH + Assign packet channel PACCH. + Done + +Handling of LLC Frame of downlink TBF and LLC Queue of downlink TBF: + + If a downlink TBF is created, the LLC PDU is attached to LLC Frame of TBF + (downlink flow is assigned to MS). + + If a downlink TBF exists, the LLC PDU is enqueued to LLC Queue of TBF. + + During transfer of downlink blocks, the LLC Queue is dequeued whenever all + segments of LLC Frame were used for generation of downlink blocks. (If a + block is partly filled with LLC Frame segment, its remaining space is filled + with the next LLC Frame from the Queue.) + + If the transfer is finished, no more LLC Frames are dequeued from the LLC + Queue, in case a new frame has arrived during lifetime of TBF. + + If the all downlink blocks have been acknowledged, the LLC Queue is + dequeued and an existing frame is attached to LLC Frame. If so, the new + state is FLOW (downlink flow is assigned to MS), otherwise WAIT RELEASE. + + If a new LLC PDU is attached to LLC Frame during WAIT RELEASE state, the + state is changed to FLOW (downlink flow is assigned to MS). + +Handling of LLC Frame on uplink TBF: + + Received uplink blocks are appended to LLC Frame of TBF. If the PDU is + complete, it is forwarded to the upper layer. + +Polling: + In order to poll uplink control block from MS, a special poll state and + frame number is stored at TBF. The scheduler reads that value and will not + assign uplink ressource for other TBFs at that frame number. + + When there is no uplink transmission received on the block, a timeout is + indicated by layer 1 interface. There are two ways of checking timeout: + - The received frame is bad (BFI). + - The GSM indicates that the block should have been already received. + |