From 8c2734fa436c0e1a85be7a1b5a0c5131df99b190 Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Wed, 15 Feb 2023 12:15:11 +0100 Subject: [PATCH] rlcmac: Implement Rx of UL ACK/NACK Related: OS#5500 Change-Id: I5e3d8e77042d3ad1618e6b62bc1a377a93239580 --- include/osmocom/gprs/rlcmac/rlc_window.h | 6 ++ include/osmocom/gprs/rlcmac/rlcmac_dec.h | 8 ++ include/osmocom/gprs/rlcmac/rlcmac_private.h | 1 + include/osmocom/gprs/rlcmac/tbf_ul.h | 2 + include/osmocom/gprs/rlcmac/tbf_ul_fsm.h | 2 +- include/osmocom/gprs/rlcmac/types_private.h | 8 ++ src/rlcmac/rlc_window.c | 8 +- src/rlcmac/rlcmac.c | 70 ++++++++++++++++- src/rlcmac/rlcmac_dec.c | 81 ++++++++++++++++++++ src/rlcmac/tbf_ul.c | 69 +++++++++++++++++ src/rlcmac/tbf_ul_fsm.c | 6 +- tests/rlcmac/rlcmac_prim_test.c | 72 +++++++++++++++++ tests/rlcmac/rlcmac_prim_test.err | 9 +++ 13 files changed, 331 insertions(+), 11 deletions(-) diff --git a/include/osmocom/gprs/rlcmac/rlc_window.h b/include/osmocom/gprs/rlcmac/rlc_window.h index a5d89ab..09a2739 100644 --- a/include/osmocom/gprs/rlcmac/rlc_window.h +++ b/include/osmocom/gprs/rlcmac/rlc_window.h @@ -3,6 +3,12 @@ #include +#define GPRS_RLCMAC_GPRS_WS 64 /* max window size */ +#define GPRS_RLCMAC_EGPRS_MIN_WS 64 /* min window size */ +#define GPRS_RLCMAC_EGPRS_MAX_WS 1024 /* min window size */ +#define GPRS_RLCMAC_EGPRS_MAX_BSN_DELTA 512 +#define GPRS_RLCMAC_MAX_WS RLC_EGPRS_MAX_WS + struct gprs_rlcmac_rlc_window { uint16_t sns; uint16_t ws; diff --git a/include/osmocom/gprs/rlcmac/rlcmac_dec.h b/include/osmocom/gprs/rlcmac/rlcmac_dec.h index c973917..ea92a0f 100644 --- a/include/osmocom/gprs/rlcmac/rlcmac_dec.h +++ b/include/osmocom/gprs/rlcmac/rlcmac_dec.h @@ -4,10 +4,13 @@ #include #include +#include +#include #include #include +struct gprs_rlcmac_rlc_ul_window; /**************** * DATA BLOCKS: @@ -38,3 +41,8 @@ unsigned int gprs_rlcmac_rlc_copy_to_aligned_buffer(const struct gprs_rlcmac_rlc /**************** * CONTROL BLOCKS: ****************/ + +void gprs_rlcmac_extract_rbb(const struct bitvec *rbb, char *show_rbb); +int gprs_rlcmac_decode_gprs_acknack_bits(const Ack_Nack_Description_t *desc, + struct bitvec *bits, int *bsn_begin, int *bsn_end, + struct gprs_rlcmac_rlc_ul_window *ulw); diff --git a/include/osmocom/gprs/rlcmac/rlcmac_private.h b/include/osmocom/gprs/rlcmac/rlcmac_private.h index f5bbfb0..80461da 100644 --- a/include/osmocom/gprs/rlcmac/rlcmac_private.h +++ b/include/osmocom/gprs/rlcmac/rlcmac_private.h @@ -80,6 +80,7 @@ extern struct gprs_rlcmac_ctx *g_ctx; /* rlcmac.c */ struct gprs_rlcmac_entity *gprs_rlcmac_find_entity_by_tlli(uint32_t tlli); struct gprs_rlcmac_dl_tbf *gprs_rlcmac_find_dl_tbf_by_tfi(uint8_t dl_tfi); +struct gprs_rlcmac_ul_tbf *gprs_rlcmac_find_ul_tbf_by_tfi(uint8_t ul_tfi); int gprs_rlcmac_handle_ccch_imm_ass(const struct gsm48_imm_ass *ia); int gprs_rlcmac_handle_gprs_dl_block(const struct osmo_gprs_rlcmac_prim *rlcmac_prim, enum gprs_rlcmac_coding_scheme cs); diff --git a/include/osmocom/gprs/rlcmac/tbf_ul.h b/include/osmocom/gprs/rlcmac/tbf_ul.h index efe03b4..f9c5a7f 100644 --- a/include/osmocom/gprs/rlcmac/tbf_ul.h +++ b/include/osmocom/gprs/rlcmac/tbf_ul.h @@ -49,6 +49,8 @@ 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); +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); static inline struct gprs_rlcmac_tbf *ul_tbf_as_tbf(struct gprs_rlcmac_ul_tbf *ul_tbf) { diff --git a/include/osmocom/gprs/rlcmac/tbf_ul_fsm.h b/include/osmocom/gprs/rlcmac/tbf_ul_fsm.h index dc50a66..1d7ff88 100644 --- a/include/osmocom/gprs/rlcmac/tbf_ul_fsm.h +++ b/include/osmocom/gprs/rlcmac/tbf_ul_fsm.h @@ -26,7 +26,7 @@ enum tbf_ul_fsm_event { GPRS_RLCMAC_TBF_UL_EV_UL_ASS_START, GPRS_RLCMAC_TBF_UL_EV_UL_ASS_COMPL, GPRS_RLCMAC_TBF_UL_EV_LAST_UL_DATA_SENT, - GPRS_RLCMAC_TBF_UL_EV_FOOBAR, + GPRS_RLCMAC_TBF_UL_EV_FINAL_ACK_RECVD, }; int gprs_rlcmac_tbf_ul_fsm_init(void); diff --git a/include/osmocom/gprs/rlcmac/types_private.h b/include/osmocom/gprs/rlcmac/types_private.h index 77a0504..8f985ba 100644 --- a/include/osmocom/gprs/rlcmac/types_private.h +++ b/include/osmocom/gprs/rlcmac/types_private.h @@ -46,3 +46,11 @@ enum gprs_rlcmac_llc_pdu_type { GPRS_RLCMAC_LLC_PDU_TYPE_ACKNOWLEDGED = 0, GPRS_RLCMAC_LLC_PDU_TYPE_UNACKNOWLEDGED = 1, }; + +/* TS 44.060 12.20 "PAGE_MODE" */ +enum gprs_rlcmac_page_mode { + GPRS_RLCMAC_PAGE_MODE_NORMAL = 0, + GPRS_RLCMAC_PAGE_MODE_EXTENDED = 1, + GPRS_RLCMAC_PAGE_MODE_REORGANIZATION = 2, + GPRS_RLCMAC_PAGE_MODE_SAME_BEFORE = 3, +}; diff --git a/src/rlcmac/rlc_window.c b/src/rlcmac/rlc_window.c index d17307b..2a37e97 100644 --- a/src/rlcmac/rlc_window.c +++ b/src/rlcmac/rlc_window.c @@ -22,16 +22,10 @@ #include #include -#define RLC_GPRS_WS 64 /* max window size */ -#define RLC_EGPRS_MIN_WS 64 /* min window size */ -#define RLC_EGPRS_MAX_WS 1024 /* min window size */ -#define RLC_EGPRS_MAX_BSN_DELTA 512 -#define RLC_MAX_WS RLC_EGPRS_MAX_WS - void gprs_rlcmac_rlc_window_constructor(struct gprs_rlcmac_rlc_window *w) { w->sns = RLC_GPRS_SNS; - w->ws = RLC_GPRS_WS; + w->ws = GPRS_RLCMAC_GPRS_WS; } void gprs_rlcmac_rlc_window_destructor(struct gprs_rlcmac_rlc_window *w) diff --git a/src/rlcmac/rlcmac.c b/src/rlcmac/rlcmac.c index 1e28bac..c6c23e6 100644 --- a/src/rlcmac/rlcmac.c +++ b/src/rlcmac/rlcmac.c @@ -36,6 +36,7 @@ #include #include #include +#include #define GPRS_CODEL_SLOW_INTERVAL_MS 4000 @@ -144,6 +145,20 @@ struct gprs_rlcmac_dl_tbf *gprs_rlcmac_find_dl_tbf_by_tfi(uint8_t dl_tfi) return NULL; } +struct gprs_rlcmac_ul_tbf *gprs_rlcmac_find_ul_tbf_by_tfi(uint8_t ul_tfi) +{ + struct gprs_rlcmac_entity *gre; + + llist_for_each_entry(gre, &g_ctx->gre_list, entry) { + if (!gre->ul_tbf) + continue; + if (gre->ul_tbf->cur_alloc.ul_tfi != ul_tfi) + continue; + return gre->ul_tbf; + } + return NULL; +} + static int gprs_rlcmac_handle_ccch_imm_ass_ul_tbf(uint8_t ts_nr, const struct gsm48_imm_ass *ia, const IA_RestOctets_t *iaro) { int rc = -ENOENT; @@ -281,6 +296,45 @@ int gprs_rlcmac_handle_ccch_imm_ass(const struct gsm48_imm_ass *ia) return rc; } +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); + if (!ul_tbf) { + LOGRLCMAC(LOGL_INFO, "TS=%u FN=%u Rx Pkt UL ACK/NACK: UL_TBF TFI=%u not found\n", + rlcmac_prim->l1ctl.pdch_data_ind.ts_nr, + rlcmac_prim->l1ctl.pdch_data_ind.fn, + dl_block->TFI); + return -ENOENT; + } + + 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_handle_pkt_ul_ack_nack(ul_tbf, ack_desc->FINAL_ACK_INDICATION, bsn_begin, &bits); + return rc; +} + static int gprs_rlcmac_handle_gprs_dl_ctrl_block(const struct osmo_gprs_rlcmac_prim *rlcmac_prim) { struct bitvec *bv; @@ -302,7 +356,21 @@ static int gprs_rlcmac_handle_gprs_dl_ctrl_block(const struct osmo_gprs_rlcmac_p goto free_ret; } - LOGRLCMAC(LOGL_NOTICE, "TODO: handle decoded dl ctrl block!\n"); + LOGRLCMAC(LOGL_INFO, "TS=%u FN=%u Rx %s\n", + rlcmac_prim->l1ctl.pdch_data_ind.ts_nr, + rlcmac_prim->l1ctl.pdch_data_ind.fn, + get_value_string(osmo_gprs_rlcmac_dl_msg_type_names, dl_ctrl_block->u.MESSAGE_TYPE)); + + switch (dl_ctrl_block->u.MESSAGE_TYPE) { + case OSMO_GPRS_RLCMAC_DL_MSGT_PACKET_UPLINK_ACK_NACK: + rc = gprs_rlcmac_handle_pkt_ul_ack_nack(rlcmac_prim, dl_ctrl_block); + break; + default: + LOGRLCMAC(LOGL_ERROR, "TS=%u FN=%u Rx %s NOT SUPPORTED! ignoring\n", + rlcmac_prim->l1ctl.pdch_data_ind.ts_nr, + rlcmac_prim->l1ctl.pdch_data_ind.fn, + get_value_string(osmo_gprs_rlcmac_dl_msg_type_names, dl_ctrl_block->u.MESSAGE_TYPE)); + } free_ret: talloc_free(dl_ctrl_block); diff --git a/src/rlcmac/rlcmac_dec.c b/src/rlcmac/rlcmac_dec.c index cd44fc8..fa88c26 100644 --- a/src/rlcmac/rlcmac_dec.c +++ b/src/rlcmac/rlcmac_dec.c @@ -26,6 +26,7 @@ #include #include #include +#include #define LENGTH_TO_END 255 /*! @@ -341,3 +342,83 @@ unsigned int gprs_rlcmac_rlc_copy_to_aligned_buffer( return rdbi->data_len; } + +/** + * show_rbb needs to be an array with 65 elements + * The index of the array is the bit position in the rbb + * (show_rbb[63] relates to BSN ssn-1) + */ +void gprs_rlcmac_extract_rbb(const struct bitvec *rbb, char *show_rbb) +{ + unsigned int i; + for (i = 0; i < rbb->cur_bit; i++) { + uint8_t bit; + bit = bitvec_get_bit_pos(rbb, i); + show_rbb[i] = bit == 1 ? 'R' : 'I'; + } + + show_rbb[i] = '\0'; +} + +static int handle_final_ack(struct bitvec *bits, int *bsn_begin, int *bsn_end, + struct gprs_rlcmac_rlc_ul_window *ulw) +{ + int num_blocks, i; + uint16_t v_a = gprs_rlcmac_rlc_ul_window_v_a(ulw); + + num_blocks = gprs_rlcmac_rlc_window_mod_sns_bsn(rlc_ulw_as_w(ulw), + gprs_rlcmac_rlc_ul_window_v_s(ulw) - v_a); + for (i = 0; i < num_blocks; i++) + bitvec_set_bit(bits, ONE); + + *bsn_begin = v_a; + *bsn_end = gprs_rlcmac_rlc_window_mod_sns_bsn(rlc_ulw_as_w(ulw), *bsn_begin + num_blocks); + return num_blocks; +} + +int gprs_rlcmac_decode_gprs_acknack_bits(const Ack_Nack_Description_t *desc, + struct bitvec *bits, int *bsn_begin, int *bsn_end, + struct gprs_rlcmac_rlc_ul_window *ulw) +{ + int urbb_len = GPRS_RLCMAC_GPRS_WS; + int num_blocks; + struct bitvec urbb; + + if (desc->FINAL_ACK_INDICATION) + return handle_final_ack(bits, bsn_begin, bsn_end, ulw); + + *bsn_begin = gprs_rlcmac_rlc_ul_window_v_a(ulw); + *bsn_end = desc->STARTING_SEQUENCE_NUMBER; + + num_blocks = gprs_rlcmac_rlc_window_mod_sns_bsn(rlc_ulw_as_w(ulw), *bsn_end - *bsn_begin); + + if (num_blocks < 0 || num_blocks > urbb_len) { + *bsn_end = *bsn_begin; + LOGRLCMAC(LOGL_NOTICE, "Invalid GPRS Ack/Nack window %d:%d (length %d)\n", + *bsn_begin, *bsn_end, num_blocks); + return -EINVAL; + } + + urbb.cur_bit = 0; + urbb.data = (uint8_t *)desc->RECEIVED_BLOCK_BITMAP; + urbb.data_len = sizeof(desc->RECEIVED_BLOCK_BITMAP); + + /* + * TS 44.060, 12.3: + * BSN = (SSN - bit_number) modulo 128, for bit_number = 1 to 64. + * The BSN values represented range from (SSN - 1) mod 128 to (SSN - 64) mod 128. + * + * We are only interested in the range from V(A) to SSN-1 which is + * num_blocks large. The RBB is laid out as + * [SSN-1] [SSN-2] ... [V(A)] ... [SSN-64] + * so we want to start with [V(A)] and go backwards until we reach + * [SSN-1] to get the needed BSNs in an increasing order. Note that + * the bit numbers are counted from the end of the buffer. + */ + for (int i = num_blocks; i > 0; i--) { + int is_ack = bitvec_get_bit_pos(&urbb, urbb_len - i); + bitvec_set_bit(bits, is_ack == 1 ? ONE : ZERO); + } + + return num_blocks; +} diff --git a/src/rlcmac/tbf_ul.c b/src/rlcmac/tbf_ul.c index 906efbe..ae6b156 100644 --- a/src/rlcmac/tbf_ul.c +++ b/src/rlcmac/tbf_ul.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -110,6 +111,74 @@ bool gprs_rlcmac_ul_tbf_data_rts(const struct gprs_rlcmac_ul_tbf *ul_tbf, const return (st == GPRS_RLCMAC_TBF_UL_ST_FLOW); } +static int gprs_rlcmac_ul_tbf_update_window(struct gprs_rlcmac_ul_tbf *ul_tbf, + unsigned first_bsn, struct bitvec *rbb) +{ + unsigned dist; + uint16_t lost = 0, received = 0; + char show_v_b[RLC_MAX_SNS + 1]; + char show_rbb[RLC_MAX_SNS + 1]; + dist = gprs_rlcmac_rlc_ul_window_distance(ul_tbf->ulw); + unsigned num_blocks = rbb->cur_bit > dist + ? dist : rbb->cur_bit; + unsigned behind_last_bsn = gprs_rlcmac_rlc_window_mod_sns_bsn(ul_tbf->w, first_bsn + num_blocks); + + gprs_rlcmac_extract_rbb(rbb, show_rbb); + /* show received array in debug */ + LOGPTBFUL(ul_tbf, LOGL_DEBUG, + "ack: (BSN=%d)\"%s\"(BSN=%d) R=ACK I=NACK\n", + first_bsn, show_rbb, + gprs_rlcmac_rlc_window_mod_sns_bsn(ul_tbf->w, behind_last_bsn - 1)); + + gprs_rlcmac_rlc_ul_window_update(ul_tbf->ulw, rbb, first_bsn, &lost, &received); + + /* raise V(A), if possible */ + gprs_rlcmac_rlc_ul_window_raise(ul_tbf->ulw, + gprs_rlcmac_rlc_ul_window_move_window(ul_tbf->ulw)); + + /* show receive state array in debug (V(A)..V(S)-1) */ + gprs_rlcmac_rlc_ul_window_show_state(ul_tbf->ulw, show_v_b); + LOGPTBFUL(ul_tbf, LOGL_DEBUG, + "V(B): (V(A)=%d)\"%s\"(V(S)-1=%d) A=Acked N=Nacked U=Unacked X=Resend-Unacked I=Invalid\n", + gprs_rlcmac_rlc_ul_window_v_a(ul_tbf->ulw), show_v_b, + gprs_rlcmac_rlc_ul_window_v_s_mod(ul_tbf->ulw, -1)); + return 0; +} + +int gprs_rlcmac_ul_tbf_handle_final_ack(struct gprs_rlcmac_ul_tbf *ul_tbf) +{ + int rc = 0; + + osmo_fsm_inst_dispatch(ul_tbf->state_fsm.fi, GPRS_RLCMAC_TBF_UL_EV_FINAL_ACK_RECVD, NULL); + + /* range V(A)..V(S)-1 */ + //received = gprs_rlcmac_rlc_ul_window_count_unacked(ul_tbf->ulw); + /* report all outstanding packets as received */ + //gprs_rlcmac_received_lost(this, received, 0); + gprs_rlcmac_rlc_ul_window_reset(ul_tbf->ulw); + + /* TODO: check for RRBP and attempt to create a new UL TBF if + * gprs_rlcmac_ul_tbf_have_data(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 rc; + rc = gprs_rlcmac_ul_tbf_update_window(ul_tbf, first_bsn, rbb); + + if (final_ack) { + 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) && + gprs_rlcmac_rlc_ul_window_window_empty(ul_tbf->ulw)) { + LOGPTBFUL(ul_tbf, LOGL_NOTICE, + "Received acknowledge of all blocks, but without final ack indication (don't worry)\n"); + } + return rc; +} + struct msgb *gprs_rlcmac_ul_tbf_dummy_create(const struct gprs_rlcmac_ul_tbf *ul_tbf) { struct msgb *msg; diff --git a/src/rlcmac/tbf_ul_fsm.c b/src/rlcmac/tbf_ul_fsm.c index 5095605..3cff899 100644 --- a/src/rlcmac/tbf_ul_fsm.c +++ b/src/rlcmac/tbf_ul_fsm.c @@ -33,7 +33,7 @@ static const struct value_string tbf_ul_fsm_event_names[] = { { GPRS_RLCMAC_TBF_UL_EV_UL_ASS_START, "UL_ASS_START" }, { GPRS_RLCMAC_TBF_UL_EV_UL_ASS_COMPL, "UL_ASS_COMPL" }, { GPRS_RLCMAC_TBF_UL_EV_LAST_UL_DATA_SENT, "LAST_UL_DATA_SENT" }, - { GPRS_RLCMAC_TBF_UL_EV_FOOBAR, "FOOBAR" }, + { GPRS_RLCMAC_TBF_UL_EV_FINAL_ACK_RECVD, "FINAL_ACK_RECVD" }, { 0, NULL } }; @@ -118,6 +118,8 @@ static void st_finished(struct osmo_fsm_inst *fi, uint32_t event, void *data) { //struct gprs_rlcmac_tbf_ul_fsm_ctx *ctx = (struct gprs_rlcmac_tbf_ul_fsm_ctx *)fi->priv; switch (event) { + case GPRS_RLCMAC_TBF_UL_EV_FINAL_ACK_RECVD: + break; default: OSMO_ASSERT(0); } @@ -151,7 +153,7 @@ static struct osmo_fsm_state tbf_ul_fsm_states[] = { }, [GPRS_RLCMAC_TBF_UL_ST_FINISHED] = { .in_event_mask = - X(GPRS_RLCMAC_TBF_UL_EV_FOOBAR), + X(GPRS_RLCMAC_TBF_UL_EV_FINAL_ACK_RECVD), .out_state_mask = X(GPRS_RLCMAC_TBF_UL_ST_WAIT_ASSIGN), .name = "FINISHED", diff --git a/tests/rlcmac/rlcmac_prim_test.c b/tests/rlcmac/rlcmac_prim_test.c index 2711889..658ddb3 100644 --- a/tests/rlcmac/rlcmac_prim_test.c +++ b/tests/rlcmac/rlcmac_prim_test.c @@ -23,8 +23,10 @@ #include #include +#include #include #include +#include #include #include @@ -192,6 +194,64 @@ static inline unsigned fn_next_block(unsigned fn) return fn % GSM_MAX_FN; } +static struct osmo_gprs_rlcmac_prim *create_dl_ctrl_block_buf(uint8_t *buf, int num_bytes, uint8_t tn, uint32_t fn) +{ + struct osmo_gprs_rlcmac_prim *rlcmac_prim; + + + rlcmac_prim = osmo_gprs_rlcmac_prim_alloc_l1ctl_pdch_data_ind(tn, fn, 0, 0, 0, + NULL, num_bytes); + rlcmac_prim->l1ctl.pdch_data_ind.data = msgb_put(rlcmac_prim->oph.msg, num_bytes); + memcpy(rlcmac_prim->l1ctl.pdch_data_ind.data, buf, num_bytes); + return rlcmac_prim; +} + +static struct osmo_gprs_rlcmac_prim *create_dl_ctrl_block(RlcMacDownlink_t *dl_block, uint8_t tn, uint32_t fn) +{ + struct bitvec *rlc_block; + uint8_t buf[64]; + int num_bytes; + + rlc_block = bitvec_alloc(23, tall_ctx); + + OSMO_ASSERT(osmo_gprs_rlcmac_encode_downlink(rlc_block, dl_block) == 0); + num_bytes = bitvec_pack(rlc_block, &buf[0]); + OSMO_ASSERT((size_t)num_bytes < sizeof(buf)); + bitvec_free(rlc_block); + + return create_dl_ctrl_block_buf(&buf[0], num_bytes, tn, fn); +} + +static void ul_ack_nack_init(RlcMacDownlink_t *dl_block, uint8_t ul_tfi, enum gprs_rlcmac_coding_scheme cs) +{ + Packet_Uplink_Ack_Nack_t *ack = &dl_block->u.Packet_Uplink_Ack_Nack; + PU_AckNack_GPRS_t *gprs = &ack->u.PU_AckNack_GPRS_Struct; + + memset(dl_block, 0, sizeof(*dl_block)); + dl_block->PAYLOAD_TYPE = GPRS_RLCMAC_PT_CONTROL_BLOCK; + dl_block->RRBP = 0; + dl_block->SP = 0; + dl_block->USF = 0x00; + dl_block->u.MESSAGE_TYPE = OSMO_GPRS_RLCMAC_DL_MSGT_PACKET_UPLINK_ACK_NACK; + + ack->MESSAGE_TYPE = OSMO_GPRS_RLCMAC_DL_MSGT_PACKET_UPLINK_ACK_NACK; + ack->PAGE_MODE = GPRS_RLCMAC_PAGE_MODE_NORMAL; + ack->UPLINK_TFI = ul_tfi; + ack->UnionType = 0; /* GPRS */ + + gprs->CHANNEL_CODING_COMMAND = cs; +} + +static void ul_ack_nack_mark(Ack_Nack_Description_t *ack_desc, unsigned int idx, bool received) +{ + //ack_desc->RECEIVED_BLOCK_BITMAP[sizeof(ack_desc->RECEIVED_BLOCK_BITMAP) - 1] = 0xff; + //memset(ack_desc->RECEIVED_BLOCK_BITMAP, 0xff, sizeof(ack_desc->RECEIVED_BLOCK_BITMAP)); + if (received) + ack_desc->RECEIVED_BLOCK_BITMAP[sizeof(ack_desc->RECEIVED_BLOCK_BITMAP) - idx/8 - 1] |= (1 << (idx & 0x03)); + else + ack_desc->RECEIVED_BLOCK_BITMAP[sizeof(ack_desc->RECEIVED_BLOCK_BITMAP) - idx/8 - 1] &= ~(1 << (idx & 0x03)); +} + static int test_rlcmac_prim_up_cb(struct osmo_gprs_rlcmac_prim *rlcmac_prim, void *user_data) { const char *pdu_name = osmo_gprs_rlcmac_prim_name(rlcmac_prim); @@ -306,7 +366,10 @@ static void test_ul_tbf_attach(void) printf("=== %s start ===\n", __func__); prepare_test(); + RlcMacDownlink_t dl_block; + Ack_Nack_Description_t *ack_desc = &dl_block.u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Ack_Nack_Description; uint32_t tlli = 0x2342; + uint8_t ul_tfi = 0; uint8_t ts_nr = 7; uint8_t usf = 0; uint32_t rts_fn = 4; @@ -330,7 +393,16 @@ static void test_ul_tbf_attach(void) rts_fn = fn_next_block(rts_fn); 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); + /* PCU acks it: */ + ul_ack_nack_init(&dl_block, ul_tfi, GPRS_RLCMAC_CS_2); + ack_desc->STARTING_SEQUENCE_NUMBER = 1; + ack_desc->FINAL_ACK_INDICATION = 1; + ul_ack_nack_mark(ack_desc, 0, true); + ul_ack_nack_mark(ack_desc, 1, true); + 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); printf("=== %s end ===\n", __func__); diff --git a/tests/rlcmac/rlcmac_prim_test.err b/tests/rlcmac/rlcmac_prim_test.err index 2e82b2e..8f7283d 100644 --- a/tests/rlcmac/rlcmac_prim_test.err +++ b/tests/rlcmac/rlcmac_prim_test.err @@ -37,6 +37,15 @@ DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00002342) need_padding 0 spb_status 0 spb 0 (BSN DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00002342) Copying 1 RLC blocks, 1 BSNs DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00002342) Copying data unit 0 (BSN 1) DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00002342) msg block (BSN 1, CS-2): 00 00 02 0d e2 18 f2 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 00 +DLGLOBAL INFO Rx from lower layers: L1CTL-PDCH_DATA.indication +DLGLOBAL INFO TS=7 FN=8 Rx Pkt UL ACK/NACK +DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00002342) Got GPRS UL ACK bitmap: SSN: 1, BSN 0 to 2 - 1 (2 blocks), "RR" +DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00002342) ack: (BSN=0)"RR"(BSN=1) R=ACK I=NACK +DLGLOBAL DEBUG - got ack for BSN=0 +DLGLOBAL DEBUG - got ack for BSN=1 +DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00002342) V(B): (V(A)=2)""(V(S)-1=1) A=Acked N=Nacked U=Unacked X=Resend-Unacked I=Invalid +DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00002342) Final ACK received. +DLGLOBAL INFO UL_TBF{FINISHED}: Received Event FINAL_ACK_RECVD DLGLOBAL INFO UL_TBF_ASS{IDLE}: Deallocated DLGLOBAL INFO UL_TBF{FINISHED}: Deallocated DLGLOBAL INFO Rx from upper layers: GMMRR-ASSIGN.request