nr rlc: bugfix: fix NACK with range
We do some sanity checks for incoming rlc control packets. One of them is to check that so_start is not > so_end when present. But when 'range' is present and bigger than 1 it means that so_start refers to one PDU and so_end to another one. So we may well have so_start > so_end. This commit fixes that and reorganizes a bit the code to do the check before processing and rejecting the PDU if the values are not correct. (Before this commit we were NACKing the whole PDUs if so_start > so_end.)
This commit is contained in:
@@ -650,7 +650,7 @@ control:
|
|||||||
control_decoder = decoder;
|
control_decoder = decoder;
|
||||||
control_e1 = e1;
|
control_e1 = e1;
|
||||||
while (control_e1) {
|
while (control_e1) {
|
||||||
nr_rlc_pdu_decoder_get_bits(&control_decoder, entity->sn_field_length); R(control_decoder); /* NACK_SN */
|
nack_sn = nr_rlc_pdu_decoder_get_bits(&control_decoder, entity->sn_field_length); R(control_decoder);
|
||||||
control_e1 = nr_rlc_pdu_decoder_get_bits(&control_decoder, 1); R(control_decoder);
|
control_e1 = nr_rlc_pdu_decoder_get_bits(&control_decoder, 1); R(control_decoder);
|
||||||
control_e2 = nr_rlc_pdu_decoder_get_bits(&control_decoder, 1); R(control_decoder);
|
control_e2 = nr_rlc_pdu_decoder_get_bits(&control_decoder, 1); R(control_decoder);
|
||||||
control_e3 = nr_rlc_pdu_decoder_get_bits(&control_decoder, 1); R(control_decoder);
|
control_e3 = nr_rlc_pdu_decoder_get_bits(&control_decoder, 1); R(control_decoder);
|
||||||
@@ -660,17 +660,36 @@ control:
|
|||||||
} else {
|
} else {
|
||||||
nr_rlc_pdu_decoder_get_bits(&control_decoder, 1); R(control_decoder);
|
nr_rlc_pdu_decoder_get_bits(&control_decoder, 1); R(control_decoder);
|
||||||
}
|
}
|
||||||
|
/* check range and so_start/so_end consistency */
|
||||||
if (control_e2) {
|
if (control_e2) {
|
||||||
nr_rlc_pdu_decoder_get_bits(&control_decoder, 16); R(control_decoder); /* SOstart */
|
so_start = nr_rlc_pdu_decoder_get_bits(&control_decoder, 16); R(control_decoder);
|
||||||
nr_rlc_pdu_decoder_get_bits(&control_decoder, 16); R(control_decoder); /* SOend */
|
so_end = nr_rlc_pdu_decoder_get_bits(&control_decoder, 16); R(control_decoder);
|
||||||
|
} else {
|
||||||
|
so_start = 0;
|
||||||
|
so_end = 0xffff;
|
||||||
}
|
}
|
||||||
if (control_e3) {
|
if (control_e3) {
|
||||||
nr_rlc_pdu_decoder_get_bits(&control_decoder, 8); R(control_decoder); /* NACK range */
|
range = nr_rlc_pdu_decoder_get_bits(&control_decoder, 8); R(control_decoder);
|
||||||
|
} else {
|
||||||
|
range = 1;
|
||||||
|
}
|
||||||
|
if (range < 1) {
|
||||||
|
LOG_E(RLC, "%s:%d:%s: error, bad 'range' in RLC NACK (sn %d)\n",
|
||||||
|
__FILE__, __LINE__, __FUNCTION__, nack_sn);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
/* so_start can be > so_end if more than one range; they don't refer
|
||||||
|
* to the same PDU then
|
||||||
|
*/
|
||||||
|
if (range == 1 && so_end < so_start) {
|
||||||
|
LOG_E(RLC, "%s:%d:%s: error, bad so start/end (sn %d)\n",
|
||||||
|
__FILE__, __LINE__, __FUNCTION__, nack_sn);
|
||||||
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 38.322 5.3.3.3 says to stop t_poll_retransmit if a ACK or NACK is
|
/* 38.322 5.3.3.3 says to stop t_poll_retransmit if a ACK or NACK is
|
||||||
* received for the SN 'poll_sn'
|
* received for the SN 'poll_sn' - check ACK case (NACK done below)
|
||||||
*/
|
*/
|
||||||
if (sn_compare_tx(entity, entity->poll_sn, ack_sn) < 0)
|
if (sn_compare_tx(entity, entity->poll_sn, ack_sn) < 0)
|
||||||
entity->t_poll_retransmit_start = 0;
|
entity->t_poll_retransmit_start = 0;
|
||||||
@@ -697,28 +716,22 @@ control:
|
|||||||
if (e2) {
|
if (e2) {
|
||||||
so_start = nr_rlc_pdu_decoder_get_bits(&decoder, 16); R(decoder);
|
so_start = nr_rlc_pdu_decoder_get_bits(&decoder, 16); R(decoder);
|
||||||
so_end = nr_rlc_pdu_decoder_get_bits(&decoder, 16); R(decoder);
|
so_end = nr_rlc_pdu_decoder_get_bits(&decoder, 16); R(decoder);
|
||||||
if (so_end < so_start) {
|
|
||||||
LOG_W(RLC, "%s:%d:%s: warning, bad so start/end, NACK the whole PDU (sn %d)\n",
|
|
||||||
__FILE__, __LINE__, __FUNCTION__, nack_sn);
|
|
||||||
so_start = 0;
|
|
||||||
so_end = -1;
|
|
||||||
}
|
|
||||||
/* special value 0xffff indicates 'all bytes to the end' */
|
|
||||||
if (so_end == 0xffff)
|
|
||||||
so_end = -1;
|
|
||||||
} else {
|
} else {
|
||||||
so_start = 0;
|
so_start = 0;
|
||||||
so_end = -1;
|
so_end = 0xffff;
|
||||||
}
|
}
|
||||||
if (e3) {
|
if (e3) {
|
||||||
range = nr_rlc_pdu_decoder_get_bits(&decoder, 8); R(decoder);
|
range = nr_rlc_pdu_decoder_get_bits(&decoder, 8); R(decoder);
|
||||||
} else {
|
} else {
|
||||||
range = 1;
|
range = 1;
|
||||||
}
|
}
|
||||||
|
/* special value 0xffff indicates 'all bytes to the end' */
|
||||||
|
if (so_end == 0xffff)
|
||||||
|
so_end = -1;
|
||||||
process_received_nack(entity, nack_sn, so_start, so_end, range, sn_set);
|
process_received_nack(entity, nack_sn, so_start, so_end, range, sn_set);
|
||||||
|
|
||||||
/* 38.322 5.3.3.3 says to stop t_poll_retransmit if a ACK or NACK is
|
/* 38.322 5.3.3.3 says to stop t_poll_retransmit if a ACK or NACK is
|
||||||
* received for the SN 'poll_sn'
|
* received for the SN 'poll_sn' - check NACK case (ACK done above)
|
||||||
*/
|
*/
|
||||||
if (sn_compare_tx(entity, nack_sn, entity->poll_sn) <= 0 &&
|
if (sn_compare_tx(entity, nack_sn, entity->poll_sn) <= 0 &&
|
||||||
sn_compare_tx(entity, entity->poll_sn, (nack_sn + range) % entity->sn_modulus) < 0)
|
sn_compare_tx(entity, entity->poll_sn, (nack_sn + range) % entity->sn_modulus) < 0)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
test_count=14
|
test_count=15
|
||||||
|
|
||||||
for i in `seq $test_count`
|
for i in `seq $test_count`
|
||||||
do
|
do
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* am test (SN field size 18):
|
||||||
|
* test "range" in NACK, generate a case where so_start > so_end
|
||||||
|
* (so so_start and so_end are not from the same PDU)
|
||||||
|
*/
|
||||||
|
|
||||||
|
TIME, 1,
|
||||||
|
GNB_AM, 100000, 100000, 45, 35, 0, -1, -1, 8, 18,
|
||||||
|
UE_AM, 100000, 100000, 45, 35, 0, -1, -1, 8, 18,
|
||||||
|
GNB_PDU_SIZE, 40,
|
||||||
|
UE_PDU_SIZE, 80,
|
||||||
|
GNB_SDU, 0, 50,
|
||||||
|
GNB_SDU, 1, 50,
|
||||||
|
GNB_SDU, 2, 50,
|
||||||
|
TIME, 2,
|
||||||
|
UE_RECV_FAILS, 1,
|
||||||
|
TIME, 4,
|
||||||
|
UE_RECV_FAILS, 0,
|
||||||
|
TIME, -1
|
||||||
Binary file not shown.
Reference in New Issue
Block a user