mirror of
https://git.savannah.nongnu.org/git/lwip.git
synced 2026-06-01 15:34:05 +08:00
IPv6: fragment reassembly fixes
This patch aims to fix three closely related issues. o The implementation of IPV6_FRAG_COPYHEADER was fundamentally incompatible with the presence of extension headers between the IPv6 header and the Fragment Header. This patch changes the implementation to support such extension headers as well, with pretty much the same memory requirements. As a result, we can remove the check that prevented such packets from being reassembled in all cases, even with IPV6_FRAG_COPYHEADER off. o Given that temporary data is stored in the Fragment Header of packets saved for the purpose of reassembly, but ICMPv6 "Fragment Reassembly Time Exceeded" packets contain part of the original packet, such ICMPv6 packets could actually end up containing part of the temporary data, which may even include a pointer value. The ICMPv6 packet should contain the original, unchanged packet, so save the original header data before overwriting it even if IPV6_FRAG_COPYHEADER is disabled. This does add some extra memory consumption. o Previously, the reassembly would leave the fragment header in the reassembled packet, which is not permitted by RFC 2460 and prevents reassembly of particularly large packets (close to 65535 bytes after reassembly). This patch gets rid of the fragment header. It does require an implementation of memmove() for that purpose. Note that this patch aims to improve correctness. Future changes might restore some of the previous functionality in order to regain optimal performance for certain cases (at the cost of more code).
This commit is contained in:
committed by
Dirk Ziegelmeier
parent
b17c050861
commit
7cedf7ae71
@@ -54,24 +54,34 @@ extern "C" {
|
||||
|
||||
#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 */
|
||||
/** The IPv6 reassembly timer interval in milliseconds. */
|
||||
#define IP6_REASS_TMR_INTERVAL 1000
|
||||
|
||||
/** IP6_FRAG_COPYHEADER==1: for platforms where sizeof(void*) > 4, "struct
|
||||
* ip6_reass_helper" is too large to be stored in the IPv6 fragment header, and
|
||||
* will bleed into the header before it, which may be the IPv6 header or an
|
||||
* extension header. This means that for each first fragment packet, we need to
|
||||
* 1) make a copy of some IPv6 header fields (src+dest) that we need later on,
|
||||
* just in case we do overwrite part of the IPv6 header, and 2) make a copy of
|
||||
* the header data that we overwrote, so that we can restore it before either
|
||||
* completing reassembly or sending an ICMPv6 reply. The last part is true even
|
||||
* if this setting is disabled, but if it is enabled, we need to save a bit
|
||||
* more data (up to the size of a pointer) because we overwrite more. */
|
||||
#ifndef IPV6_FRAG_COPYHEADER
|
||||
#define IPV6_FRAG_COPYHEADER 0
|
||||
#endif
|
||||
|
||||
/** The IPv6 reassembly timer interval in milliseconds. */
|
||||
#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? */
|
||||
/* With IPV6_FRAG_COPYHEADER==1, a helper structure may (or, depending on the
|
||||
* presence of extensions, may not) overwrite part of the IP header. Therefore,
|
||||
* we copy the fields that we need from the IP header for as long as the helper
|
||||
* structure may still be in place. This is easier than temporarily restoring
|
||||
* those fields in the IP header each time we need to perform checks on them. */
|
||||
#if IPV6_FRAG_COPYHEADER
|
||||
#define IPV6_FRAG_HDRPTR
|
||||
#define IPV6_FRAG_HDRREF(hdr) (&(hdr))
|
||||
#define IPV6_FRAG_SRC(ipr) ((ipr)->src)
|
||||
#define IPV6_FRAG_DEST(ipr) ((ipr)->dest)
|
||||
#else /* IPV6_FRAG_COPYHEADER */
|
||||
#define IPV6_FRAG_HDRPTR *
|
||||
#define IPV6_FRAG_HDRREF(hdr) (hdr)
|
||||
#define IPV6_FRAG_SRC(ipr) ((ipr)->iphdr->src)
|
||||
#define IPV6_FRAG_DEST(ipr) ((ipr)->iphdr->dest)
|
||||
#endif /* IPV6_FRAG_COPYHEADER */
|
||||
|
||||
/** IPv6 reassembly helper struct.
|
||||
@@ -80,7 +90,17 @@ extern "C" {
|
||||
struct ip6_reassdata {
|
||||
struct ip6_reassdata *next;
|
||||
struct pbuf *p;
|
||||
struct ip6_hdr IPV6_FRAG_HDRPTR iphdr;
|
||||
struct ip6_hdr *iphdr; /* pointer to the first (original) IPv6 header */
|
||||
#if IPV6_FRAG_COPYHEADER
|
||||
ip6_addr_p_t src; /* copy of the source address in the IP header */
|
||||
ip6_addr_p_t dest; /* copy of the destination address in the IP header */
|
||||
/* This buffer (for the part of the original header that we overwrite) will
|
||||
* be slightly oversized, but we cannot compute the exact size from here. */
|
||||
u8_t orig_hdr[sizeof(struct ip6_frag_hdr) + sizeof(void*)];
|
||||
#else /* IPV6_FRAG_COPYHEADER */
|
||||
/* In this case we still need the buffer, for sending ICMPv6 replies. */
|
||||
u8_t orig_hdr[sizeof(struct ip6_frag_hdr)];
|
||||
#endif /* IPV6_FRAG_COPYHEADER */
|
||||
u32_t identification;
|
||||
u16_t datagram_len;
|
||||
u8_t nexth;
|
||||
|
||||
@@ -144,6 +144,15 @@
|
||||
#if !defined SMEMCPY || defined __DOXYGEN__
|
||||
#define SMEMCPY(dst,src,len) memcpy(dst,src,len)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* MEMMOVE: override this if you have a faster implementation at hand than the
|
||||
* one included in your C library. lwIP currently uses MEMMOVE only when IPv6
|
||||
* fragmentation support is enabled.
|
||||
*/
|
||||
#if !defined MEMMOVE || defined __DOXYGEN__
|
||||
#define MEMMOVE(dst,src,len) memmove(dst,src,len)
|
||||
#endif
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user