[ipxe-devel] PXENV_UDP_WRITE

Frediano Ziglio frediano.ziglio at citrix.com
Wed Feb 29 18:30:39 UTC 2012


This patch implement handling ARP request sending UDP packets

From 2e11876de0968568b8a4b75dcc305af80e2407f1 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <frediano.ziglio at citrix.com>
Date: Wed, 29 Feb 2012 18:29:00 +0000
Subject: [PATCH] handle ARP packets in PXENV_UDP_WRITE

---
 src/arch/i386/interface/pxe/pxe_udp.c |  119 ++++++++++++++++++++++-----------
 1 files changed, 79 insertions(+), 40 deletions(-)

diff --git a/src/arch/i386/interface/pxe/pxe_udp.c b/src/arch/i386/interface/pxe/pxe_udp.c
index a127f45..79430f9 100644
--- a/src/arch/i386/interface/pxe/pxe_udp.c
+++ b/src/arch/i386/interface/pxe/pxe_udp.c
@@ -11,6 +11,7 @@
 #include <ipxe/udp.h>
 #include <ipxe/uaccess.h>
 #include <ipxe/process.h>
+#include <ipxe/retry.h>
 #include <pxe.h>
 
 /*
@@ -41,6 +42,10 @@ struct pxe_udp_connection {
 	struct sockaddr_in local;
 	/** Current PXENV_UDP_READ parameter block */
 	struct s_PXENV_UDP_READ *pxenv_udp_read;
+	/** Current PXENV_UDP_WRITE parameter block */
+	struct s_PXENV_UDP_WRITE *pxenv_udp_write;
+	/** return from write */
+	int rc;
 };
 
 /**
@@ -213,6 +218,67 @@ pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
 	return PXENV_EXIT_SUCCESS;
 }
 
+static void udp_write_expired ( struct retry_timer *timer, int over )
+{
+	struct sockaddr_in dest;
+	struct xfer_metadata meta = {
+		.src = ( struct sockaddr * ) &pxe_udp.local,
+		.dest = ( struct sockaddr * ) &dest,
+		.netdev = pxe_netdev,
+	};
+	int rc;
+	struct s_PXENV_UDP_WRITE *pxenv_udp_write = pxe_udp.pxenv_udp_write;
+	size_t len;
+	struct io_buffer *iobuf;
+	userptr_t buffer;
+
+	DBG ( "UDP timer over %d\n", over);
+
+	if ( over || !pxenv_udp_write ) {
+		/* this generate a generic failure */
+		pxe_udp.rc = -ETIME;
+		return;
+	}
+
+	/* Construct destination socket address */
+	memset ( &dest, 0, sizeof ( dest ) );
+	dest.sin_family = AF_INET;
+	dest.sin_addr.s_addr = pxenv_udp_write->ip;
+	dest.sin_port = pxenv_udp_write->dst_port;
+
+	/* FIXME: we ignore the gateway specified, since we're
+	 * confident of being able to do our own routing.  We should
+	 * probably allow for multiple gateways.
+	 */
+
+	/* Allocate and fill data buffer */
+	len = pxenv_udp_write->buffer_size;
+	iobuf = xfer_alloc_iob ( &pxe_udp.xfer, len );
+	if ( ! iobuf ) {
+		DBG ( " out of memory\n" );
+		pxe_udp.rc = -ENOMEM;
+		return;
+	}
+	buffer = real_to_user ( pxenv_udp_write->buffer.segment,
+				pxenv_udp_write->buffer.offset );
+	copy_from_user ( iob_put ( iobuf, len ), buffer, 0, len );
+
+	DBG ( " %04x:%04x+%x %d->%s:%d\n", pxenv_udp_write->buffer.segment,
+	      pxenv_udp_write->buffer.offset, pxenv_udp_write->buffer_size,
+	      ntohs ( pxenv_udp_write->src_port ),
+	      inet_ntoa ( dest.sin_addr ),
+	      ntohs ( pxenv_udp_write->dst_port ) );
+
+	/* Otherwise, retransmit the packet */
+	rc = xfer_deliver ( &pxe_udp.xfer, iobuf, &meta );
+	if ( PXENV_STATUS(rc) == PXENV_STATUS_TFTP_FILE_NOT_FOUND ) {
+		start_timer ( timer );
+		return;
+	}
+
+	pxe_udp.rc = rc;
+}
+
 /**
  * UDP WRITE
  *
@@ -256,25 +322,11 @@ pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
  */
 static PXENV_EXIT_t
 pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
-	struct sockaddr_in dest;
-	struct xfer_metadata meta = {
-		.src = ( struct sockaddr * ) &pxe_udp.local,
-		.dest = ( struct sockaddr * ) &dest,
-		.netdev = pxe_netdev,
-	};
-	size_t len;
-	struct io_buffer *iobuf;
-	userptr_t buffer;
 	int rc;
+	struct retry_timer timer;
 
 	DBG ( "PXENV_UDP_WRITE" );
 
-	/* Construct destination socket address */
-	memset ( &dest, 0, sizeof ( dest ) );
-	dest.sin_family = AF_INET;
-	dest.sin_addr.s_addr = pxenv_udp_write->ip;
-	dest.sin_port = pxenv_udp_write->dst_port;
-
 	/* Set local (source) port.  PXE spec says source port is 2069
 	 * if not specified.  Really, this ought to be set at UDP open
 	 * time but hey, we didn't design this API.
@@ -283,33 +335,20 @@ pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
 	if ( ! pxe_udp.local.sin_port )
 		pxe_udp.local.sin_port = htons ( 2069 );
 
-	/* FIXME: we ignore the gateway specified, since we're
-	 * confident of being able to do our own routing.  We should
-	 * probably allow for multiple gateways.
-	 */
-
-	/* Allocate and fill data buffer */
-	len = pxenv_udp_write->buffer_size;
-	iobuf = xfer_alloc_iob ( &pxe_udp.xfer, len );
-	if ( ! iobuf ) {
-		DBG ( " out of memory\n" );
-		pxenv_udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES;
-		return PXENV_EXIT_FAILURE;
-	}
-	buffer = real_to_user ( pxenv_udp_write->buffer.segment,
-				pxenv_udp_write->buffer.offset );
-	copy_from_user ( iob_put ( iobuf, len ), buffer, 0, len );
+	memset(&timer, 0, sizeof(timer));
+	timer.expired = udp_write_expired;
+	pxe_udp.rc = -EINPROGRESS;
+	pxe_udp.pxenv_udp_write = pxenv_udp_write;
 
-	DBG ( " %04x:%04x+%x %d->%s:%d\n", pxenv_udp_write->buffer.segment,
-	      pxenv_udp_write->buffer.offset, pxenv_udp_write->buffer_size,
-	      ntohs ( pxenv_udp_write->src_port ),
-	      inet_ntoa ( dest.sin_addr ),
-	      ntohs ( pxenv_udp_write->dst_port ) );
-	
 	/* Transmit packet */
-	if ( ( rc = xfer_deliver ( &pxe_udp.xfer, iobuf, &meta ) ) != 0 ) {
-		DBG ( "PXENV_UDP_WRITE could not transmit: %s\n",
-		      strerror ( rc ) );
+	start_timer_nodelay ( &timer );
+
+	while ( ( rc = pxe_udp.rc ) == -EINPROGRESS )
+		step();
+
+	pxe_udp.pxenv_udp_write = NULL;
+
+	if ( rc != 0) {
 		pxenv_udp_write->Status = PXENV_STATUS ( rc );
 		return PXENV_EXIT_FAILURE;
 	}
-- 
1.7.5.4


On Tue, 2012-02-21 at 17:44 +0000, Frediano Ziglio wrote:
> On Wed, 2012-02-15 at 23:29 +0000, Michael Brown wrote:
> > On Wednesday 15 Feb 2012 16:34:40 Simon Rowe wrote:
> > > On Sunday 12 February 2012 13:38:43 Michael Brown wrote:
> > > > PXE will never block on PXENV_UDP_WRITE.  As you describe, an ARP request
> > > > will be sent instead of the UDP packet.  Since UDP is an unreliable
> > > > protocol,  the caller must be prepared to retransmit the UDP packet, at
> > > > which point hopefully the ARP response will have been received and the
> > > > UDP packet can be sent.
> > > 
> > > Is returning AX=0 from PXENV_UDP_WRITE the correct action or should some
> > > indication be given to the caller that the UDP packet was discarded?
> > 
> > Probably the latter.  It looks as though the error gets hidden in 
> > udp_xfer_deliver().  Could you try the attached (untested) patch and see if it 
> > does what you expect?
> > 
> > Thanks,
> > 
> > Michael
> 
> Hi Michael,
>   patch propagate error correctly. I don't know if
> PXENV_STATUS_TFTP_FILE_NOT_FOUND (0x3B) is the right error to expect,
> specification define only PXENV_STATUS_ARP_TIMEOUT and
> PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS errors for ARP.
> 
> Note also that if you call UDP_WRITE without UDP_OPEN ipxe returns
> success and does not send any packet.
> 
> Regards
>   Frediano
> 
> _______________________________________________
> ipxe-devel mailing list
> ipxe-devel at lists.ipxe.org
> https://lists.ipxe.org/mailman/listinfo/ipxe-devel



More information about the ipxe-devel mailing list