TFTP upgraded to use a core function library (in tftpcore.c) which will be
authorMichael Brown <mcb30@etherboot.org>
Wed, 1 Jun 2005 13:13:05 +0000 (13:13 +0000)
committerMichael Brown <mcb30@etherboot.org>
Wed, 1 Jun 2005 13:13:05 +0000 (13:13 +0000)
shared between TFTP, TFTM and MTFTP protocols.

src/include/etherboot.h
src/include/pxe.h
src/include/tftp.h
src/interface/pxe/pxe_tftp.c
src/proto/tcp.c
src/proto/tftm.c
src/proto/tftp.c
src/proto/tftpcore.c

index 9d36428..669ee8b 100644 (file)
@@ -154,7 +154,6 @@ enum {
 #include       "udp.h"
 #include       "tcp.h"
 #include       "bootp.h"
-#include       "tftp.h"
 #include       "igmp.h"
 #include       "nfs.h"
 #include       "console.h"
index 3264df0..f8e2de7 100644 (file)
@@ -4,6 +4,7 @@
 #include "pxe_types.h"
 #include "pxe_api.h"
 #include "etherboot.h"
+#include "tftp.h"
 
 /* Union used for PXE API calls; we don't know the type of the
  * structure until we interpret the opcode.  Also, Status is available
@@ -88,7 +89,7 @@ typedef struct pxe_stack {
                        uint32_t magic_cookie;
                        unsigned int len;
                        int eof;
-                       char data[TFTP_MAX_PACKET];
+                       char data[TFTP_MAX_BLKSIZE];
                } tftpdata;
                struct {
                        char *buffer;
index 7019206..22329e5 100644 (file)
@@ -1,13 +1,17 @@
 #ifndef        TFTP_H
 #define        TFTP_H
 
+/** @file */
+
 #include "in.h"
 #include "buffer.h"
 #include "nic.h"
+#include "ip.h"
+#include "udp.h"
 
-#define TFTP_PORT      69
-#define        TFTP_DEFAULTSIZE_PACKET 512
-#define        TFTP_MAX_PACKET         1432 /* 512 */
+#define TFTP_PORT      69              /**< Default TFTP server port */
+#define        TFTP_DEFAULT_BLKSIZE    512
+#define        TFTP_MAX_BLKSIZE                1432 /* 512 */
 
 #define TFTP_RRQ       1
 #define TFTP_WRQ       2
 #define TFTP_ERROR     5
 #define TFTP_OACK      6
 
-#define TFTP_CODE_EOF  1
-#define TFTP_CODE_MORE 2
-#define TFTP_CODE_ERROR        3
-#define TFTP_CODE_BOOT 4
-#define TFTP_CODE_CFG  5
+#define TFTP_ERR_FILE_NOT_FOUND        1 /**< File not found */
+#define TFTP_ERR_ACCESS_DENIED 2 /**< Access violation */
+#define TFTP_ERR_DISK_FULL     3 /**< Disk full or allocation exceeded */
+#define TFTP_ERR_ILLEGAL_OP    4 /**< Illegal TFTP operation */
+#define TFTP_ERR_UNKNOWN_TID   5 /**< Unknown transfer ID */
+#define TFTP_ERR_FILE_EXISTS   6 /**< File already exists */
+#define TFTP_ERR_UNKNOWN_USER  7 /**< No such user */
+#define TFTP_ERR_BAD_OPTS      8 /**< Option negotiation failed */
 
-struct tftp_t {
+/** A TFTP request (RRQ) packet */
+struct tftp_rrq {
+       struct iphdr ip;
+       struct udphdr udp;
+       uint16_t opcode;
+       char data[TFTP_DEFAULT_BLKSIZE];
+} PACKED;
+
+/** A TFTP data (DATA) packet */
+struct tftp_data {
+       struct iphdr ip;
+       struct udphdr udp;
+       uint16_t opcode;
+       uint16_t block;
+       uint8_t data[TFTP_MAX_BLKSIZE];
+} PACKED;
+/** A TFTP acknowledgement (ACK) packet */
+struct tftp_ack {
        struct iphdr ip;
        struct udphdr udp;
        uint16_t opcode;
-       union {
-               uint8_t rrq[TFTP_DEFAULTSIZE_PACKET];
-               struct {
-                       uint16_t block;
-                       uint8_t  download[TFTP_MAX_PACKET];
-               } data;
-               struct {
-                       uint16_t block;
-               } ack;
-               struct {
-                       uint16_t errcode;
-                       uint8_t  errmsg[TFTP_DEFAULTSIZE_PACKET];
-               } err;
-               struct {
-                       uint8_t  data[TFTP_DEFAULTSIZE_PACKET+2];
-               } oack;
-       } u;
+       uint16_t block;
 } PACKED;
 
-/* define a smaller tftp packet solely for making requests to conserve stack
-   512 bytes should be enough */
-struct tftpreq_t {
+/** A TFTP error (ERROR) packet */
+struct tftp_error {
        struct iphdr ip;
        struct udphdr udp;
        uint16_t opcode;
-       union {
-               uint8_t rrq[512];
-               struct {
-                       uint16_t block;
-               } ack;
-               struct {
-                       uint16_t errcode;
-                       uint8_t  errmsg[512-2];
-               } err;
-       } u;
+       uint16_t errcode;
+       char errmsg[TFTP_DEFAULT_BLKSIZE];
 } PACKED;
 
+/** A TFTP options acknowledgement (OACK) packet */
+struct tftp_oack {
+       struct iphdr ip;
+       struct udphdr udp;
+       uint16_t opcode;
+       uint8_t data[TFTP_DEFAULT_BLKSIZE];
+} PACKED;
+
+/** The common header of all TFTP packets */
+struct tftp_common {
+       struct iphdr ip;
+       struct udphdr udp;
+       uint16_t opcode;
+} PACKED;
+
+/** A union encapsulating all TFTP packet types */
+union tftp_any {
+       struct tftp_common      common;
+       struct tftp_rrq         rrq;
+       struct tftp_data        data;
+       struct tftp_ack         ack;
+       struct tftp_error       error;
+       struct tftp_oack        oack;
+};     
+
+/**
+ * TFTP state
+ *
+ * This data structure holds the state for an ongoing TFTP transfer.
+ */
+struct tftp_state {
+       /** TFTP server address
+        *
+        * This is the IP address and UDP port from which data packets
+        * will be sent, and to which ACK packets should be sent.
+        */
+       struct sockaddr_in server;
+       /** TFTP client address
+        *
+        * The IP address, if any, is the multicast address to which
+        * data packets will be sent.  The client will always send
+        * packets from its own IP address.
+        *
+        * The UDP port is the port from which the open request will
+        * be sent, and to which data packets will be sent.  (Due to
+        * the "design" of the MTFTP protocol, the master client will
+        * receive its first data packet as unicast, and subsequent
+        * packets as multicast.)
+        */
+       struct sockaddr_in client;
+       /** Master client
+        *
+        * This will be true if the client is the master client for a
+        * multicast protocol (i.e. MTFTP or TFTM).  (It will always
+        * be true for a non-multicast protocol, i.e. plain old TFTP).
+        */
+       int master;
+       /** Data block size
+        *
+        * This is the "blksize" option negotiated with the TFTP
+        * server.  (If the TFTP server does not support TFTP options,
+        * this will default to 512).
+        */
+       unsigned int blksize;
+       /** File size
+        *
+        * This is the value returned in the "tsize" option from the
+        * TFTP server.  If the TFTP server does not support the
+        * "tsize" option, this value will be zero.
+        */
+       off_t tsize;
+       /** Last received block
+        *
+        * The block number of the most recent block received from the
+        * TFTP server.  Note that the first data block is block 1; a
+        * value of 0 indicates that no data blocks have yet been
+        * received.
+        */
+       unsigned int block;
+};
+
+
+
 struct tftpreq_info_t {
        struct sockaddr_in *server;
        const char *name;
index 1faaf25..2d824e1 100644 (file)
@@ -131,7 +131,7 @@ PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) {
        request.blksize = tftp_open->PacketSize;
        DBG ( " %@:%d/%s (%d)", tftp_open->ServerIPAddress,
              tftp_open->TFTPPort, request.name, request.blksize );
-       if ( !request.blksize ) request.blksize = TFTP_DEFAULTSIZE_PACKET;
+       if ( !request.blksize ) request.blksize = TFTP_DEFAULT_BLKSIZE;
        /* Make request and get first packet */
        if ( !tftp_block ( &request, &block ) ) {
                tftp_open->Status = PXENV_STATUS_TFTP_FILE_NOT_FOUND;
index 197bfce..1e0531d 100644 (file)
@@ -1,7 +1,7 @@
 #include "etherboot.h"
 #include "ip.h"
 #include "tcp.h"
-
+#include "nic.h"
 
 void build_tcp_hdr(unsigned long destip, unsigned int srcsock,
                  unsigned int destsock, long send_seq, long recv_seq,
index 426d0dd..6dbf1af 100644 (file)
@@ -1,3 +1,5 @@
+#if 0
+
 /**************************************************************************
 *
 *    proto_tftm.c -- Etherboot Multicast TFTP 
@@ -481,3 +483,5 @@ static struct protocol tftm_protocol __protocol = {
        .default_port = TFTM_PORT,
        .load = url_tftm,
 };
+
+#endif
index b154f57..e5bf5a8 100644 (file)
 #include "etherboot.h"
-#include "in.h"
-#include "nic.h"
 #include "proto.h"
+#include "errno.h"
 #include "tftp.h"
+#include "tftpcore.h"
 
-/* Utility function for tftp_block() */
-static int await_tftp ( int ival, void *ptr __unused,
-                       unsigned short ptype __unused, struct iphdr *ip,
-                       struct udphdr *udp, struct tcphdr *tcp __unused ) {
-       if ( ! udp ) {
-               return 0;
-       }
-       if ( arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr )
-               return 0;
-       if ( ntohs ( udp->dest ) != ival )
-               return 0;
-       return 1;
-}
+/** @file
+ *
+ * TFTP protocol
+ */
 
-/*
- * Download a single block via TFTP.  This function is non-static so
- * that pxe_export.c can call it.
+/**
+ * Process a TFTP block
  *
  */
-int tftp_block ( struct tftpreq_info_t *request,
-                struct tftpblk_info_t *block ) {
-       static struct sockaddr_in server;
-       static unsigned short lport = 2000; /* local port */
-       struct tftp_t *rcvd = NULL;
-       static struct tftpreq_t xmit;
-       static unsigned short xmitlen = 0;
-       static unsigned short blockidx = 0; /* Last block received */
-       static unsigned short retry = 0; /* Retry attempts on last block */
-       static int blksize = 0;
-       unsigned short recvlen = 0;
+static inline int process_tftp_data ( struct tftp_state *state,
+                                     struct tftp_data *data,
+                                     struct buffer *buffer,
+                                     int *eof ) {
+       unsigned int blksize;
 
-       /* If this is a new request (i.e. if name is set), fill in
-        * transmit block with RRQ and send it.
-        */
-       if ( request ) {
-               rx_qdrain(); /* Flush receive queue */
-               xmit.opcode = htons(TFTP_RRQ);
-               xmitlen = (void*)&xmit.u.rrq - (void*)&xmit +
-                       sprintf((char*)xmit.u.rrq, "%s%coctet%cblksize%c%d",
-                               request->name, 0, 0, 0, request->blksize)
-                       + 1; /* null terminator */
-               blockidx = 0; /* Reset counters */
-               retry = 0;
-               blksize = TFTP_DEFAULTSIZE_PACKET;
-               lport++; /* Use new local port */
-               server = *(request->server);
-               if ( !udp_transmit(server.sin_addr.s_addr, lport,
-                                  server.sin_port, xmitlen, &xmit) )
-                       return (0);
+       /* Check it's the correct DATA block */
+       if ( ntohs ( data->block ) != ( state->block + 1 ) ) {
+               DBG ( "TFTP: got block %d, wanted block %d\n",
+                     ntohs ( data->block ), state->block + 1 );
+               return 1;
        }
-       /* Exit if no transfer in progress */
-       if ( !blksize ) return (0);
-       /* Loop to wait until we get a packet we're interested in */
-       block->data = NULL; /* Used as flag */
-       while ( block->data == NULL ) {
-               long timeout = rfc2131_sleep_interval ( blockidx ? TFTP_REXMT :
-                                                       TIMEOUT, retry );
-               if ( !await_reply(await_tftp, lport, NULL, timeout) ) {
-                       /* No packet received */
-                       if ( retry++ > MAX_TFTP_RETRIES ) break;
-                       /* Retransmit last packet */
-                       if ( !blockidx ) lport++; /* New lport if new RRQ */
-                       if ( !udp_transmit(server.sin_addr.s_addr, lport,
-                                          server.sin_port, xmitlen, &xmit) )
-                               return (0);
-                       continue; /* Back to waiting for packet */
-               }
-               /* Packet has been received */
-               rcvd = (struct tftp_t *)&nic.packet[ETH_HLEN];
-               recvlen = ntohs(rcvd->udp.len) - sizeof(struct udphdr)
-                       - sizeof(rcvd->opcode);
-               server.sin_port = ntohs(rcvd->udp.src);
-               retry = 0; /* Reset retry counter */
-               switch ( htons(rcvd->opcode) ) {
-               case TFTP_ERROR : {
-                       printf ( "TFTP error %d (%s)\n",
-                                ntohs(rcvd->u.err.errcode),
-                                rcvd->u.err.errmsg );
-                       return (0); /* abort */
-               }
-               case TFTP_OACK : {
-                       const char *p = rcvd->u.oack.data;
-                       const char *e = p + recvlen - 10; /* "blksize\0\d\0" */
-
-                       *((char*)(p+recvlen-1)) = '\0'; /* Force final 0 */
-                       if ( blockidx || !request ) break; /* Too late */
-                       if ( recvlen <= TFTP_MAX_PACKET ) /* sanity */ {
-                               /* Check for blksize option honoured */
-                               while ( p < e ) {
-                                       if ( strcasecmp("blksize",p) == 0 &&
-                                            p[7] == '\0' ) {
-                                               blksize = strtoul(p+8,&p,10);
-                                               p++; /* skip null */
-                                       }
-                                       while ( *(p++) ) {};
-                               }
-                       }
-                       if ( blksize < TFTP_DEFAULTSIZE_PACKET ||
-                            blksize > request->blksize ) {
-                               /* Incorrect blksize - error and abort */
-                               xmit.opcode = htons(TFTP_ERROR);
-                               xmit.u.err.errcode = 8;
-                               xmitlen = (void*)&xmit.u.err.errmsg
-                                       - (void*)&xmit
-                                       + sprintf((char*)xmit.u.err.errmsg,
-                                                 "RFC1782 error")
-                                       + 1;
-                               udp_transmit(server.sin_addr.s_addr, lport,
-                                            server.sin_port, xmitlen, &xmit);
-                               return (0);
-                       }
-               } break;
-               case TFTP_DATA :
-                       if ( ntohs(rcvd->u.data.block) != ( blockidx + 1 ) )
-                               break; /* Re-ACK last block sent */
-                       if ( recvlen > ( blksize+sizeof(rcvd->u.data.block) ) )
-                               break; /* Too large; ignore */
-                       block->data = rcvd->u.data.download;
-                       block->block = ++blockidx;
-                       block->len = recvlen - sizeof(rcvd->u.data.block);
-                       block->eof = ( (unsigned short)block->len < blksize );
-                       /* If EOF, zero blksize to indicate transfer done */
-                       if ( block->eof ) blksize = 0;
-                       break;
-               default: break; /* Do nothing */
-               }
-               /* Send ACK */
-               xmit.opcode = htons(TFTP_ACK);
-               xmit.u.ack.block = htons(blockidx);
-               xmitlen = TFTP_MIN_PACKET;
-               udp_transmit ( server.sin_addr.s_addr, lport, server.sin_port,
-                              xmitlen, &xmit );
+       /* Check it's an acceptable size */
+       blksize = ( ntohs ( data->udp.len )
+                   + offsetof ( typeof ( *data ), udp )
+                   - offsetof ( typeof ( *data ), data ) );
+       if ( blksize > state->blksize ) {
+               DBG ( "TFTP: oversized block size %d (max %d)\n",
+                     blksize, state->blksize );
+               return 1;
        }
-       return ( block->data ? 1 : 0 );
+       /* Place block in the buffer */
+       if ( ! fill_buffer ( buffer, data->data, state->block * state->blksize,
+                            blksize ) ) {
+               DBG ( "TFTP: could not place data in buffer: %m\n" );
+               return 0;
+       }
+       /* Increment block counter */
+       state->block++;
+       /* Set EOF marker */
+       *eof = ( blksize < state->blksize );
+       return 1;
 }
 
-/*
+/**
  * Download a file via TFTP
  *
  */
 int tftp ( char *url __unused, struct sockaddr_in *server, char *file,
           struct buffer *buffer ) {
-       struct tftpreq_info_t request_data = {
-               .server = server,
-               .name = file,
-               .blksize = TFTP_MAX_PACKET,
-       };
-       struct tftpreq_info_t *request = &request_data;
-       struct tftpblk_info_t block;
-       off_t offset = 0;
+       struct tftp_state state;
+       union tftp_any *reply;
+       int eof = 0;
+
+       /* Initialise TFTP state */
+       memset ( &state, 0, sizeof ( state ) );
+       state.server = *server;
+       
+       /* Open the file */
+       if ( ! tftp_open ( &state, file, &reply ) ) {
+               DBG ( "TFTP: could not open %@:%d/%s : %m\n",
+                     server->sin_addr.s_addr, server->sin_port, file );
+               return 0;
+       }
+       
+       /* Process OACK, if any */
+       if ( ntohs ( reply->common.opcode ) == TFTP_OACK ) {
+               if ( ! tftp_process_opts ( &state, &reply->oack ) ) {
+                       DBG ( "TFTP: option processing failed : %m\n" );
+                       return 0;
+               }
+               reply = NULL;
+       }
 
+       /* Fetch file, a block at a time */
        do {
-               if ( ! tftp_block ( request, &block ) )
+               /* Get next block to process.  (On the first time
+                * through, we may already have a block from
+                * tftp_open()).
+                */
+               if ( ! reply ) {
+                       if ( ! tftp_ack ( &state, &reply ) ) {
+                               DBG ( "TFTP: could not get next block: %m\n" );
+                               return 0;
+                       }
+               }
+               twiddle();
+               /* Check it's a DATA block */
+               if ( ntohs ( reply->common.opcode ) != TFTP_DATA ) {
+                       DBG ( "TFTP: unexpected opcode %d\n",
+                             ntohs ( reply->common.opcode ) );
+                       errno = PXENV_STATUS_TFTP_UNKNOWN_OPCODE;
                        return 0;
-               if ( ! fill_buffer ( buffer, block.data, offset, block.len ) )
+               }
+               /* Process the DATA block */
+               if ( ! process_tftp_data ( &state, &reply->data, buffer,
+                                          &eof ) )
                        return 0;
-               twiddle();
-               offset += block.len;
-               request = NULL; /* Send request only once */
-       } while ( ! block.eof );
+               reply = NULL;
+       } while ( ! eof );
+
+       /* ACK the final packet, as a courtesy to the server */
+       tftp_ack_nowait ( &state );
 
        return 1;
 }
index 51ad8b4..491bab6 100644 (file)
@@ -47,21 +47,32 @@ int await_tftp ( int ival __unused, void *ptr, unsigned short ptype __unused,
 
        /* Must have valid UDP (and, therefore, also IP) headers */
        if ( ! udp ) {
+               DBG2 ( "TFTPCORE: not UDP\n" );
                return 0;
        }
        /* Packet must come from the TFTP server */
-       if ( ip->src.s_addr != state->server.sin_addr.s_addr )
+       if ( ip->src.s_addr != state->server.sin_addr.s_addr ) {
+               DBG2 ( "TFTPCORE: from %@, not from TFTP server %@\n",
+                      ip->src.s_addr, state->server.sin_addr.s_addr );
                return 0;
+       }
        /* Packet must be addressed to the correct UDP port */
-       if ( ntohs ( udp->dest ) != state->client.sin_port )
+       if ( ntohs ( udp->dest ) != state->client.sin_port ) {
+               DBG2 ( "TFTPCORE: to UDP port %d, not to TFTP port %d\n",
+                      ntohs ( udp->dest ), state->client.sin_port );
                return 0;
+       }
        /* Packet must be addressed to us, or to our multicast
         * listening address (if we have one).
         */
        if ( ! ( ( ip->dest.s_addr == arptable[ARP_CLIENT].ipaddr.s_addr ) ||
                 ( ( state->client.sin_addr.s_addr ) && 
-                  ( ip->dest.s_addr == state->client.sin_addr.s_addr ) ) ) )
+                  ( ip->dest.s_addr == state->client.sin_addr.s_addr ) ) ) ) {
+               DBG2 ( "TFTPCORE: to %@, not to %@ (or %@)\n",
+                      ip->dest.s_addr, arptable[ARP_CLIENT].ipaddr.s_addr,
+                      state->client.sin_addr.s_addr );
                return 0;
+       }
        return 1;
 }
 
@@ -164,7 +175,7 @@ int tftp_open ( struct tftp_state *state, const char *filename,
                state->server.sin_port = TFTP_PORT;
 
        /* Determine whether or not to use lport */
-       fixed_lport = state->server.sin_port;
+       fixed_lport = state->client.sin_port;
 
        /* Set up RRQ */
        rrq.opcode = htons ( TFTP_RRQ );
@@ -202,7 +213,11 @@ int tftp_open ( struct tftp_state *state, const char *filename,
                if ( await_reply ( await_tftp, 0, state, timeout ) ) {
                        *reply = ( union tftp_any * ) &nic.packet[ETH_HLEN];
                        state->server.sin_port =
-                               ntohs ( (*reply)->common.udp.dest );
+                               ntohs ( (*reply)->common.udp.src );
+                       DBG ( "TFTPCORE: got reply from %@:%d (type %d)\n",
+                             state->server.sin_addr.s_addr,
+                             state->server.sin_port,
+                             ntohs ( (*reply)->common.opcode ) );
                        if ( ntohs ( (*reply)->common.opcode ) == TFTP_ERROR ){
                                tftp_set_errno ( &(*reply)->error );
                                return 0;
@@ -211,6 +226,7 @@ int tftp_open ( struct tftp_state *state, const char *filename,
                }
        }
 
+       DBG ( "TFTPCORE: open request timed out\n" );
        errno = PXENV_STATUS_TFTP_OPEN_TIMEOUT;
        return 0;
 }
@@ -250,6 +266,8 @@ int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
        const char *p;
        const char *end;
 
+       DBG ( "TFTPCORE: processing OACK\n" );
+
        /* End of options */
        end = ( ( char * ) &oack->udp ) + ntohs ( oack->udp.len );
 
@@ -266,6 +284,7 @@ int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
                                return 0;
                        }
                        p++;
+                       DBG ( "TFTPCORE: got blksize %d\n", state->blksize );
                } else if ( strcasecmp ( "tsize", p ) == 0 ) {
                        p += 6;
                        state->tsize = strtoul ( p, &p, 10 );
@@ -275,6 +294,7 @@ int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
                                return 0;
                        }
                        p++;
+                       DBG ( "TFTPCORE: got tsize %d\n", state->tsize );
                } else if ( strcasecmp ( "multicast", p ) == 0 ) {
                        char *e = strchr ( p, ',' );
                        if ( ( ! e ) || ( e >= end ) ) {
@@ -317,7 +337,12 @@ int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
                                return 0;
                        }
                        p++;
+                       DBG ( "TFTPCORE: got multicast %@:%d (%s)\n",
+                             state->client.sin_addr.s_addr,
+                             state->client.sin_port,
+                             ( state->master ? "master" : "not master" ) );
                } else {
+                       DBG ( "TFTPCORE: unknown option \"%s\"\n", p );
                        p += strlen ( p ) + 1; /* skip option name */
                        p += strlen ( p ) + 1; /* skip option value */
                }
@@ -351,6 +376,7 @@ int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
 int tftp_ack_nowait ( struct tftp_state *state ) {
        struct tftp_ack ack;
 
+       DBG ( "TFTPCORE: acknowledging data block %d\n", state->block );
        ack.opcode = htons ( TFTP_ACK );
        ack.block = htons ( state->block );
        return udp_transmit ( state->server.sin_addr.s_addr,
@@ -396,9 +422,11 @@ int tftp_ack ( struct tftp_state *state, union tftp_any **reply ) {
                        DBG ( "TFTP: could not send ACK: %m\n" );
                        return 0;
                }       
-               if ( await_reply ( await_tftp, 0, &state, timeout ) ) {
+               if ( await_reply ( await_tftp, 0, state, timeout ) ) {
                        /* We received a reply */
                        *reply = ( union tftp_any * ) &nic.packet[ETH_HLEN];
+                       DBG ( "TFTPCORE: got reply (type %d)\n",
+                             ntohs ( (*reply)->common.opcode ) );
                        if ( ntohs ( (*reply)->common.opcode ) == TFTP_ERROR ){
                                tftp_set_errno ( &(*reply)->error );
                                return 0;
@@ -406,7 +434,7 @@ int tftp_ack ( struct tftp_state *state, union tftp_any **reply ) {
                        return 1;
                }
        }
-       DBG ( "TFTP: ACK retries exceeded\n" );
+       DBG ( "TFTP: timed out during read\n" );
        errno = PXENV_STATUS_TFTP_READ_TIMEOUT;
        return 0;
 }