rbuf: drop overlapped fragment only if offset or size differs from previous one.

https://tools.ietf.org/html/rfc4944#section-5.3 says:

> If a link fragment that overlaps another fragment is received, as
> identified above, and differs in either the size or datagram_offset
> of the overlapped fragment, the fragment(s) already accumulated in
> the reassembly buffer SHALL be discarded.  A fresh reassembly may be
> commenced with the most recently received link fragment.
This commit is contained in:
Yonezawa-T2 2016-02-09 11:14:44 +09:00
parent 8cf5ffdabc
commit f638d68ebb

View File

@ -44,8 +44,8 @@ static char l2addr_str[3 * RBUF_L2ADDR_MAX_LEN];
/* ------------------------------------ /* ------------------------------------
* internal function definitions * internal function definitions
* ------------------------------------*/ * ------------------------------------*/
/* checks whether start and end are in given interval i */ /* checks whether start and end overlaps, but not identical to, given interval i */
static inline bool _rbuf_int_in(rbuf_int_t *i, uint16_t start, uint16_t end); static inline bool _rbuf_int_overlap_partially(rbuf_int_t *i, uint16_t start, uint16_t end);
/* gets a free entry from interval buffer */ /* gets a free entry from interval buffer */
static rbuf_int_t *_rbuf_int_get_free(void); static rbuf_int_t *_rbuf_int_get_free(void);
/* remove entry from reassembly buffer */ /* remove entry from reassembly buffer */
@ -66,6 +66,7 @@ void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
/* cppcheck is clearly wrong here */ /* cppcheck is clearly wrong here */
/* cppcheck-suppress variableScope */ /* cppcheck-suppress variableScope */
unsigned int data_offset = 0; unsigned int data_offset = 0;
size_t original_size = frag_size;
sixlowpan_frag_t *frag = pkt->data; sixlowpan_frag_t *frag = pkt->data;
rbuf_int_t *ptr; rbuf_int_t *ptr;
uint8_t *data = ((uint8_t *)pkt->data) + sizeof(sixlowpan_frag_t); uint8_t *data = ((uint8_t *)pkt->data) + sizeof(sixlowpan_frag_t);
@ -118,11 +119,20 @@ void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
return; return;
} }
/* If the fragment overlaps another fragment and differs in either the size
* or the offset of the overlapped fragment, discards the datagram
* https://tools.ietf.org/html/rfc4944#section-5.3 */
while (ptr != NULL) { while (ptr != NULL) {
if (_rbuf_int_in(ptr, offset, offset + frag_size - 1)) { if (_rbuf_int_overlap_partially(ptr, offset, offset + frag_size - 1)) {
DEBUG("6lo rfrag: overlapping or same intervals, discarding datagram\n"); DEBUG("6lo rfrag: overlapping intervals, discarding datagram\n");
gnrc_pktbuf_release(entry->pkt); gnrc_pktbuf_release(entry->pkt);
_rbuf_rem(entry); _rbuf_rem(entry);
/* "A fresh reassembly may be commenced with the most recently
* received link fragment"
* https://tools.ietf.org/html/rfc4944#section-5.3 */
rbuf_add(netif_hdr, pkt, original_size, offset);
return; return;
} }
@ -168,11 +178,11 @@ void rbuf_add(gnrc_netif_hdr_t *netif_hdr, gnrc_pktsnip_t *pkt,
} }
} }
static inline bool _rbuf_int_in(rbuf_int_t *i, uint16_t start, uint16_t end) static inline bool _rbuf_int_overlap_partially(rbuf_int_t *i, uint16_t start, uint16_t end)
{ {
return (((i->start < start) && (start <= i->end)) || /* start and ends are both inclusive, so using <= for both */
((start < i->start) && (i->start <= end)) || return ((i->start <= end) && (start <= i->end)) && /* overlaps */
((i->start == start) && (i->end == end))); ((start != i->start) || (end != i->end)); /* not identical */
} }
static rbuf_int_t *_rbuf_int_get_free(void) static rbuf_int_t *_rbuf_int_get_free(void)