Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:12.2
xen
ipxe-ipv4-fragment.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File ipxe-ipv4-fragment.patch of Package xen
Index: xen-4.1.2-testing/tools/firmware/etherboot/patches/ipxe-git-13186b64b6c3 =================================================================== --- /dev/null 2010-05-08 03:31:08.000000000 -0600 +++ xen-4.1.2-testing/tools/firmware/etherboot/patches/ipxe-git-13186b64b6c3 2011-12-19 15:05:32.000000000 -0700 @@ -0,0 +1,354 @@ +commit 13186b64b6c3d5cbe9ed13bda1532e79b1afe81d +Author: Michael Brown <mcb30@ipxe.org> +Date: Sat Jul 16 01:15:53 2011 +0100 + + [ipv4] Fix fragment reassembly + + Signed-off-by: Michael Brown <mcb30@ipxe.org> + Signed-off-by: Michal Kubecek <mkubecek@suse.cz> + +diff -up a/src/include/gpxe/ip.h.orig-frag b/src/include/gpxe/ip.h +--- a/src/include/gpxe/ip.h.orig-frag 2010-02-02 17:12:44.000000000 +0100 ++++ b/src/include/gpxe/ip.h 2011-11-18 15:49:17.202660163 +0100 +@@ -32,9 +32,6 @@ struct net_protocol; + #define IP_TOS 0 + #define IP_TTL 64 + +-#define IP_FRAG_IOB_SIZE 1500 +-#define IP_FRAG_TIMEOUT 50 +- + /** An IPv4 packet header */ + struct iphdr { + uint8_t verhdrlen; +@@ -74,20 +71,16 @@ struct ipv4_miniroute { + struct in_addr gateway; + }; + +-/* Fragment reassembly buffer */ +-struct frag_buffer { +- /* Identification number */ +- uint16_t ident; +- /* Source network address */ +- struct in_addr src; +- /* Destination network address */ +- struct in_addr dest; +- /* Reassembled I/O buffer */ +- struct io_buffer *frag_iob; +- /* Reassembly timer */ +- struct retry_timer frag_timer; ++/* IPv4 fragment reassembly buffer */ ++struct ipv4_fragment { + /* List of fragment reassembly buffers */ + struct list_head list; ++ /** Reassembled packet */ ++ struct io_buffer *iobuf; ++ /** Current offset */ ++ size_t offset; ++ /** Reassembly timer */ ++ struct retry_timer timer; + }; + + extern struct list_head ipv4_miniroutes; +diff -up a/src/include/gpxe/retry.h.orig-frag b/src/include/gpxe/retry.h +--- a/src/include/gpxe/retry.h.orig-frag 2010-02-02 17:12:44.000000000 +0100 ++++ b/src/include/gpxe/retry.h 2011-11-18 15:59:25.258837891 +0100 +@@ -51,6 +51,19 @@ struct retry_timer { + void ( * expired ) ( struct retry_timer *timer, int over ); + }; + ++/** ++ * Initialise a timer ++ * ++ * @v timer Retry timer ++ * @v expired Timer expired callback ++ */ ++static inline __attribute__ (( always_inline )) void ++timer_init ( struct retry_timer *timer, ++ void ( * expired ) ( struct retry_timer *timer, int over ) ) ++{ ++ timer->expired = expired; ++} ++ + extern void start_timer ( struct retry_timer *timer ); + extern void start_timer_fixed ( struct retry_timer *timer, + unsigned long timeout ); +diff -up a/src/net/ipv4.c.orig-frag b/src/net/ipv4.c +--- a/src/net/ipv4.c.orig-frag 2010-02-02 17:12:44.000000000 +0100 ++++ b/src/net/ipv4.c 2011-11-18 15:49:17.203660142 +0100 +@@ -14,6 +14,7 @@ + #include <gpxe/tcpip.h> + #include <gpxe/dhcp.h> + #include <gpxe/settings.h> ++#include <gpxe/timer.h> + + /** @file + * +@@ -32,7 +33,10 @@ struct net_protocol ipv4_protocol; + struct list_head ipv4_miniroutes = LIST_HEAD_INIT ( ipv4_miniroutes ); + + /** List of fragment reassembly buffers */ +-static LIST_HEAD ( frag_buffers ); ++static LIST_HEAD ( ipv4_fragments ); ++ ++/** Fragment reassembly timeout */ ++#define IP_FRAG_TIMEOUT ( TICKS_PER_SEC / 2 ) + + /** + * Add IPv4 minirouting table entry +@@ -134,104 +138,126 @@ static struct ipv4_miniroute * ipv4_rout + } + + /** +- * Fragment reassembly counter timeout ++ * Expire fragment reassembly buffer + * +- * @v timer Retry timer +- * @v over If asserted, the timer is greater than @c MAX_TIMEOUT ++ * @v timer Retry timer ++ * @v fail Failure indicator + */ +-static void ipv4_frag_expired ( struct retry_timer *timer __unused, +- int over ) { +- if ( over ) { +- DBG ( "Fragment reassembly timeout" ); +- /* Free the fragment buffer */ +- } ++static void ipv4_fragment_expired ( struct retry_timer *timer, ++ int fail __unused ) { ++ struct ipv4_fragment *frag = ++ container_of ( timer, struct ipv4_fragment, timer ); ++ struct iphdr *iphdr = frag->iobuf->data; ++ ++ DBG ( "IPv4 fragment %04x expired\n", ntohs ( iphdr->ident ) ); ++ free_iob ( frag->iobuf ); ++ list_del ( &frag->list ); ++ free ( frag ); + } + + /** +- * Free fragment buffer ++ * Find matching fragment reassembly buffer + * +- * @v fragbug Fragment buffer ++ * @v iphdr IPv4 header ++ * @ret frag Fragment reassembly buffer, or NULL + */ +-static void free_fragbuf ( struct frag_buffer *fragbuf ) { +- free ( fragbuf ); ++static struct ipv4_fragment * ipv4_fragment ( struct iphdr *iphdr ) { ++ struct ipv4_fragment *frag; ++ struct iphdr *frag_iphdr; ++ ++ list_for_each_entry ( frag, &ipv4_fragments, list ) { ++ frag_iphdr = frag->iobuf->data; ++ ++ if ( ( iphdr->src.s_addr == frag_iphdr->src.s_addr ) && ++ ( iphdr->ident == frag_iphdr->ident ) ) { ++ return frag; ++ } ++ } ++ ++ return NULL; + } + + /** + * Fragment reassembler + * +- * @v iobuf I/O buffer, fragment of the datagram +- * @ret frag_iob Reassembled packet, or NULL ++ * @v iobuf I/O buffer ++ * @ret iobuf Reassembled packet, or NULL + */ +-static struct io_buffer * ipv4_reassemble ( struct io_buffer * iobuf ) { ++static struct io_buffer * ipv4_reassemble ( struct io_buffer *iobuf ) { + struct iphdr *iphdr = iobuf->data; +- struct frag_buffer *fragbuf; +- +- /** +- * Check if the fragment belongs to any fragment series +- */ +- list_for_each_entry ( fragbuf, &frag_buffers, list ) { +- if ( fragbuf->ident == iphdr->ident && +- fragbuf->src.s_addr == iphdr->src.s_addr ) { +- /** +- * Check if the packet is the expected fragment +- * +- * The offset of the new packet must be equal to the +- * length of the data accumulated so far (the length of +- * the reassembled I/O buffer +- */ +- if ( iob_len ( fragbuf->frag_iob ) == +- ( iphdr->frags & IP_MASK_OFFSET ) ) { +- /** +- * Append the contents of the fragment to the +- * reassembled I/O buffer +- */ +- iob_pull ( iobuf, sizeof ( *iphdr ) ); +- memcpy ( iob_put ( fragbuf->frag_iob, +- iob_len ( iobuf ) ), +- iobuf->data, iob_len ( iobuf ) ); +- free_iob ( iobuf ); +- +- /** Check if the fragment series is over */ +- if ( ! ( iphdr->frags & IP_MASK_MOREFRAGS ) ) { +- iobuf = fragbuf->frag_iob; +- free_fragbuf ( fragbuf ); +- return iobuf; +- } +- +- } else { +- /* Discard the fragment series */ +- free_fragbuf ( fragbuf ); +- free_iob ( iobuf ); +- } +- return NULL; ++ size_t offset = ( ( ntohs ( iphdr->frags ) & IP_MASK_OFFSET ) << 3 ); ++ unsigned int more_frags = ( iphdr->frags & htons ( IP_MASK_MOREFRAGS )); ++ size_t hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 ); ++ struct ipv4_fragment *frag; ++ size_t expected_offset; ++ struct io_buffer *new_iobuf; ++ ++ /* Find matching fragment reassembly buffer, if any */ ++ frag = ipv4_fragment ( iphdr ); ++ ++ /* Drop out-of-order fragments */ ++ expected_offset = ( frag ? frag->offset : 0 ); ++ if ( offset != expected_offset ) { ++ DBG ( "IPv4 dropping out-of-sequence fragment %04x (%zd+%zd, " ++ "expected %zd)\n", ntohs ( iphdr->ident ), offset, ++ ( iob_len ( iobuf ) - hdrlen ), expected_offset ); ++ goto drop; ++ } ++ ++ /* Create or extend fragment reassembly buffer as applicable */ ++ if ( frag == NULL ) { ++ ++ /* Create new fragment reassembly buffer */ ++ frag = zalloc ( sizeof ( *frag ) ); ++ if ( ! frag ) ++ goto drop; ++ list_add ( &frag->list, &ipv4_fragments ); ++ frag->iobuf = iobuf; ++ frag->offset = ( iob_len ( iobuf ) - hdrlen ); ++ timer_init ( &frag->timer, ipv4_fragment_expired ); ++ ++ } else { ++ ++ /* Extend reassembly buffer */ ++ iob_pull ( iobuf, hdrlen ); ++ new_iobuf = alloc_iob ( iob_len ( frag->iobuf ) + ++ iob_len ( iobuf ) ); ++ if ( ! new_iobuf ) { ++ DBG ( "IPv4 could not extend reassembly buffer to " ++ "%zd bytes\n", ++ ( iob_len ( frag->iobuf ) + iob_len ( iobuf ) ) ); ++ goto drop; + } +- } +- +- /** Check if the fragment is the first in the fragment series */ +- if ( iphdr->frags & IP_MASK_MOREFRAGS && +- ( ( iphdr->frags & IP_MASK_OFFSET ) == 0 ) ) { +- +- /** Create a new fragment buffer */ +- fragbuf = ( struct frag_buffer* ) malloc ( sizeof( *fragbuf ) ); +- fragbuf->ident = iphdr->ident; +- fragbuf->src = iphdr->src; +- +- /* Set up the reassembly I/O buffer */ +- fragbuf->frag_iob = alloc_iob ( IP_FRAG_IOB_SIZE ); +- iob_pull ( iobuf, sizeof ( *iphdr ) ); +- memcpy ( iob_put ( fragbuf->frag_iob, iob_len ( iobuf ) ), ++ memcpy ( iob_put ( new_iobuf, iob_len ( frag->iobuf ) ), ++ frag->iobuf->data, iob_len ( frag->iobuf ) ); ++ memcpy ( iob_put ( new_iobuf, iob_len ( iobuf ) ), + iobuf->data, iob_len ( iobuf ) ); ++ free_iob ( frag->iobuf ); ++ frag->iobuf = new_iobuf; ++ frag->offset += iob_len ( iobuf ); + free_iob ( iobuf ); ++ iphdr = frag->iobuf->data; ++ iphdr->len = ntohs ( iob_len ( frag->iobuf ) ); + +- /* Set the reassembly timer */ +- fragbuf->frag_timer.timeout = IP_FRAG_TIMEOUT; +- fragbuf->frag_timer.expired = ipv4_frag_expired; +- start_timer ( &fragbuf->frag_timer ); ++ /* Stop fragment reassembly timer */ ++ stop_timer ( &frag->timer ); + +- /* Add the fragment buffer to the list of fragment buffers */ +- list_add ( &fragbuf->list, &frag_buffers ); ++ /* If this is the final fragment, return it */ ++ if ( ! more_frags ) { ++ iobuf = frag->iobuf; ++ list_del ( &frag->list ); ++ free ( frag ); ++ return iobuf; ++ } + } +- ++ ++ /* (Re)start fragment reassembly timer */ ++ start_timer_fixed ( &frag->timer, IP_FRAG_TIMEOUT ); ++ ++ return NULL; ++ ++ drop: ++ free_iob ( iobuf ); + return NULL; + } + +@@ -432,37 +458,38 @@ static int ipv4_rx ( struct io_buffer *i + goto err; + } + ++ /* Truncate packet to correct length */ ++ iob_unput ( iobuf, ( iob_len ( iobuf ) - len ) ); ++ + /* Print IPv4 header for debugging */ + DBG ( "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) ); + DBG ( "%s len %d proto %d id %04x csum %04x\n", + inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol, + ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) ); + +- /* Truncate packet to correct length, calculate pseudo-header +- * checksum and then strip off the IPv4 header. +- */ +- iob_unput ( iobuf, ( iob_len ( iobuf ) - len ) ); +- pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM ); +- iob_pull ( iobuf, hdrlen ); +- +- /* Fragment reassembly */ +- if ( ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) ) || +- ( ( iphdr->frags & htons ( IP_MASK_OFFSET ) ) != 0 ) ) { +- /* Pass the fragment to ipv4_reassemble() which either +- * returns a fully reassembled I/O buffer or NULL. ++ /* Perform fragment reassembly if applicable */ ++ if ( iphdr->frags & htons ( IP_MASK_OFFSET | IP_MASK_MOREFRAGS ) ) { ++ /* Pass the fragment to ipv4_reassemble() which returns ++ * either a fully reassembled I/O buffer or NULL. + */ + iobuf = ipv4_reassemble ( iobuf ); + if ( ! iobuf ) + return 0; ++ iphdr = iobuf->data; ++ hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 ); + } + +- /* Construct socket addresses and hand off to transport layer */ ++ /* Construct socket addresses, calculate pseudo-header ++ * checksum, and hand off to transport layer ++ */ + memset ( &src, 0, sizeof ( src ) ); + src.sin.sin_family = AF_INET; + src.sin.sin_addr = iphdr->src; + memset ( &dest, 0, sizeof ( dest ) ); + dest.sin.sin_family = AF_INET; + dest.sin.sin_addr = iphdr->dest; ++ pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM ); ++ iob_pull ( iobuf, hdrlen ); + if ( ( rc = tcpip_rx ( iobuf, iphdr->protocol, &src.st, + &dest.st, pshdr_csum ) ) != 0 ) { + DBG ( "IPv4 received packet rejected by stack: %s\n", Index: xen-4.1.2-testing/tools/firmware/etherboot/patches/series =================================================================== --- xen-4.1.2-testing.orig/tools/firmware/etherboot/patches/series +++ xen-4.1.2-testing/tools/firmware/etherboot/patches/series @@ -2,3 +2,4 @@ boot_prompt_option.patch gpxe-git-0edf2405b457 gpxe-git-a803ef3dfeac ipxe-git-f7c5918b179b +ipxe-git-13186b64b6c3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor