From 5daf94b2033ca5cd4bb5f6b72b8e3cbf710adc12 Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Mon, 20 Feb 2023 17:46:29 +0100 Subject: [PATCH] rlcmac: ul_tbf: Answer Pkt Ul Ack/Nack poll with Pkt Ctrl Ack Related: OS#5500 Change-Id: I833d0f189c06d093ce9bd4c36c37024cf5cb6446 --- include/osmocom/gprs/rlcmac/rlcmac_enc.h | 2 + include/osmocom/gprs/rlcmac/tbf_ul.h | 5 +- src/rlcmac/rlcmac.c | 29 +++-------- src/rlcmac/rlcmac_enc.c | 13 +++++ src/rlcmac/sched.c | 11 +++- src/rlcmac/tbf_ul.c | 66 ++++++++++++++++++++++-- tests/rlcmac/rlcmac_prim_test.c | 9 ++++ tests/rlcmac/rlcmac_prim_test.err | 4 ++ tests/rlcmac/rlcmac_prim_test.ok | 1 + 9 files changed, 112 insertions(+), 28 deletions(-) diff --git a/include/osmocom/gprs/rlcmac/rlcmac_enc.h b/include/osmocom/gprs/rlcmac/rlcmac_enc.h index 1a0f586..406109a 100644 --- a/include/osmocom/gprs/rlcmac/rlcmac_enc.h +++ b/include/osmocom/gprs/rlcmac/rlcmac_enc.h @@ -48,3 +48,5 @@ void gprs_rlcmac_enc_prepare_pkt_ul_dummy_block(RlcMacUplink_t *block, uint32_t void gprs_rlcmac_enc_prepare_pkt_resource_req(RlcMacUplink_t *block, struct gprs_rlcmac_ul_tbf *ul_tbf, enum gprs_rlcmac_access_type acc_type); void gprs_rlcmac_enc_prepare_pkt_downlink_ack_nack(RlcMacUplink_t *block, const struct gprs_rlcmac_dl_tbf *dl_tbf); + +void gprs_rlcmac_enc_prepare_pkt_ctrl_ack(RlcMacUplink_t *block, uint32_t tlli); diff --git a/include/osmocom/gprs/rlcmac/tbf_ul.h b/include/osmocom/gprs/rlcmac/tbf_ul.h index c187938..32d7036 100644 --- a/include/osmocom/gprs/rlcmac/tbf_ul.h +++ b/include/osmocom/gprs/rlcmac/tbf_ul.h @@ -52,9 +52,10 @@ bool gprs_rlcmac_ul_tbf_dummy_rts(const struct gprs_rlcmac_ul_tbf *ul_tbf, const struct msgb *gprs_rlcmac_ul_tbf_data_create(struct gprs_rlcmac_ul_tbf *ul_tbf, const struct gprs_rlcmac_rts_block_ind *bi); struct msgb *gprs_rlcmac_ul_tbf_dummy_create(const struct gprs_rlcmac_ul_tbf *ul_tbf); +struct msgb *gprs_rlcmac_ul_tbf_create_pkt_ctrl_ack(const struct gprs_rlcmac_ul_tbf *ul_tbf); -int gprs_rlcmac_ul_tbf_handle_pkt_ul_ack_nack(struct gprs_rlcmac_ul_tbf *ul_tbf, bool final_ack, - unsigned first_bsn, struct bitvec *rbb); +int gprs_rlcmac_ul_tbf_handle_pkt_ul_ack_nack(struct gprs_rlcmac_ul_tbf *ul_tbf, + const RlcMacDownlink_t *dl_block); static inline struct gprs_rlcmac_tbf *ul_tbf_as_tbf(struct gprs_rlcmac_ul_tbf *ul_tbf) { diff --git a/src/rlcmac/rlcmac.c b/src/rlcmac/rlcmac.c index 39e5c9e..b273b68 100644 --- a/src/rlcmac/rlcmac.c +++ b/src/rlcmac/rlcmac.c @@ -320,19 +320,7 @@ int gprs_rlcmac_handle_bcch_si13(const struct gsm48_system_information_type_13 * static int gprs_rlcmac_handle_pkt_ul_ack_nack(const struct osmo_gprs_rlcmac_prim *rlcmac_prim, const RlcMacDownlink_t *dl_block) { - const Packet_Uplink_Ack_Nack_t *ack = &dl_block->u.Packet_Uplink_Ack_Nack; - const PU_AckNack_GPRS_t *gprs = &ack->u.PU_AckNack_GPRS_Struct; - const Ack_Nack_Description_t *ack_desc = &gprs->Ack_Nack_Description; struct gprs_rlcmac_ul_tbf *ul_tbf; - int bsn_begin, bsn_end; - int num_blocks; - uint8_t bits_data[GPRS_RLCMAC_GPRS_WS/8]; - char show_bits[GPRS_RLCMAC_GPRS_WS + 1]; - struct bitvec bits = { - .data = bits_data, - .data_len = sizeof(bits_data), - .cur_bit = 0, - }; int rc; ul_tbf = gprs_rlcmac_find_ul_tbf_by_tfi(dl_block->TFI); @@ -344,16 +332,15 @@ static int gprs_rlcmac_handle_pkt_ul_ack_nack(const struct osmo_gprs_rlcmac_prim return -ENOENT; } - num_blocks = gprs_rlcmac_decode_gprs_acknack_bits( - ack_desc, &bits, &bsn_begin, &bsn_end, ul_tbf->ulw); + rc = gprs_rlcmac_ul_tbf_handle_pkt_ul_ack_nack(ul_tbf, dl_block); - LOGPTBFUL(ul_tbf, LOGL_DEBUG, - "Got GPRS UL ACK bitmap: SSN: %d, BSN %d to %d - 1 (%d blocks), \"%s\"\n", - ack_desc->STARTING_SEQUENCE_NUMBER, - bsn_begin, bsn_end, num_blocks, - (gprs_rlcmac_extract_rbb(&bits, show_bits), show_bits)); - - rc = gprs_rlcmac_ul_tbf_handle_pkt_ul_ack_nack(ul_tbf, ack_desc->FINAL_ACK_INDICATION, bsn_begin, &bits); + /* If RRBP contains valid data, schedule a response (PKT CONTROL ACK or PKT RESOURCE REQ). */ + if (dl_block->SP) { + uint32_t poll_fn = rrbp2fn(rlcmac_prim->l1ctl.pdch_data_ind.fn, dl_block->RRBP); + gprs_rlcmac_pdch_ulc_reserve(g_ctx->sched.ulc[rlcmac_prim->l1ctl.pdch_data_ind.ts_nr], poll_fn, + GPRS_RLCMAC_PDCH_ULC_POLL_UL_ACK, + ul_tbf_as_tbf(ul_tbf)); + } return rc; } diff --git a/src/rlcmac/rlcmac_enc.c b/src/rlcmac/rlcmac_enc.c index dbebc4f..4b8c469 100644 --- a/src/rlcmac/rlcmac_enc.c +++ b/src/rlcmac/rlcmac_enc.c @@ -410,3 +410,16 @@ void gprs_rlcmac_enc_prepare_pkt_downlink_ack_nack(RlcMacUplink_t *block, const gprs_rlcmac_enc_prepare_channel_quality_report(&ack->Channel_Quality_Report, dl_tbf); } + +void gprs_rlcmac_enc_prepare_pkt_ctrl_ack(RlcMacUplink_t *block, uint32_t tlli) +{ + Packet_Control_Acknowledgement_t *ctrl_ack = &block->u.Packet_Control_Acknowledgement; + + memset(block, 0, sizeof(*block)); + ctrl_ack->MESSAGE_TYPE = OSMO_GPRS_RLCMAC_UL_MSGT_PACKET_CONTROL_ACK; + ctrl_ack->PayloadType = GPRS_RLCMAC_PT_CONTROL_BLOCK; + ctrl_ack->R = 0; /* MS sent channel request message once */ + + ctrl_ack->TLLI = tlli; + ctrl_ack->CTRL_ACK = 0; /* not clear what this should be set to. TS 44.060 Table 11.2.2.2 */ +} diff --git a/src/rlcmac/sched.c b/src/rlcmac/sched.c index 6a31f83..5a3fae8 100644 --- a/src/rlcmac/sched.c +++ b/src/rlcmac/sched.c @@ -34,6 +34,7 @@ struct tbf_sched_ctrl_candidates { struct gprs_rlcmac_dl_tbf *poll_dl_ack_final_ack; /* 8.1.2.2 1) */ struct gprs_rlcmac_dl_tbf *poll_dl_ack; /* 8.1.2.2 7) */ + struct gprs_rlcmac_ul_tbf *poll_ul_ack; /* 11.2.2 (answer with PKT CTRL ACK) */ struct gprs_rlcmac_ul_tbf *ul_ass; }; @@ -88,7 +89,8 @@ static void get_ctrl_msg_tbf_candidates(const struct gprs_rlcmac_rts_block_ind * /* TODO */ break; case GPRS_RLCMAC_PDCH_ULC_POLL_UL_ACK: - /* TODO */ + ul_tbf = tbf_as_ul_tbf(node->tbf); + tbfs->poll_ul_ack = ul_tbf; break; case GPRS_RLCMAC_PDCH_ULC_POLL_DL_ACK: dl_tbf = tbf_as_dl_tbf(node->tbf); @@ -156,6 +158,13 @@ static struct msgb *sched_select_ctrl_msg(const struct gprs_rlcmac_rts_block_ind } /* 8.1.2.2 5) Any other RLC/MAC control message, other than a (EGPRS) PACKET DOWNLINK ACK/NACK */ + if (tbfs->poll_ul_ack) { + LOGRLCMAC(LOGL_DEBUG, "(ts=%u,fn=%u,usf=%u) Tx Pkt Control Ack (UL ACK/NACK poll)\n", + bi->ts, bi->fn, bi->usf); + msg = gprs_rlcmac_ul_tbf_create_pkt_ctrl_ack(tbfs->poll_ul_ack); + if (msg) + return msg; + } if (tbfs->ul_ass) { msg = gprs_rlcmac_tbf_ul_ass_create_rlcmac_msg(tbfs->ul_ass, bi); if (msg) diff --git a/src/rlcmac/tbf_ul.c b/src/rlcmac/tbf_ul.c index 964f1ad..60bb0a2 100644 --- a/src/rlcmac/tbf_ul.c +++ b/src/rlcmac/tbf_ul.c @@ -199,16 +199,38 @@ int gprs_rlcmac_ul_tbf_handle_final_ack(struct gprs_rlcmac_ul_tbf *ul_tbf) return rc; } -int gprs_rlcmac_ul_tbf_handle_pkt_ul_ack_nack(struct gprs_rlcmac_ul_tbf *ul_tbf, bool final_ack, - unsigned first_bsn, struct bitvec *rbb) +int gprs_rlcmac_ul_tbf_handle_pkt_ul_ack_nack(struct gprs_rlcmac_ul_tbf *ul_tbf, + const RlcMacDownlink_t *dl_block) { + const Packet_Uplink_Ack_Nack_t *ack = &dl_block->u.Packet_Uplink_Ack_Nack; + const PU_AckNack_GPRS_t *gprs = &ack->u.PU_AckNack_GPRS_Struct; + const Ack_Nack_Description_t *ack_desc = &gprs->Ack_Nack_Description; + int bsn_begin, bsn_end; + int num_blocks; + uint8_t bits_data[GPRS_RLCMAC_GPRS_WS/8]; + char show_bits[GPRS_RLCMAC_GPRS_WS + 1]; + struct bitvec bits = { + .data = bits_data, + .data_len = sizeof(bits_data), + .cur_bit = 0, + }; int rc; - rc = gprs_rlcmac_ul_tbf_update_window(ul_tbf, first_bsn, rbb); + + num_blocks = gprs_rlcmac_decode_gprs_acknack_bits( + ack_desc, &bits, &bsn_begin, &bsn_end, ul_tbf->ulw); + + LOGPTBFUL(ul_tbf, LOGL_DEBUG, + "Got GPRS UL ACK bitmap: SSN: %d, BSN %d to %d - 1 (%d blocks), \"%s\"\n", + ack_desc->STARTING_SEQUENCE_NUMBER, + bsn_begin, bsn_end, num_blocks, + (gprs_rlcmac_extract_rbb(&bits, show_bits), show_bits)); + + rc = gprs_rlcmac_ul_tbf_update_window(ul_tbf, bsn_begin, &bits); if (gprs_rlcmac_ul_tbf_in_contention_resolution(ul_tbf)) osmo_fsm_inst_dispatch(ul_tbf->state_fsm.fi, GPRS_RLCMAC_TBF_UL_EV_CONTENTION_RESOLUTION_SUCCESS, NULL); - if (final_ack) { + if (ack_desc->FINAL_ACK_INDICATION) { LOGPTBFUL(ul_tbf, LOGL_DEBUG, "Final ACK received.\n"); rc = gprs_rlcmac_ul_tbf_handle_final_ack(ul_tbf); } else if (gprs_rlcmac_tbf_ul_state(ul_tbf) && @@ -216,6 +238,7 @@ int gprs_rlcmac_ul_tbf_handle_pkt_ul_ack_nack(struct gprs_rlcmac_ul_tbf *ul_tbf, LOGPTBFUL(ul_tbf, LOGL_NOTICE, "Received acknowledge of all blocks, but without final ack indication (don't worry)\n"); } + return rc; } @@ -253,6 +276,41 @@ free_ret: return NULL; } +struct msgb *gprs_rlcmac_ul_tbf_create_pkt_ctrl_ack(const struct gprs_rlcmac_ul_tbf *ul_tbf) +{ + struct msgb *msg; + struct bitvec bv; + RlcMacUplink_t ul_block; + int rc; + + OSMO_ASSERT(ul_tbf); + + msg = msgb_alloc(GSM_MACBLOCK_LEN, "pkt_ctrl_ack"); + if (!msg) + return NULL; + + /* Initialize a bit vector that uses allocated msgb as the data buffer. */ + bv = (struct bitvec){ + .data = msgb_put(msg, GSM_MACBLOCK_LEN), + .data_len = GSM_MACBLOCK_LEN, + }; + bitvec_unhex(&bv, GPRS_RLCMAC_DUMMY_VEC); + + gprs_rlcmac_enc_prepare_pkt_ctrl_ack(&ul_block, ul_tbf->tbf.gre->tlli); + rc = osmo_gprs_rlcmac_encode_uplink(&bv, &ul_block); + if (rc < 0) { + LOGPTBFUL(ul_tbf, LOGL_ERROR, "Encoding of Packet Control ACK failed (%d)\n", rc); + goto free_ret; + } + LOGPTBFUL(ul_tbf, LOGL_DEBUG, "Tx Packet Control Ack\n"); + + return msg; + +free_ret: + msgb_free(msg); + return NULL; +} + bool gprs_rlcmac_ul_tbf_have_data(const struct gprs_rlcmac_ul_tbf *ul_tbf) { return (ul_tbf->llc_tx_msg && msgb_length(ul_tbf->llc_tx_msg) > 0) || diff --git a/tests/rlcmac/rlcmac_prim_test.c b/tests/rlcmac/rlcmac_prim_test.c index cc33c4c..45b0b21 100644 --- a/tests/rlcmac/rlcmac_prim_test.c +++ b/tests/rlcmac/rlcmac_prim_test.c @@ -503,10 +503,19 @@ static void test_ul_tbf_attach(void) ack_desc->FINAL_ACK_INDICATION = 1; ul_ack_nack_mark(ack_desc, 0, true); ul_ack_nack_mark(ack_desc, 1, true); + /* Final ACK has Poll set: */ + dl_block.SP = 1; + dl_block.RRBP = GPRS_RLCMAC_RRBP_N_plus_13; rlcmac_prim = create_dl_ctrl_block(&dl_block, ts_nr, rts_fn); rc = osmo_gprs_rlcmac_prim_lower_up(rlcmac_prim); OSMO_ASSERT(rc == 0); + /* Trigger transmission of PKT CTRL ACK */ + rts_fn = rrbp2fn(rts_fn, dl_block.RRBP); + rlcmac_prim = osmo_gprs_rlcmac_prim_alloc_l1ctl_pdch_rts_ind(ts_nr, rts_fn, usf); + rc = osmo_gprs_rlcmac_prim_lower_up(rlcmac_prim); + OSMO_ASSERT(rc == 0); + printf("=== %s end ===\n", __func__); cleanup_test(); } diff --git a/tests/rlcmac/rlcmac_prim_test.err b/tests/rlcmac/rlcmac_prim_test.err index 794bfbc..a690bb0 100644 --- a/tests/rlcmac/rlcmac_prim_test.err +++ b/tests/rlcmac/rlcmac_prim_test.err @@ -53,6 +53,10 @@ DLGLOBAL INFO UL_TBF{FINISHED}: Received Event CONTENTION_RESOLUTION_SUCCESS DLGLOBAL INFO UL_TBF{FINISHED}: Contention resolution succeeded, stop T3166 DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00002342) Final ACK received. DLGLOBAL INFO UL_TBF{FINISHED}: Received Event FINAL_ACK_RECVD +DLGLOBAL DEBUG Register POLL (TS=7 FN=21, reason=UL_ACK) +DLGLOBAL INFO Rx from lower layers: L1CTL-PDCH_RTS.indication +DLGLOBAL DEBUG (ts=7,fn=21,usf=0) Tx Pkt Control Ack (UL ACK/NACK poll) +DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00002342) Tx Packet Control Ack DLGLOBAL INFO UL_TBF_ASS{IDLE}: Deallocated DLGLOBAL INFO UL_TBF{FINISHED}: Deallocated DLGLOBAL INFO Rx from upper layers: GRR-UNITDATA.request diff --git a/tests/rlcmac/rlcmac_prim_test.ok b/tests/rlcmac/rlcmac_prim_test.ok index 669738a..76cd901 100644 --- a/tests/rlcmac/rlcmac_prim_test.ok +++ b/tests/rlcmac/rlcmac_prim_test.ok @@ -4,6 +4,7 @@ test_rlcmac_prim_down_cb(): Rx L1CTL-RACH.request ra=0x7e test_rlcmac_prim_down_cb(): Rx L1CTL-CFG_UL_TBF.request ul_tbf_nr=0 ul_slotmask=0x80 test_rlcmac_prim_down_cb(): Rx L1CTL-PDCH_DATA.request fn=4 ts=7 data_len=34 data=[3c 00 01 00 00 23 42 01 c0 00 08 01 01 d5 71 00 00 08 29 26 24 00 00 00 00 71 62 f2 24 6c 84 44 04 00 ] test_rlcmac_prim_down_cb(): Rx L1CTL-PDCH_DATA.request fn=8 ts=7 data_len=34 data=[00 00 02 1d 00 00 23 42 11 e5 10 00 e2 18 f2 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 ] +test_rlcmac_prim_down_cb(): Rx L1CTL-PDCH_DATA.request fn=21 ts=7 data_len=23 data=[40 04 00 00 8d 08 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b ] === test_ul_tbf_attach end === === test_ul_tbf_t3164_timeout start === sys={0.000000}, mono={0.000000}: clock_override_set