[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