369 lines
12 KiB
Diff
369 lines
12 KiB
Diff
|
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
|