SRSLTE: fix RLC reordering and segment overlaping

master
Xavier Arteaga 5 years ago committed by Xavier Arteaga
parent d3537fc340
commit 39bec9aab1

@ -1685,24 +1685,30 @@ void rlc_am_lte::rlc_am_lte_rx::print_rx_segments()
// NOTE: Preference would be to capture by value, and then move; but header is stack allocated // NOTE: Preference would be to capture by value, and then move; but header is stack allocated
bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu_t* segment) bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu_t* segment)
{ {
// Check for first segment // Find segment insertion point in the list of segments
if (0 == segment->header.so) { auto it1 = pdu->segments.begin();
pdu->segments.clear(); while (it1 != pdu->segments.end() && (*it1).header.so < segment->header.so) {
pdu->segments.push_back(std::move(*segment)); // Increment iterator
return false; it1++;
} }
// Check segment offset // Check if the insertion point was found
uint32_t n = 0; if (it1 != pdu->segments.end()) {
if (!pdu->segments.empty()) { // Found insertion point
rlc_amd_rx_pdu_t& back = pdu->segments.back(); rlc_amd_rx_pdu_t& s = *it1;
n = back.header.so + back.buf->N_bytes; if (s.header.so == segment->header.so) {
} // Same Segment offset
if (segment->buf->N_bytes > s.buf->N_bytes) {
if (segment->header.so != n) { // replace if the new one is bigger
log->warning("Received PDU with SO=%d, expected %d. Discarding PDU.\n", segment->header.so, n); s = std::move(*segment);
return false; } else {
// Ignore otherwise
}
} else if (s.header.so > segment->header.so) {
pdu->segments.insert(it1, std::move(*segment));
}
} else { } else {
// Either the new segment is the latest or the only one, push back
pdu->segments.push_back(std::move(*segment)); pdu->segments.push_back(std::move(*segment));
} }
@ -1710,11 +1716,16 @@ bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t*
uint32_t so = 0; uint32_t so = 0;
std::list<rlc_amd_rx_pdu_t>::iterator it, tmpit; std::list<rlc_amd_rx_pdu_t>::iterator it, tmpit;
for (it = pdu->segments.begin(); it != pdu->segments.end(); it++) { for (it = pdu->segments.begin(); it != pdu->segments.end(); it++) {
if (so != it->header.so) { // Check that there is no gap between last segment and current; overlap allowed
if (so < it->header.so) {
return false; return false;
} }
so += it->buf->N_bytes;
// Update segment offset it shall not go backwards
so = SRSLTE_MAX(so, it->header.so + it->buf->N_bytes);
} }
// Check for last segment flag available
if (!pdu->segments.back().header.lsf) { if (!pdu->segments.back().header.lsf) {
return false; return false;
} }
@ -1799,8 +1810,26 @@ bool rlc_am_lte::rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t*
#endif #endif
} }
for (it = pdu->segments.begin(); it != pdu->segments.end(); it++) { for (it = pdu->segments.begin(); it != pdu->segments.end(); it++) {
memcpy(&full_pdu->msg[full_pdu->N_bytes], it->buf->msg, it->buf->N_bytes); // By default, the segment is not copied. It could be it is fully overlapped with previous segments
full_pdu->N_bytes += it->buf->N_bytes; uint32_t overlap = 0;
uint32_t n = 0;
// Check if the segment has non-overlapped bytes
if (it->header.so + it->buf->N_bytes > full_pdu->N_bytes) {
// Calculate overlap and number of bytes
overlap = full_pdu->N_bytes - it->header.so;
n = it->buf->N_bytes - overlap;
}
// Check overlapped data is matching
if (memcmp(&full_pdu->msg[it->header.so], it->buf->msg, overlap) != 0) {
log->warning("Overlapped data between segments does not match. Discarding PDU.\n");
return false;
}
// Copy data itself
memcpy(&full_pdu->msg[full_pdu->N_bytes], &it->buf->msg[overlap], n);
full_pdu->N_bytes += n;
} }
handle_data_pdu(full_pdu->msg, full_pdu->N_bytes, header); handle_data_pdu(full_pdu->msg, full_pdu->N_bytes, header);

Loading…
Cancel
Save