aboutsummaryrefslogtreecommitdiffstats
path: root/src/bts.cpp
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2016-01-13 13:55:44 +0100
committerJacob Erlbeck <jerlbeck@sysmocom.de>2016-02-08 00:45:34 +0100
commitae9c575d2c2e7f906c41d28682445e6c8cb53f03 (patch)
treeb9236fb18dc558431e8fa398b530de4fcb06641f /src/bts.cpp
parentc2141c6064ddf5283937c7f77468bf2396787804 (diff)
edge: Handle EGPRS PACKET DOWNLINK ACK NACK
Currently this message is ignored. Support decoding and handling of this message. Use a bitvec for the decoder that just represents a BSN sequence without any encoding details (first bit -> first BSN). Return the corresponding BSN range (snsmod(bsn_begin + bits_in_bitvec) = bsn_end), so snsmod(bsn_end-1) is the last BSN if there is at least 1. If bsn_begin == bsn_end, no BSNs has been added. Note that this bitvec is not yet used for RBB handling. It just calls the old rcvd_dl_ack with a faked (all bits are 1) RBB map. Sponsored-by: On-Waves ehf
Diffstat (limited to 'src/bts.cpp')
-rw-r--r--src/bts.cpp120
1 files changed, 120 insertions, 0 deletions
diff --git a/src/bts.cpp b/src/bts.cpp
index 18bee665..16961454 100644
--- a/src/bts.cpp
+++ b/src/bts.cpp
@@ -946,6 +946,123 @@ void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_n
}
}
+void gprs_rlcmac_pdch::rcv_control_egprs_dl_ack_nack(EGPRS_PD_AckNack_t *ack_nack, uint32_t fn)
+{
+ int8_t tfi = 0; /* must be signed */
+ struct gprs_rlcmac_dl_tbf *tbf;
+ struct pcu_l1_meas meas;
+ int rc;
+ int num_blocks;
+ uint8_t bits_data[RLC_EGPRS_MAX_WS/8];
+ char show_bits[RLC_EGPRS_MAX_WS + 1];
+ bitvec bits;
+ int bsn_begin, bsn_end;
+
+ tfi = ack_nack->DOWNLINK_TFI;
+ tbf = bts()->dl_tbf_by_poll_fn(fn, trx_no(), ts_no);
+ if (!tbf) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "EGPRS PACKET DOWNLINK ACK with "
+ "unknown FN=%u TFI=%d (TRX %d TS %d)\n",
+ fn, tfi, trx_no(), ts_no);
+ return;
+ }
+ if (tbf->tfi() != tfi) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "EGPRS PACKET DOWNLINK ACK with "
+ "wrong TFI=%d, ignoring!\n", tfi);
+ return;
+ }
+ tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_DL_ACK);
+ if ((tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK))) {
+ tbf->state_flags &= ~(1 << GPRS_RLCMAC_FLAG_TO_DL_ACK);
+ LOGP(DRLCMAC, LOGL_NOTICE, "Recovered EGPRS downlink ack "
+ "for %s\n", tbf_name(tbf));
+ }
+ /* reset N3105 */
+ tbf->n3105 = 0;
+ tbf->stop_t3191();
+ LOGP(DRLCMAC, LOGL_DEBUG,
+ "RX: [PCU <- BTS] %s EGPRS Packet Downlink Ack/Nack\n",
+ tbf_name(tbf));
+ tbf->poll_state = GPRS_RLCMAC_POLL_NONE;
+
+ LOGP(DRLCMAC, LOGL_DEBUG, "EGPRS ACK/NACK: "
+ "ut: %d, final: %d, bow: %d, eow: %d, ssn: %d, have_crbb: %d, "
+ "urbb_len:%d, %p, %p, %d, %d, win: %d-%d, urbb: %s\n",
+ (int)ack_nack->EGPRS_AckNack.UnionType,
+ (int)ack_nack->EGPRS_AckNack.Desc.FINAL_ACK_INDICATION,
+ (int)ack_nack->EGPRS_AckNack.Desc.BEGINNING_OF_WINDOW,
+ (int)ack_nack->EGPRS_AckNack.Desc.END_OF_WINDOW,
+ (int)ack_nack->EGPRS_AckNack.Desc.STARTING_SEQUENCE_NUMBER,
+ (int)ack_nack->EGPRS_AckNack.Desc.Exist_CRBB,
+ (int)ack_nack->EGPRS_AckNack.Desc.URBB_LENGTH,
+ (void *)&ack_nack->EGPRS_AckNack.UnionType,
+ (void *)&ack_nack->EGPRS_AckNack.Desc,
+ (int)offsetof(EGPRS_AckNack_t, Desc),
+ (int)offsetof(EGPRS_AckNack_w_len_t, Desc),
+ tbf->m_window.v_a(),
+ tbf->m_window.v_s(),
+ osmo_hexdump((const uint8_t *)&ack_nack->EGPRS_AckNack.Desc.URBB,
+ sizeof(ack_nack->EGPRS_AckNack.Desc.URBB)));
+
+ bits.data = bits_data;
+ bits.data_len = sizeof(bits_data);
+ bits.cur_bit = 0;
+
+ num_blocks = Decoding::decode_egprs_acknack_bits(
+ &ack_nack->EGPRS_AckNack.Desc, &bits,
+ &bsn_begin, &bsn_end, &tbf->m_window);
+
+ for (int i = 0; i < num_blocks; i++) {
+ show_bits[i] = bitvec_get_bit_pos(&bits, i) ? 'R' : 'I';
+ }
+ show_bits[num_blocks] = 0;
+
+ LOGP(DRLCMAC, LOGL_DEBUG,
+ "EGPRS DL ACK bitmap: BSN %d to %d - 1 (%d blocks): %s\n",
+ bsn_begin, bsn_end, num_blocks, show_bits);
+
+ if (ack_nack->EGPRS_AckNack.Desc.URBB_LENGTH == 0 &&
+ !ack_nack->EGPRS_AckNack.Desc.Exist_CRBB)
+ {
+ /* Everything has been received successfully */
+ /* Fake a GPRS type ack */
+ uint64_t fake_map = -1;
+
+ rc = tbf->rcvd_dl_ack(
+ ack_nack->EGPRS_AckNack.Desc.FINAL_ACK_INDICATION,
+ tbf->m_window.mod_sns(ack_nack->EGPRS_AckNack.Desc.STARTING_SEQUENCE_NUMBER-1),
+ (uint8_t *)&fake_map);
+
+ if (rc == 1) {
+ tbf_free(tbf);
+ return;
+ }
+ }
+
+ /* check for channel request */
+ if (ack_nack->Exist_ChannelRequestDescription) {
+ LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack "
+ "message, so we provide one:\n");
+
+ /* This call will register the new TBF with the MS on success */
+ tbf_alloc_ul(bts_data(), tbf->trx->trx_no,
+ tbf->ms_class(), tbf->ms()->egprs_ms_class(),
+ tbf->tlli(), tbf->ta(), tbf->ms());
+
+ /* schedule uplink assignment */
+ tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
+ }
+
+ /* get measurements */
+ if (tbf->ms()) {
+ /* TODO: Implement Measurements parsing for EGPRS */
+ /*
+ get_meas(&meas, &ack_nack->Channel_Quality_Report);
+ tbf->ms()->update_l1_meas(&meas);
+ */
+ }
+}
+
void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request, uint32_t fn)
{
struct gprs_rlcmac_sba *sba;
@@ -1105,6 +1222,9 @@ int gprs_rlcmac_pdch::rcv_control_block(
case MT_PACKET_DOWNLINK_ACK_NACK:
rcv_control_dl_ack_nack(&ul_control_block->u.Packet_Downlink_Ack_Nack, fn);
break;
+ case MT_EGPRS_PACKET_DOWNLINK_ACK_NACK:
+ rcv_control_egprs_dl_ack_nack(&ul_control_block->u.Egprs_Packet_Downlink_Ack_Nack, fn);
+ break;
case MT_PACKET_RESOURCE_REQUEST:
rcv_resource_request(&ul_control_block->u.Packet_Resource_Request, fn);
break;