mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-10-01 04:12:07 +00:00
fixed bug bug #41009: IPv6 reassembly broken on 64-bit platforms: define IPV6_FRAG_COPYHEADER==1 on these platforms to copy the IPv6 header instead of referencing it, which gives more room for struct ip6_reass_helper
This commit is contained in:
parent
aad76acb68
commit
f649172580
@ -249,6 +249,11 @@ HISTORY
|
|||||||
|
|
||||||
++ Bugfixes:
|
++ Bugfixes:
|
||||||
|
|
||||||
|
2015-08-26: Simon Goldschmidt
|
||||||
|
* ip6_frag.h/.c: fixed bug bug #41009: IPv6 reassembly broken on 64-bit platforms:
|
||||||
|
define IPV6_FRAG_COPYHEADER==1 on these platforms to copy the IPv6 header
|
||||||
|
instead of referencing it, which gives more room for struct ip6_reass_helper
|
||||||
|
|
||||||
2015-08-25: Simon Goldschmidt
|
2015-08-25: Simon Goldschmidt
|
||||||
* sockets.c: fixed bug #45827: recvfrom: TCP window is updated with MSG_PEEK
|
* sockets.c: fixed bug #45827: recvfrom: TCP window is updated with MSG_PEEK
|
||||||
|
|
||||||
|
@ -70,6 +70,10 @@
|
|||||||
#define IP_REASS_FREE_OLDEST 1
|
#define IP_REASS_FREE_OLDEST 1
|
||||||
#endif /* IP_REASS_FREE_OLDEST */
|
#endif /* IP_REASS_FREE_OLDEST */
|
||||||
|
|
||||||
|
#if IPV6_FRAG_COPYHEADER
|
||||||
|
#define IPV6_FRAG_REQROOM ((s16_t)(sizeof(struct ip6_reass_helper) - IP6_FRAG_HLEN))
|
||||||
|
#endif
|
||||||
|
|
||||||
#define IP_REASS_FLAG_LASTFRAG 0x01
|
#define IP_REASS_FLAG_LASTFRAG 0x01
|
||||||
|
|
||||||
/** This is a helper struct which holds the starting
|
/** This is a helper struct which holds the starting
|
||||||
@ -150,7 +154,7 @@ ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr)
|
|||||||
p = ipr->p;
|
p = ipr->p;
|
||||||
ipr->p = iprh->next_pbuf;
|
ipr->p = iprh->next_pbuf;
|
||||||
/* Then, move back to the original header (we are now pointing to Fragment header). */
|
/* Then, move back to the original header (we are now pointing to Fragment header). */
|
||||||
if (pbuf_header(p, (s16_t)((u8_t*)p->payload - (u8_t*)ipr->iphdr))) {
|
if (pbuf_header(p, (s16_t)((u8_t*)p->payload - (u8_t*)IPV6_FRAG_HDRREF(ipr->iphdr)))) {
|
||||||
LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed\n", 0);
|
LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed\n", 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -278,8 +282,8 @@ ip6_reass(struct pbuf *p)
|
|||||||
in the reassembly buffer. If so, we proceed with copying the
|
in the reassembly buffer. If so, we proceed with copying the
|
||||||
fragment into the buffer. */
|
fragment into the buffer. */
|
||||||
if ((frag_hdr->_identification == ipr->identification) &&
|
if ((frag_hdr->_identification == ipr->identification) &&
|
||||||
ip6_addr_cmp(ip6_current_src_addr(), &(ipr->iphdr->src)) &&
|
ip6_addr_cmp(ip6_current_src_addr(), &(IPV6_FRAG_HDRREF(ipr->iphdr)->src)) &&
|
||||||
ip6_addr_cmp(ip6_current_dest_addr(), &(ipr->iphdr->dest))) {
|
ip6_addr_cmp(ip6_current_dest_addr(), &(IPV6_FRAG_HDRREF(ipr->iphdr)->dest))) {
|
||||||
IP6_FRAG_STATS_INC(ip6_frag.cachehit);
|
IP6_FRAG_STATS_INC(ip6_frag.cachehit);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -320,7 +324,11 @@ ip6_reass(struct pbuf *p)
|
|||||||
/* Use the current IPv6 header for src/dest address reference.
|
/* Use the current IPv6 header for src/dest address reference.
|
||||||
* Eventually, we will replace it when we get the first fragment
|
* Eventually, we will replace it when we get the first fragment
|
||||||
* (it might be this one, in any case, it is done later). */
|
* (it might be this one, in any case, it is done later). */
|
||||||
|
#if IPV6_FRAG_COPYHEADER
|
||||||
|
MEMCPY(&ipr->iphdr, ip6_current_header(), IP6_HLEN);
|
||||||
|
#else /* IPV6_FRAG_COPYHEADER */
|
||||||
ipr->iphdr = (struct ip6_hdr *)ip6_current_header();
|
ipr->iphdr = (struct ip6_hdr *)ip6_current_header();
|
||||||
|
#endif /* IPV6_FRAG_COPYHEADER */
|
||||||
|
|
||||||
/* copy the fragmented packet id. */
|
/* copy the fragmented packet id. */
|
||||||
ipr->identification = frag_hdr->_identification;
|
ipr->identification = frag_hdr->_identification;
|
||||||
@ -352,9 +360,17 @@ ip6_reass(struct pbuf *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Overwrite Fragment Header with our own helper struct. */
|
/* Overwrite Fragment Header with our own helper struct. */
|
||||||
iprh = (struct ip6_reass_helper *)p->payload;
|
#if IPV6_FRAG_COPYHEADER
|
||||||
LWIP_ASSERT("sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN",
|
if (IPV6_FRAG_REQROOM > 0) {
|
||||||
|
/* make room for struct ip6_reass_helper (only required if sizeof(void*) > 4) */
|
||||||
|
err_t hdrerr = pbuf_header(p, IPV6_FRAG_REQROOM);
|
||||||
|
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == ERR_OK);
|
||||||
|
}
|
||||||
|
#else /* IPV6_FRAG_COPYHEADER */
|
||||||
|
LWIP_ASSERT("sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN, set IP6_FRAG_COPYHEADER to 1",
|
||||||
sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN);
|
sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN);
|
||||||
|
#endif /* IPV6_FRAG_COPYHEADER */
|
||||||
|
iprh = (struct ip6_reass_helper *)p->payload;
|
||||||
iprh->next_pbuf = NULL;
|
iprh->next_pbuf = NULL;
|
||||||
iprh->start = (offset & IP6_FRAG_OFFSET_MASK);
|
iprh->start = (offset & IP6_FRAG_OFFSET_MASK);
|
||||||
iprh->end = (offset & IP6_FRAG_OFFSET_MASK) + len;
|
iprh->end = (offset & IP6_FRAG_OFFSET_MASK) + len;
|
||||||
@ -444,7 +460,13 @@ ip6_reass(struct pbuf *p)
|
|||||||
|
|
||||||
/* Remember IPv6 header if this is the first fragment. */
|
/* Remember IPv6 header if this is the first fragment. */
|
||||||
if (iprh->start == 0) {
|
if (iprh->start == 0) {
|
||||||
|
#if IPV6_FRAG_COPYHEADER
|
||||||
|
if (iprh->next_pbuf != NULL) {
|
||||||
|
MEMCPY(&ipr->iphdr, ip6_current_header(), IP6_HLEN);
|
||||||
|
}
|
||||||
|
#else /* IPV6_FRAG_COPYHEADER */
|
||||||
ipr->iphdr = (struct ip6_hdr *)ip6_current_header();
|
ipr->iphdr = (struct ip6_hdr *)ip6_current_header();
|
||||||
|
#endif /* IPV6_FRAG_COPYHEADER */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If this is the last fragment, calculate total packet length. */
|
/* If this is the last fragment, calculate total packet length. */
|
||||||
@ -476,19 +498,26 @@ ip6_reass(struct pbuf *p)
|
|||||||
|
|
||||||
if (valid) {
|
if (valid) {
|
||||||
/* All fragments have been received */
|
/* All fragments have been received */
|
||||||
u8_t* iphdr_ptr;
|
struct ip6_hdr* iphdr_ptr;
|
||||||
|
|
||||||
/* chain together the pbufs contained within the ip6_reassdata list. */
|
/* chain together the pbufs contained within the ip6_reassdata list. */
|
||||||
iprh = (struct ip6_reass_helper*) ipr->p->payload;
|
iprh = (struct ip6_reass_helper*) ipr->p->payload;
|
||||||
while(iprh != NULL) {
|
while(iprh != NULL) {
|
||||||
|
struct pbuf* next_pbuf = iprh->next_pbuf;
|
||||||
if (iprh->next_pbuf != NULL) {
|
if (next_pbuf != NULL) {
|
||||||
/* Save next helper struct (will be hidden in next step). */
|
/* Save next helper struct (will be hidden in next step). */
|
||||||
iprh_tmp = (struct ip6_reass_helper*) iprh->next_pbuf->payload;
|
iprh_tmp = (struct ip6_reass_helper*)next_pbuf->payload;
|
||||||
|
|
||||||
/* hide the fragment header for every succeeding fragment */
|
/* hide the fragment header for every succeeding fragment */
|
||||||
pbuf_header(iprh->next_pbuf, -IP6_FRAG_HLEN);
|
pbuf_header(next_pbuf, -IP6_FRAG_HLEN);
|
||||||
pbuf_cat(ipr->p, iprh->next_pbuf);
|
#if IPV6_FRAG_COPYHEADER
|
||||||
|
if (IPV6_FRAG_REQROOM > 0) {
|
||||||
|
/* hide the extra bytes borrowed from ip6_hdr for struct ip6_reass_helper */
|
||||||
|
err_t hdrerr = pbuf_header(next_pbuf, -(s16_t)(IPV6_FRAG_REQROOM));
|
||||||
|
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == ERR_OK);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
pbuf_cat(ipr->p, next_pbuf);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
iprh_tmp = NULL;
|
iprh_tmp = NULL;
|
||||||
@ -497,13 +526,25 @@ ip6_reass(struct pbuf *p)
|
|||||||
iprh = iprh_tmp;
|
iprh = iprh_tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IPV6_FRAG_COPYHEADER
|
||||||
|
if (IPV6_FRAG_REQROOM > 0) {
|
||||||
|
/* get back room for struct ip6_reass_helper (only required if sizeof(void*) > 4) */
|
||||||
|
err_t hdrerr = pbuf_header(ipr->p, -(s16_t)(IPV6_FRAG_REQROOM));
|
||||||
|
LWIP_ASSERT("no room for struct ip6_reass_helper", hdrerr == ERR_OK);
|
||||||
|
}
|
||||||
|
iphdr_ptr = (struct ip6_hdr*)((u8_t*)ipr->p->payload - IP6_HLEN);
|
||||||
|
MEMCPY(iphdr_ptr, &ipr->iphdr, IP6_HLEN);
|
||||||
|
#else
|
||||||
|
iphdr_ptr = ipr->iphdr;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Adjust datagram length by adding header lengths. */
|
/* Adjust datagram length by adding header lengths. */
|
||||||
ipr->datagram_len += (u16_t)(((u8_t*)ipr->p->payload - (u8_t*)ipr->iphdr)
|
ipr->datagram_len += (u16_t)(((u8_t*)ipr->p->payload - (u8_t*)iphdr_ptr)
|
||||||
+ IP6_FRAG_HLEN
|
+ IP6_FRAG_HLEN
|
||||||
- IP6_HLEN);
|
- IP6_HLEN);
|
||||||
|
|
||||||
/* Set payload length in ip header. */
|
/* Set payload length in ip header. */
|
||||||
ipr->iphdr->_plen = htons(ipr->datagram_len);
|
iphdr_ptr->_plen = htons(ipr->datagram_len);
|
||||||
|
|
||||||
/* Get the first pbuf. */
|
/* Get the first pbuf. */
|
||||||
p = ipr->p;
|
p = ipr->p;
|
||||||
@ -525,14 +566,13 @@ ip6_reass(struct pbuf *p)
|
|||||||
LWIP_ASSERT("sanity check linked list", ipr_prev != NULL);
|
LWIP_ASSERT("sanity check linked list", ipr_prev != NULL);
|
||||||
ipr_prev->next = ipr->next;
|
ipr_prev->next = ipr->next;
|
||||||
}
|
}
|
||||||
iphdr_ptr = (u8_t*)ipr->iphdr;
|
|
||||||
memp_free(MEMP_IP6_REASSDATA, ipr);
|
memp_free(MEMP_IP6_REASSDATA, ipr);
|
||||||
|
|
||||||
/* adjust the number of pbufs currently queued for reassembly. */
|
/* adjust the number of pbufs currently queued for reassembly. */
|
||||||
ip6_reass_pbufcount -= pbuf_clen(p);
|
ip6_reass_pbufcount -= pbuf_clen(p);
|
||||||
|
|
||||||
/* Move pbuf back to IPv6 header. */
|
/* Move pbuf back to IPv6 header. */
|
||||||
if (pbuf_header(p, (s16_t)((u8_t*)p->payload - iphdr_ptr))) {
|
if (pbuf_header(p, (s16_t)((u8_t*)p->payload - (u8_t*)iphdr_ptr))) {
|
||||||
LWIP_ASSERT("ip6_reass: moving p->payload to ip6 header failed\n", 0);
|
LWIP_ASSERT("ip6_reass: moving p->payload to ip6 header failed\n", 0);
|
||||||
pbuf_free(p);
|
pbuf_free(p);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
#include "lwip/opt.h"
|
#include "lwip/opt.h"
|
||||||
#include "lwip/pbuf.h"
|
#include "lwip/pbuf.h"
|
||||||
#include "lwip/ip6_addr.h"
|
#include "lwip/ip6_addr.h"
|
||||||
|
#include "lwip/ip6.h"
|
||||||
#include "lwip/netif.h"
|
#include "lwip/netif.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -53,16 +54,33 @@ extern "C" {
|
|||||||
|
|
||||||
#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */
|
#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
|
/** IP6_FRAG_COPYHEADER==1: for platforms where sizeof(void*) > 4, this needs to
|
||||||
|
* be enabled (to not overwrite part of the data). When enabled, the IPv6 header
|
||||||
|
* is copied instead of referencing it, which gives more room for struct ip6_reass_helper */
|
||||||
|
#ifndef IPV6_FRAG_COPYHEADER
|
||||||
|
#define IPV6_FRAG_COPYHEADER 0
|
||||||
|
#endif
|
||||||
|
|
||||||
/* The IPv6 reassembly timer interval in milliseconds. */
|
/* The IPv6 reassembly timer interval in milliseconds. */
|
||||||
#define IP6_REASS_TMR_INTERVAL 1000
|
#define IP6_REASS_TMR_INTERVAL 1000
|
||||||
|
|
||||||
|
/* Copy the complete header of the first fragment to struct ip6_reassdata
|
||||||
|
or just point to its original location in the first pbuf? */
|
||||||
|
#if IPV6_FRAG_COPYHEADER
|
||||||
|
#define IPV6_FRAG_HDRPTR
|
||||||
|
#define IPV6_FRAG_HDRREF(hdr) (&(hdr))
|
||||||
|
#else /* IPV6_FRAG_COPYHEADER */
|
||||||
|
#define IPV6_FRAG_HDRPTR *
|
||||||
|
#define IPV6_FRAG_HDRREF(hdr) (hdr)
|
||||||
|
#endif /* IPV6_FRAG_COPYHEADER */
|
||||||
|
|
||||||
/* IPv6 reassembly helper struct.
|
/* IPv6 reassembly helper struct.
|
||||||
* This is exported because memp needs to know the size.
|
* This is exported because memp needs to know the size.
|
||||||
*/
|
*/
|
||||||
struct ip6_reassdata {
|
struct ip6_reassdata {
|
||||||
struct ip6_reassdata *next;
|
struct ip6_reassdata *next;
|
||||||
struct pbuf *p;
|
struct pbuf *p;
|
||||||
struct ip6_hdr * iphdr;
|
struct ip6_hdr IPV6_FRAG_HDRPTR iphdr;
|
||||||
u32_t identification;
|
u32_t identification;
|
||||||
u16_t datagram_len;
|
u16_t datagram_len;
|
||||||
u8_t nexth;
|
u8_t nexth;
|
||||||
|
Loading…
Reference in New Issue
Block a user