fix RLC AM issue where an invalid status PDU was generated

happens when very small grant is provided and the status
PDU generation fails because of a too small grant

add extra check to prevent that ACK_SN is also in NACKS list
This commit is contained in:
Andre Puschmann 2019-09-30 21:03:32 +02:00
parent a166b3c2d9
commit f07a9277a0
4 changed files with 28 additions and 3 deletions

View File

@ -306,6 +306,7 @@ int rlc_am_write_status_pdu(rlc_status_pdu_t *status, uint8_t *payload);
uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t *header); uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t *header);
uint32_t rlc_am_packed_length(rlc_status_pdu_t *status); uint32_t rlc_am_packed_length(rlc_status_pdu_t *status);
uint32_t rlc_am_packed_length(rlc_amd_retx_t retx); uint32_t rlc_am_packed_length(rlc_amd_retx_t retx);
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status);
bool rlc_am_is_control_pdu(byte_buffer_t *pdu); bool rlc_am_is_control_pdu(byte_buffer_t *pdu);
bool rlc_am_is_control_pdu(uint8_t *payload); bool rlc_am_is_control_pdu(uint8_t *payload);
bool rlc_am_is_pdu_segment(uint8_t *payload); bool rlc_am_is_pdu_segment(uint8_t *payload);
@ -318,5 +319,4 @@ bool rlc_am_not_start_aligned(const uint8_t fi);
} // namespace srslte } // namespace srslte
#endif // SRSLTE_RLC_AM_H #endif // SRSLTE_RLC_AM_H

View File

@ -154,7 +154,7 @@ struct rlc_status_nack_t{
// STATUS PDU // STATUS PDU
struct rlc_status_pdu_t{ struct rlc_status_pdu_t{
uint16_t ack_sn; uint16_t ack_sn; // SN of the next not received RLC Data PDU
uint32_t N_nack; uint32_t N_nack;
rlc_status_nack_t nacks[RLC_AM_WINDOW_SIZE]; rlc_status_nack_t nacks[RLC_AM_WINDOW_SIZE];

View File

@ -1629,6 +1629,14 @@ int rlc_am::rlc_am_rx::get_status_pdu(rlc_status_pdu_t* status, const uint32_t m
if (status->N_nack >= 1) { if (status->N_nack >= 1) {
log->debug("Removing last NACK SN=%d\n", status->nacks[status->N_nack].nack_sn); log->debug("Removing last NACK SN=%d\n", status->nacks[status->N_nack].nack_sn);
status->N_nack--; status->N_nack--;
// make sure we don't have the current ACK_SN in the NACK list
if (rlc_am_is_valid_status_pdu(*status) == false) {
// No space to send any NACKs
log->debug("Resetting N_nack to zero\n");
status->N_nack = 0;
}
} else {
log->error("Failed to generate small enough status PDU\n");
} }
break; break;
} }
@ -2024,6 +2032,16 @@ int rlc_am_write_status_pdu(rlc_status_pdu_t *status, uint8_t *payload)
return tmp.N_bits/8; return tmp.N_bits/8;
} }
bool rlc_am_is_valid_status_pdu(const rlc_status_pdu_t& status)
{
for (uint16_t i = 0; i < status.N_nack; ++i) {
if (status.nacks[i].nack_sn == status.ack_sn) {
return false;
}
}
return true;
}
uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t *header) uint32_t rlc_am_packed_length(rlc_amd_pdu_header_t *header)
{ {
uint32_t len = 2; // Fixed part is 2 bytes uint32_t len = 2; // Fixed part is 2 bytes

View File

@ -1586,11 +1586,18 @@ bool status_pdu_test()
// Read status PDU from RLC2 // Read status PDU from RLC2
byte_buffer_t status_buf; byte_buffer_t status_buf;
len = rlc2.read_pdu(status_buf.msg, 3); // provide only small grant len = rlc2.read_pdu(status_buf.msg, 5); // provide only small grant
status_buf.N_bytes = len; status_buf.N_bytes = len;
assert(status_buf.N_bytes != 0); assert(status_buf.N_bytes != 0);
// check status PDU doesn't contain ACK_SN in NACK list
rlc_status_pdu_t status_pdu = {};
rlc_am_read_status_pdu(status_buf.msg, status_buf.N_bytes, &status_pdu);
if (rlc_am_is_valid_status_pdu(status_pdu) == false) {
return -1;
}
// Write status PDU to RLC1 // Write status PDU to RLC1
rlc1.write_pdu(status_buf.msg, status_buf.N_bytes); rlc1.write_pdu(status_buf.msg, status_buf.N_bytes);