mirror of
https://git.savannah.nongnu.org/git/lwip.git
synced 2025-08-03 21:14:40 +08:00
Added check for overlapping or duplicate fragments. ip_reass_init() is not needed any more (the check is done in chain_frag_into_packet_and_validate()).
This commit is contained in:
parent
8cd65eaf46
commit
e561c7b49d
@ -70,13 +70,16 @@ static u16_t ip_reass_pbufcount;
|
|||||||
* The IP reassembly code currently has the following limitations:
|
* The IP reassembly code currently has the following limitations:
|
||||||
* - IP header options are not supported
|
* - IP header options are not supported
|
||||||
* - fragments must not overlap (e.g. due to different routes),
|
* - fragments must not overlap (e.g. due to different routes),
|
||||||
* currently, overlapping fragments will produce undefined results!
|
* currently, overlapping or duplicate fragments are thrown away
|
||||||
|
* if IP_REASS_CHECK_OVERLAP=1 (the default)!
|
||||||
*
|
*
|
||||||
* @todo: throw away overlapping fragments!
|
|
||||||
* @todo: work with IP header options
|
* @todo: work with IP header options
|
||||||
* @todo: check what happens if the same fragment arrives twice or overlapping fragments arrive!
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef IP_REASS_CHECK_OVERLAP
|
||||||
|
#define IP_REASS_CHECK_OVERLAP 1
|
||||||
|
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||||
|
|
||||||
/* function prototypes */
|
/* function prototypes */
|
||||||
static void dequeue_packet(struct ip_reassdata *ipr, struct ip_reassdata *prev);
|
static void dequeue_packet(struct ip_reassdata *ipr, struct ip_reassdata *prev);
|
||||||
|
|
||||||
@ -86,9 +89,6 @@ static void dequeue_packet(struct ip_reassdata *ipr, struct ip_reassdata *prev);
|
|||||||
void
|
void
|
||||||
ip_reass_init(void)
|
ip_reass_init(void)
|
||||||
{
|
{
|
||||||
LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN",
|
|
||||||
sizeof(struct ip_reass_helper) <= IP_HLEN);
|
|
||||||
LWIP_ASSERT("ip_reass_pbufcount!=0",ip_reass_pbufcount==0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -146,7 +146,8 @@ ip_reass_tmr(void)
|
|||||||
* @return A pointer to the queue location into which the fragment was enqueued
|
* @return A pointer to the queue location into which the fragment was enqueued
|
||||||
*/
|
*/
|
||||||
static struct ip_reassdata*
|
static struct ip_reassdata*
|
||||||
enqueue_new_packet(struct ip_hdr *fraghdr) {
|
enqueue_new_packet(struct ip_hdr *fraghdr)
|
||||||
|
{
|
||||||
struct ip_reassdata* ipr;
|
struct ip_reassdata* ipr;
|
||||||
/* No matching previous fragment found, allocate a new reassdata struct */
|
/* No matching previous fragment found, allocate a new reassdata struct */
|
||||||
ipr = memp_malloc(MEMP_REASSDATA);
|
ipr = memp_malloc(MEMP_REASSDATA);
|
||||||
@ -172,7 +173,8 @@ enqueue_new_packet(struct ip_hdr *fraghdr) {
|
|||||||
* @param ipr points to the queue entry to dequeue
|
* @param ipr points to the queue entry to dequeue
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
dequeue_packet(struct ip_reassdata *ipr, struct ip_reassdata *prev) {
|
dequeue_packet(struct ip_reassdata *ipr, struct ip_reassdata *prev)
|
||||||
|
{
|
||||||
|
|
||||||
/* dequeue the reass struct */
|
/* dequeue the reass struct */
|
||||||
if (reasspackets == ipr) {
|
if (reasspackets == ipr) {
|
||||||
@ -198,7 +200,8 @@ dequeue_packet(struct ip_reassdata *ipr, struct ip_reassdata *prev) {
|
|||||||
* @return 0 if invalid, >0 otherwise
|
* @return 0 if invalid, >0 otherwise
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
chain_frag_into_packet(struct ip_reassdata *ipr, struct pbuf *new_p) {
|
chain_frag_into_packet_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p)
|
||||||
|
{
|
||||||
struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
|
struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
|
||||||
struct pbuf *q;
|
struct pbuf *q;
|
||||||
u16_t offset,len;
|
u16_t offset,len;
|
||||||
@ -212,6 +215,9 @@ chain_frag_into_packet(struct ip_reassdata *ipr, struct pbuf *new_p) {
|
|||||||
|
|
||||||
/* overwrite the fragment's ip header from the pbuf with our helper struct,
|
/* overwrite the fragment's ip header from the pbuf with our helper struct,
|
||||||
* and setup the embedded helper structure. */
|
* and setup the embedded helper structure. */
|
||||||
|
/* make sure the struct ip_reass_helper fits into the IP header */
|
||||||
|
LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN",
|
||||||
|
sizeof(struct ip_reass_helper) <= IP_HLEN);
|
||||||
iprh = (struct ip_reass_helper*)new_p->payload;
|
iprh = (struct ip_reass_helper*)new_p->payload;
|
||||||
iprh->next_pbuf = NULL;
|
iprh->next_pbuf = NULL;
|
||||||
iprh->start = offset;
|
iprh->start = offset;
|
||||||
@ -226,20 +232,26 @@ chain_frag_into_packet(struct ip_reassdata *ipr, struct pbuf *new_p) {
|
|||||||
iprh->next_pbuf = q;
|
iprh->next_pbuf = q;
|
||||||
if (iprh_prev != NULL) {
|
if (iprh_prev != NULL) {
|
||||||
/* not the fragment with the lowest offset */
|
/* not the fragment with the lowest offset */
|
||||||
|
#if IP_REASS_CHECK_OVERLAP
|
||||||
|
if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) {
|
||||||
|
/* fragment overlaps with previous or following, throw away */
|
||||||
|
goto freepbuf;
|
||||||
|
}
|
||||||
|
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||||
iprh_prev->next_pbuf = new_p;
|
iprh_prev->next_pbuf = new_p;
|
||||||
} else {
|
} else {
|
||||||
/* fragment with the lowest offset */
|
/* fragment with the lowest offset */
|
||||||
ipr->p = new_p;
|
ipr->p = new_p;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
#if IP_REASS_CHECK_OVERLAP
|
||||||
|
} else if((iprh->start == iprh_tmp->start) || (iprh->start < iprh_tmp->end)) {
|
||||||
|
/* received the same packet twice, or overlap: no need to keep the new packet */
|
||||||
|
goto freepbuf;
|
||||||
|
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||||
} else {
|
} else {
|
||||||
/* Check if the fragments received so far have not wholes. */
|
/* Check if the fragments received so far have no wholes. */
|
||||||
if (iprh_prev == NULL) {
|
if (iprh_prev != NULL) {
|
||||||
if (iprh_tmp->start != 0) {
|
|
||||||
/* the first fragment doesn't start at 0 */
|
|
||||||
valid = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (iprh_prev->end != iprh_tmp->start) {
|
if (iprh_prev->end != iprh_tmp->start) {
|
||||||
/* There is a fragment missing between the current
|
/* There is a fragment missing between the current
|
||||||
* and the previous fragment */
|
* and the previous fragment */
|
||||||
@ -256,15 +268,24 @@ chain_frag_into_packet(struct ip_reassdata *ipr, struct pbuf *new_p) {
|
|||||||
if (iprh_prev != NULL) {
|
if (iprh_prev != NULL) {
|
||||||
/* this is (for now), the fragment with the highest offset:
|
/* this is (for now), the fragment with the highest offset:
|
||||||
* chain it to the last fragment */
|
* chain it to the last fragment */
|
||||||
|
#if IP_REASS_CHECK_OVERLAP
|
||||||
|
LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start);
|
||||||
|
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||||
iprh_prev->next_pbuf = new_p;
|
iprh_prev->next_pbuf = new_p;
|
||||||
if (iprh_prev->end != iprh->start) {
|
if (iprh_prev->end != iprh->start) {
|
||||||
valid = 0;
|
valid = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
#if IP_REASS_CHECK_OVERLAP
|
||||||
|
LWIP_ASSERT("no previous fragment, this must be the first fragment!",
|
||||||
|
ipr->p == NULL);
|
||||||
|
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||||
/* this is the first fragment we ever received for this ip packet */
|
/* this is the first fragment we ever received for this ip packet */
|
||||||
ipr->p = new_p;
|
ipr->p = new_p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* At this point, the validation part begins: */
|
||||||
/* If we already received the last fragment */
|
/* If we already received the last fragment */
|
||||||
if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {
|
if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {
|
||||||
/* and had no wholes so far */
|
/* and had no wholes so far */
|
||||||
@ -306,6 +327,12 @@ chain_frag_into_packet(struct ip_reassdata *ipr, struct pbuf *new_p) {
|
|||||||
}
|
}
|
||||||
/* If we come here, not all fragments were received, yet! */
|
/* If we come here, not all fragments were received, yet! */
|
||||||
return 0; /* not yet valid! */
|
return 0; /* not yet valid! */
|
||||||
|
#if IP_REASS_CHECK_OVERLAP
|
||||||
|
freepbuf:
|
||||||
|
ip_reass_pbufcount -= pbuf_clen(new_p);
|
||||||
|
pbuf_free(new_p);
|
||||||
|
return 0;
|
||||||
|
#endif /* IP_REASS_CHECK_OVERLAP */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -391,7 +418,7 @@ ip_reass(struct pbuf *p)
|
|||||||
}
|
}
|
||||||
/* find the right place to insert this pbuf */
|
/* find the right place to insert this pbuf */
|
||||||
/* @todo: trim pbufs if fragments are overlapping */
|
/* @todo: trim pbufs if fragments are overlapping */
|
||||||
if (chain_frag_into_packet(ipr, p)) {
|
if (chain_frag_into_packet_and_validate(ipr, p)) {
|
||||||
/* the totally last fragment (flag more fragments = 0) was received at least
|
/* the totally last fragment (flag more fragments = 0) was received at least
|
||||||
* once AND all fragments are received */
|
* once AND all fragments are received */
|
||||||
ipr->packet_len += IP_HLEN;
|
ipr->packet_len += IP_HLEN;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user