From 3dedfa3d1fbb5620cb4c9255b5bed8f4dcd6352b Mon Sep 17 00:00:00 2001 From: goldsimon Date: Fri, 28 Jul 2017 09:46:56 +0200 Subject: [PATCH] ip4_reass: fixed bug #51597 (Last fragment is assumed to have arrived even if it was discarded) --- src/core/ipv4/ip4_frag.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/core/ipv4/ip4_frag.c b/src/core/ipv4/ip4_frag.c index e8fa5518..8ae67b04 100644 --- a/src/core/ipv4/ip4_frag.c +++ b/src/core/ipv4/ip4_frag.c @@ -337,10 +337,11 @@ ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) * fragment was received at least once). * @param ipr points to the reassembly state * @param new_p points to the pbuf for the current fragment + * @param is_last is 1 if this pbuf has MF==0 (ipr->flags not updated yet) * @return see IP_REASS_VALIDATE_* defines */ static int -ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p) +ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p, int is_last) { struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; struct pbuf *q; @@ -441,7 +442,7 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct /* At this point, the validation part begins: */ /* If we already received the last fragment */ - if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) { + if (is_last || ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0)) { /* and had no holes so far */ if (valid) { /* then check if the rest of the fragments is here */ @@ -469,8 +470,6 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct ((struct ip_reass_helper*)ipr->p->payload) != iprh); LWIP_ASSERT("validate_datagram:next_pbuf!=NULL", iprh->next_pbuf == NULL); - LWIP_ASSERT("validate_datagram:datagram end!=datagram len", - iprh->end == ipr->datagram_len); } } } @@ -507,6 +506,7 @@ ip4_reass(struct pbuf *p) u16_t offset, len, clen; u8_t hlen; int valid; + int is_last; IPFRAG_STATS_INC(ip_frag.recv); MIB2_STATS_INC(mib2.ipreasmreqds); @@ -582,21 +582,17 @@ ip4_reass(struct pbuf *p) * to an existing one */ /* check for 'no more fragments', and update queue entry*/ - if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) { + is_last = (IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0; + if (is_last) { u16_t datagram_len = (u16_t)(offset + len); if ((datagram_len < offset) || (datagram_len > (0xFFFF - IP_HLEN))) { /* u16_t overflow, cannot handle this */ goto nullreturn; } - ipr->datagram_len = datagram_len; - ipr->flags |= IP_REASS_FLAG_LASTFRAG; - LWIP_DEBUGF(IP_REASS_DEBUG, - ("ip4_reass: last fragment seen, total len %"S16_F"\n", - ipr->datagram_len)); } /* find the right place to insert this pbuf */ /* @todo: trim pbufs if fragments are overlapping */ - valid = ip_reass_chain_frag_into_datagram_and_validate(ipr, p); + valid = ip_reass_chain_frag_into_datagram_and_validate(ipr, p, is_last); if (valid == IP_REASS_VALIDATE_PBUF_DROPPED) { goto nullreturn; } @@ -606,6 +602,14 @@ ip4_reass(struct pbuf *p) the number of fragments that may be enqueued at any one time (overflow checked by testing against IP_REASS_MAX_PBUFS) */ ip_reass_pbufcount = (u16_t)(ip_reass_pbufcount + clen); + if (is_last) { + u16_t datagram_len = (u16_t)(offset + len); + ipr->datagram_len = datagram_len; + ipr->flags |= IP_REASS_FLAG_LASTFRAG; + LWIP_DEBUGF(IP_REASS_DEBUG, + ("ip4_reass: last fragment seen, total len %"S16_F"\n", + ipr->datagram_len)); + } if (valid == IP_REASS_VALIDATE_TELEGRAM_FINISHED) { struct ip_reassdata *ipr_prev;