iPXE
pxe_tftp.c
Go to the documentation of this file.
00001 /** @file
00002  *
00003  * PXE TFTP API
00004  *
00005  */
00006 
00007 /*
00008  * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
00009  *
00010  * This program is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU General Public License as
00012  * published by the Free Software Foundation; either version 2 of the
00013  * License, or any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00023  * 02110-1301, USA.
00024  *
00025  * You can also choose to distribute this program under the terms of
00026  * the Unmodified Binary Distribution Licence (as given in the file
00027  * COPYING.UBDL), provided that you have satisfied its requirements.
00028  */
00029 
00030 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00031 
00032 #include <stdlib.h>
00033 #include <stdio.h>
00034 #include <errno.h>
00035 #include <byteswap.h>
00036 #include <ipxe/uaccess.h>
00037 #include <ipxe/in.h>
00038 #include <ipxe/tftp.h>
00039 #include <ipxe/iobuf.h>
00040 #include <ipxe/xfer.h>
00041 #include <ipxe/open.h>
00042 #include <ipxe/process.h>
00043 #include <ipxe/uri.h>
00044 #include <realmode.h>
00045 #include <pxe.h>
00046 
00047 /** A PXE TFTP connection */
00048 struct pxe_tftp_connection {
00049         /** Data transfer interface */
00050         struct interface xfer;
00051         /** Data buffer */
00052         userptr_t buffer;
00053         /** Size of data buffer */
00054         size_t size;
00055         /** Starting offset of data buffer */
00056         size_t start;
00057         /** File position */
00058         size_t offset;
00059         /** Maximum file position */
00060         size_t max_offset;
00061         /** Block size */
00062         size_t blksize;
00063         /** Block index */
00064         unsigned int blkidx;
00065         /** Overall return status code */
00066         int rc;
00067 };
00068 
00069 /**
00070  * Close PXE TFTP connection
00071  *
00072  * @v pxe_tftp          PXE TFTP connection
00073  * @v rc                Final status code
00074  */
00075 static void pxe_tftp_close ( struct pxe_tftp_connection *pxe_tftp, int rc ) {
00076         intf_shutdown ( &pxe_tftp->xfer, rc );
00077         pxe_tftp->rc = rc;
00078 }
00079 
00080 /**
00081  * Check flow control window
00082  *
00083  * @v pxe_tftp          PXE TFTP connection
00084  * @ret len             Length of window
00085  */
00086 static size_t pxe_tftp_xfer_window ( struct pxe_tftp_connection *pxe_tftp ) {
00087 
00088         return pxe_tftp->blksize;
00089 }
00090 
00091 /**
00092  * Receive new data
00093  *
00094  * @v pxe_tftp          PXE TFTP connection
00095  * @v iobuf             I/O buffer
00096  * @v meta              Transfer metadata
00097  * @ret rc              Return status code
00098  */
00099 static int pxe_tftp_xfer_deliver ( struct pxe_tftp_connection *pxe_tftp,
00100                                    struct io_buffer *iobuf,
00101                                    struct xfer_metadata *meta ) {
00102         size_t len = iob_len ( iobuf );
00103         int rc = 0;
00104 
00105         /* Calculate new buffer position */
00106         if ( meta->flags & XFER_FL_ABS_OFFSET )
00107                 pxe_tftp->offset = 0;
00108         pxe_tftp->offset += meta->offset;
00109 
00110         /* Copy data block to buffer */
00111         if ( len == 0 ) {
00112                 /* No data (pure seek); treat as success */
00113         } else if ( pxe_tftp->offset < pxe_tftp->start ) {
00114                 DBG ( " buffer underrun at %zx (min %zx)",
00115                       pxe_tftp->offset, pxe_tftp->start );
00116                 rc = -ENOBUFS;
00117         } else if ( ( pxe_tftp->offset + len ) >
00118                     ( pxe_tftp->start + pxe_tftp->size ) ) {
00119                 DBG ( " buffer overrun at %zx (max %zx)",
00120                       ( pxe_tftp->offset + len ),
00121                       ( pxe_tftp->start + pxe_tftp->size ) );
00122                 rc = -ENOBUFS;
00123         } else {
00124                 copy_to_user ( pxe_tftp->buffer,
00125                                ( pxe_tftp->offset - pxe_tftp->start ),
00126                                iobuf->data, len );
00127         }
00128 
00129         /* Calculate new buffer position */
00130         pxe_tftp->offset += len;
00131 
00132         /* Record maximum offset as the file size */
00133         if ( pxe_tftp->max_offset < pxe_tftp->offset )
00134                 pxe_tftp->max_offset = pxe_tftp->offset;
00135 
00136         /* Terminate transfer on error */
00137         if ( rc != 0 )
00138                 pxe_tftp_close ( pxe_tftp, rc );
00139 
00140         free_iob ( iobuf );
00141         return rc;
00142 }
00143 
00144 /** PXE TFTP connection interface operations */
00145 static struct interface_operation pxe_tftp_xfer_ops[] = {
00146         INTF_OP ( xfer_deliver, struct pxe_tftp_connection *,
00147                   pxe_tftp_xfer_deliver ),
00148         INTF_OP ( xfer_window, struct pxe_tftp_connection *,
00149                   pxe_tftp_xfer_window ),
00150         INTF_OP ( intf_close, struct pxe_tftp_connection *, pxe_tftp_close ),
00151 };
00152 
00153 /** PXE TFTP connection interface descriptor */
00154 static struct interface_descriptor pxe_tftp_xfer_desc =
00155         INTF_DESC ( struct pxe_tftp_connection, xfer, pxe_tftp_xfer_ops );
00156 
00157 /** The PXE TFTP connection */
00158 static struct pxe_tftp_connection pxe_tftp = {
00159         .xfer = INTF_INIT ( pxe_tftp_xfer_desc ),
00160 };
00161 
00162 /**
00163  * Open PXE TFTP connection
00164  *
00165  * @v ipaddress         IP address
00166  * @v port              TFTP server port (in network byte order)
00167  * @v filename          File name
00168  * @v blksize           Requested block size
00169  * @ret rc              Return status code
00170  */
00171 static int pxe_tftp_open ( IP4_t ipaddress, UDP_PORT_t port,
00172                            UINT8_t *filename, UINT16_t blksize ) {
00173         union {
00174                 struct sockaddr sa;
00175                 struct sockaddr_in sin;
00176         } server;
00177         struct uri *uri;
00178         int rc;
00179 
00180         /* Reset PXE TFTP connection structure */
00181         memset ( &pxe_tftp, 0, sizeof ( pxe_tftp ) );
00182         intf_init ( &pxe_tftp.xfer, &pxe_tftp_xfer_desc, NULL );
00183         if ( blksize < TFTP_DEFAULT_BLKSIZE )
00184                 blksize = TFTP_DEFAULT_BLKSIZE;
00185         pxe_tftp.blksize = blksize;
00186         pxe_tftp.rc = -EINPROGRESS;
00187 
00188         /* Construct URI */
00189         memset ( &server, 0, sizeof ( server ) );
00190         server.sin.sin_family = AF_INET;
00191         server.sin.sin_addr.s_addr = ipaddress;
00192         server.sin.sin_port = port;
00193         DBG ( " %s", sock_ntoa ( &server.sa ) );
00194         if ( port )
00195                 DBG ( ":%d", ntohs ( port ) );
00196         DBG ( ":%s", filename );
00197         uri = pxe_uri ( &server.sa, ( ( char * ) filename ) );
00198         if ( ! uri ) {
00199                 DBG ( " could not create URI\n" );
00200                 return -ENOMEM;
00201         }
00202 
00203         /* Open PXE TFTP connection */
00204         if ( ( rc = xfer_open_uri ( &pxe_tftp.xfer, uri ) ) != 0 ) {
00205                 DBG ( " could not open (%s)\n", strerror ( rc ) );
00206                 return rc;
00207         }
00208 
00209         return 0;
00210 }
00211 
00212 /**
00213  * TFTP OPEN
00214  *
00215  * @v tftp_open                         Pointer to a struct s_PXENV_TFTP_OPEN
00216  * @v s_PXENV_TFTP_OPEN::ServerIPAddress TFTP server IP address
00217  * @v s_PXENV_TFTP_OPEN::GatewayIPAddress Relay agent IP address, or 0.0.0.0
00218  * @v s_PXENV_TFTP_OPEN::FileName       Name of file to open
00219  * @v s_PXENV_TFTP_OPEN::TFTPPort       TFTP server UDP port
00220  * @v s_PXENV_TFTP_OPEN::PacketSize     TFTP blksize option to request
00221  * @ret #PXENV_EXIT_SUCCESS             File was opened
00222  * @ret #PXENV_EXIT_FAILURE             File was not opened
00223  * @ret s_PXENV_TFTP_OPEN::Status       PXE status code
00224  * @ret s_PXENV_TFTP_OPEN::PacketSize   Negotiated blksize
00225  * @err #PXENV_STATUS_TFTP_INVALID_PACKET_SIZE Requested blksize too small
00226  *
00227  * Opens a TFTP connection for downloading a file a block at a time
00228  * using pxenv_tftp_read().
00229  *
00230  * If s_PXENV_TFTP_OPEN::GatewayIPAddress is 0.0.0.0, normal IP
00231  * routing will take place.  See the relevant
00232  * @ref pxe_routing "implementation note" for more details.
00233  *
00234  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
00235  * value before calling this function in protected mode.  You cannot
00236  * call this function with a 32-bit stack segment.  (See the relevant
00237  * @ref pxe_x86_pmode16 "implementation note" for more details.)
00238  * 
00239  * @note According to the PXE specification version 2.1, this call
00240  * "opens a file for reading/writing", though how writing is to be
00241  * achieved without the existence of an API call %pxenv_tftp_write()
00242  * is not made clear.
00243  *
00244  * @note Despite the existence of the numerous statements within the
00245  * PXE specification of the form "...if a TFTP/MTFTP or UDP connection
00246  * is active...", you cannot use pxenv_tftp_open() and
00247  * pxenv_tftp_read() to read a file via MTFTP; only via plain old
00248  * TFTP.  If you want to use MTFTP, use pxenv_tftp_read_file()
00249  * instead.  Astute readers will note that, since
00250  * pxenv_tftp_read_file() is an atomic operation from the point of
00251  * view of the PXE API, it is conceptually impossible to issue any
00252  * other PXE API call "if an MTFTP connection is active".
00253  */
00254 static PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) {
00255         int rc;
00256 
00257         DBG ( "PXENV_TFTP_OPEN" );
00258 
00259         /* Guard against callers that fail to close before re-opening */
00260         pxe_tftp_close ( &pxe_tftp, 0 );
00261 
00262         /* Open connection */
00263         if ( ( rc = pxe_tftp_open ( tftp_open->ServerIPAddress,
00264                                     tftp_open->TFTPPort,
00265                                     tftp_open->FileName,
00266                                     tftp_open->PacketSize ) ) != 0 ) {
00267                 tftp_open->Status = PXENV_STATUS ( rc );
00268                 return PXENV_EXIT_FAILURE;
00269         }
00270 
00271         /* Wait for OACK to arrive so that we have the block size */
00272         while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
00273                 ( pxe_tftp.max_offset == 0 ) ) {
00274                 step();
00275         }
00276         pxe_tftp.blksize = xfer_window ( &pxe_tftp.xfer );
00277         tftp_open->PacketSize = pxe_tftp.blksize;
00278         DBG ( " blksize=%d", tftp_open->PacketSize );
00279 
00280         /* EINPROGRESS is normal; we don't wait for the whole transfer */
00281         if ( rc == -EINPROGRESS )
00282                 rc = 0;
00283 
00284         tftp_open->Status = PXENV_STATUS ( rc );
00285         return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
00286 }
00287 
00288 /**
00289  * TFTP CLOSE
00290  *
00291  * @v tftp_close                        Pointer to a struct s_PXENV_TFTP_CLOSE
00292  * @ret #PXENV_EXIT_SUCCESS             File was closed successfully
00293  * @ret #PXENV_EXIT_FAILURE             File was not closed
00294  * @ret s_PXENV_TFTP_CLOSE::Status      PXE status code
00295  * @err None                            -
00296  *
00297  * Close a connection previously opened with pxenv_tftp_open().  You
00298  * must have previously opened a connection with pxenv_tftp_open().
00299  *
00300  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
00301  * value before calling this function in protected mode.  You cannot
00302  * call this function with a 32-bit stack segment.  (See the relevant
00303  * @ref pxe_x86_pmode16 "implementation note" for more details.)
00304  */
00305 static PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close ) {
00306         DBG ( "PXENV_TFTP_CLOSE" );
00307 
00308         pxe_tftp_close ( &pxe_tftp, 0 );
00309         tftp_close->Status = PXENV_STATUS_SUCCESS;
00310         return PXENV_EXIT_SUCCESS;
00311 }
00312 
00313 /**
00314  * TFTP READ
00315  *
00316  * @v tftp_read                         Pointer to a struct s_PXENV_TFTP_READ
00317  * @v s_PXENV_TFTP_READ::Buffer         Address of data buffer
00318  * @ret #PXENV_EXIT_SUCCESS             Data was read successfully
00319  * @ret #PXENV_EXIT_FAILURE             Data was not read
00320  * @ret s_PXENV_TFTP_READ::Status       PXE status code
00321  * @ret s_PXENV_TFTP_READ::PacketNumber TFTP packet number
00322  * @ret s_PXENV_TFTP_READ::BufferSize   Length of data written into buffer
00323  *
00324  * Reads a single packet from a connection previously opened with
00325  * pxenv_tftp_open() into the data buffer pointed to by
00326  * s_PXENV_TFTP_READ::Buffer.  You must have previously opened a
00327  * connection with pxenv_tftp_open().  The data written into
00328  * s_PXENV_TFTP_READ::Buffer is just the file data; the various
00329  * network headers have already been removed.
00330  *
00331  * The buffer must be large enough to contain a packet of the size
00332  * negotiated via the s_PXENV_TFTP_OPEN::PacketSize field in the
00333  * pxenv_tftp_open() call.  It is worth noting that the PXE
00334  * specification does @b not require the caller to fill in
00335  * s_PXENV_TFTP_READ::BufferSize before calling pxenv_tftp_read(), so
00336  * the PXE stack is free to ignore whatever value the caller might
00337  * place there and just assume that the buffer is large enough.  That
00338  * said, it may be worth the caller always filling in
00339  * s_PXENV_TFTP_READ::BufferSize to guard against PXE stacks that
00340  * mistake it for an input parameter.
00341  *
00342  * The length of the TFTP data packet will be returned via
00343  * s_PXENV_TFTP_READ::BufferSize.  If this length is less than the
00344  * blksize negotiated via s_PXENV_TFTP_OPEN::PacketSize in the call to
00345  * pxenv_tftp_open(), this indicates that the block is the last block
00346  * in the file.  Note that zero is a valid length for
00347  * s_PXENV_TFTP_READ::BufferSize, and will occur when the length of
00348  * the file is a multiple of the blksize.
00349  *
00350  * The PXE specification doesn't actually state that calls to
00351  * pxenv_tftp_read() will return the data packets in strict sequential
00352  * order, though most PXE stacks will probably do so.  The sequence
00353  * number of the packet will be returned in
00354  * s_PXENV_TFTP_READ::PacketNumber.  The first packet in the file has
00355  * a sequence number of one, not zero.
00356  *
00357  * To guard against flawed PXE stacks, the caller should probably set
00358  * s_PXENV_TFTP_READ::PacketNumber to one less than the expected
00359  * returned value (i.e. set it to zero for the first call to
00360  * pxenv_tftp_read() and then re-use the returned s_PXENV_TFTP_READ
00361  * parameter block for subsequent calls without modifying
00362  * s_PXENV_TFTP_READ::PacketNumber between calls).  The caller should
00363  * also guard against potential problems caused by flawed
00364  * implementations returning the occasional duplicate packet, by
00365  * checking that the value returned in s_PXENV_TFTP_READ::PacketNumber
00366  * is as expected (i.e. one greater than that returned from the
00367  * previous call to pxenv_tftp_read()).
00368  *
00369  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
00370  * value before calling this function in protected mode.  You cannot
00371  * call this function with a 32-bit stack segment.  (See the relevant
00372  * @ref pxe_x86_pmode16 "implementation note" for more details.)
00373  */
00374 static PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) {
00375         int rc;
00376 
00377         DBG ( "PXENV_TFTP_READ to %04x:%04x",
00378               tftp_read->Buffer.segment, tftp_read->Buffer.offset );
00379 
00380         /* Read single block into buffer */
00381         pxe_tftp.buffer = real_to_user ( tftp_read->Buffer.segment,
00382                                          tftp_read->Buffer.offset );
00383         pxe_tftp.size = pxe_tftp.blksize;
00384         pxe_tftp.start = pxe_tftp.offset;
00385         while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
00386                 ( pxe_tftp.offset == pxe_tftp.start ) )
00387                 step();
00388         pxe_tftp.buffer = UNULL;
00389         tftp_read->BufferSize = ( pxe_tftp.offset - pxe_tftp.start );
00390         tftp_read->PacketNumber = ++pxe_tftp.blkidx;
00391 
00392         /* EINPROGRESS is normal if we haven't reached EOF yet */
00393         if ( rc == -EINPROGRESS )
00394                 rc = 0;
00395 
00396         tftp_read->Status = PXENV_STATUS ( rc );
00397         return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
00398 }
00399 
00400 /**
00401  * TFTP/MTFTP read file
00402  *
00403  * @v tftp_read_file                 Pointer to a struct s_PXENV_TFTP_READ_FILE
00404  * @v s_PXENV_TFTP_READ_FILE::FileName          File name
00405  * @v s_PXENV_TFTP_READ_FILE::BufferSize        Size of the receive buffer
00406  * @v s_PXENV_TFTP_READ_FILE::Buffer            Address of the receive buffer
00407  * @v s_PXENV_TFTP_READ_FILE::ServerIPAddress   TFTP server IP address
00408  * @v s_PXENV_TFTP_READ_FILE::GatewayIPAddress  Relay agent IP address
00409  * @v s_PXENV_TFTP_READ_FILE::McastIPAddress    File's multicast IP address
00410  * @v s_PXENV_TFTP_READ_FILE::TFTPClntPort      Client multicast UDP port
00411  * @v s_PXENV_TFTP_READ_FILE::TFTPSrvPort       Server multicast UDP port
00412  * @v s_PXENV_TFTP_READ_FILE::TFTPOpenTimeOut   Time to wait for first packet
00413  * @v s_PXENV_TFTP_READ_FILE::TFTPReopenDelay   MTFTP inactivity timeout
00414  * @ret #PXENV_EXIT_SUCCESS                     File downloaded successfully
00415  * @ret #PXENV_EXIT_FAILURE                     File not downloaded
00416  * @ret s_PXENV_TFTP_READ_FILE::Status          PXE status code
00417  * @ret s_PXENV_TFTP_READ_FILE::BufferSize      Length of downloaded file
00418  *
00419  * Downloads an entire file via either TFTP or MTFTP into the buffer
00420  * pointed to by s_PXENV_TFTP_READ_FILE::Buffer.
00421  *
00422  * The PXE specification does not make it clear how the caller
00423  * requests that MTFTP be used rather than TFTP (or vice versa).  One
00424  * reasonable guess is that setting
00425  * s_PXENV_TFTP_READ_FILE::McastIPAddress to 0.0.0.0 would cause TFTP
00426  * to be used instead of MTFTP, though it is conceivable that some PXE
00427  * stacks would interpret that as "use the DHCP-provided multicast IP
00428  * address" instead.  Some PXE stacks will not implement MTFTP at all,
00429  * and will always use TFTP.
00430  *
00431  * It is not specified whether or not
00432  * s_PXENV_TFTP_READ_FILE::TFTPSrvPort will be used as the TFTP server
00433  * port for TFTP (rather than MTFTP) downloads.  Callers should assume
00434  * that the only way to access a TFTP server on a non-standard port is
00435  * to use pxenv_tftp_open() and pxenv_tftp_read().
00436  *
00437  * If s_PXENV_TFTP_READ_FILE::GatewayIPAddress is 0.0.0.0, normal IP
00438  * routing will take place.  See the relevant
00439  * @ref pxe_routing "implementation note" for more details.
00440  *
00441  * It is interesting to note that s_PXENV_TFTP_READ_FILE::Buffer is an
00442  * #ADDR32_t type, i.e. nominally a flat physical address.  Some PXE
00443  * NBPs (e.g. NTLDR) are known to call pxenv_tftp_read_file() in real
00444  * mode with s_PXENV_TFTP_READ_FILE::Buffer set to an address above
00445  * 1MB.  This means that PXE stacks must be prepared to write to areas
00446  * outside base memory.  Exactly how this is to be achieved is not
00447  * specified, though using INT 15,87 is as close to a standard method
00448  * as any, and should probably be used.  Switching to protected-mode
00449  * in order to access high memory will fail if pxenv_tftp_read_file()
00450  * is called in V86 mode; it is reasonably to expect that a V86
00451  * monitor would intercept the relatively well-defined INT 15,87 if it
00452  * wants the PXE stack to be able to write to high memory.
00453  *
00454  * Things get even more interesting if pxenv_tftp_read_file() is
00455  * called in protected mode, because there is then absolutely no way
00456  * for the PXE stack to write to an absolute physical address.  You
00457  * can't even get around the problem by creating a special "access
00458  * everything" segment in the s_PXE data structure, because the
00459  * #SEGDESC_t descriptors are limited to 64kB in size.
00460  *
00461  * Previous versions of the PXE specification (e.g. WfM 1.1a) provide
00462  * a separate API call, %pxenv_tftp_read_file_pmode(), specifically to
00463  * work around this problem.  The s_PXENV_TFTP_READ_FILE_PMODE
00464  * parameter block splits s_PXENV_TFTP_READ_FILE::Buffer into
00465  * s_PXENV_TFTP_READ_FILE_PMODE::BufferSelector and
00466  * s_PXENV_TFTP_READ_FILE_PMODE::BufferOffset, i.e. it provides a
00467  * protected-mode segment:offset address for the data buffer.  This
00468  * API call is no longer present in version 2.1 of the PXE
00469  * specification.
00470  *
00471  * Etherboot makes the assumption that s_PXENV_TFTP_READ_FILE::Buffer
00472  * is an offset relative to the caller's data segment, when
00473  * pxenv_tftp_read_file() is called in protected mode.
00474  *
00475  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
00476  * value before calling this function in protected mode.  You cannot
00477  * call this function with a 32-bit stack segment.  (See the relevant
00478  * @ref pxe_x86_pmode16 "implementation note" for more details.)
00479  */
00480 PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
00481                                     *tftp_read_file ) {
00482         int rc;
00483 
00484         DBG ( "PXENV_TFTP_READ_FILE to %08x+%x", tftp_read_file->Buffer,
00485               tftp_read_file->BufferSize );
00486 
00487         /* Open TFTP file */
00488         if ( ( rc = pxe_tftp_open ( tftp_read_file->ServerIPAddress, 0,
00489                                     tftp_read_file->FileName, 0 ) ) != 0 ) {
00490                 tftp_read_file->Status = PXENV_STATUS ( rc );
00491                 return PXENV_EXIT_FAILURE;
00492         }
00493 
00494         /* Read entire file */
00495         pxe_tftp.buffer = phys_to_user ( tftp_read_file->Buffer );
00496         pxe_tftp.size = tftp_read_file->BufferSize;
00497         while ( ( rc = pxe_tftp.rc ) == -EINPROGRESS )
00498                 step();
00499         pxe_tftp.buffer = UNULL;
00500         tftp_read_file->BufferSize = pxe_tftp.max_offset;
00501 
00502         /* Close TFTP file */
00503         pxe_tftp_close ( &pxe_tftp, rc );
00504 
00505         tftp_read_file->Status = PXENV_STATUS ( rc );
00506         return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
00507 }
00508 
00509 /**
00510  * TFTP GET FILE SIZE
00511  *
00512  * @v tftp_get_fsize                 Pointer to a struct s_PXENV_TFTP_GET_FSIZE
00513  * @v s_PXENV_TFTP_GET_FSIZE::ServerIPAddress   TFTP server IP address
00514  * @v s_PXENV_TFTP_GET_FSIZE::GatewayIPAddress  Relay agent IP address
00515  * @v s_PXENV_TFTP_GET_FSIZE::FileName  File name
00516  * @ret #PXENV_EXIT_SUCCESS             File size was determined successfully
00517  * @ret #PXENV_EXIT_FAILURE             File size was not determined
00518  * @ret s_PXENV_TFTP_GET_FSIZE::Status  PXE status code
00519  * @ret s_PXENV_TFTP_GET_FSIZE::FileSize        File size
00520  *
00521  * Determine the size of a file on a TFTP server.  This uses the
00522  * "tsize" TFTP option, and so will not work with a TFTP server that
00523  * does not support TFTP options, or that does not support the "tsize"
00524  * option.
00525  *
00526  * The PXE specification states that this API call will @b not open a
00527  * TFTP connection for subsequent use with pxenv_tftp_read().  (This
00528  * is somewhat daft, since the only way to obtain the file size via
00529  * the "tsize" option involves issuing a TFTP open request, but that's
00530  * life.)
00531  *
00532  * You cannot call pxenv_tftp_get_fsize() while a TFTP or UDP
00533  * connection is open.
00534  *
00535  * If s_PXENV_TFTP_GET_FSIZE::GatewayIPAddress is 0.0.0.0, normal IP
00536  * routing will take place.  See the relevant
00537  * @ref pxe_routing "implementation note" for more details.
00538  *
00539  * On x86, you must set the s_PXE::StatusCallout field to a nonzero
00540  * value before calling this function in protected mode.  You cannot
00541  * call this function with a 32-bit stack segment.  (See the relevant
00542  * @ref pxe_x86_pmode16 "implementation note" for more details.)
00543  * 
00544  * @note There is no way to specify the TFTP server port with this API
00545  * call.  Though you can open a file using a non-standard TFTP server
00546  * port (via s_PXENV_TFTP_OPEN::TFTPPort or, potentially,
00547  * s_PXENV_TFTP_READ_FILE::TFTPSrvPort), you can only get the size of
00548  * a file from a TFTP server listening on the standard TFTP port.
00549  * "Consistency" is not a word in Intel's vocabulary.
00550  */
00551 static PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE
00552                                            *tftp_get_fsize ) {
00553         int rc;
00554 
00555         DBG ( "PXENV_TFTP_GET_FSIZE" );
00556 
00557         /* Open TFTP file */
00558         if ( ( rc = pxe_tftp_open ( tftp_get_fsize->ServerIPAddress, 0,
00559                                     tftp_get_fsize->FileName, 0 ) ) != 0 ) {
00560                 tftp_get_fsize->Status = PXENV_STATUS ( rc );
00561                 return PXENV_EXIT_FAILURE;
00562         }
00563 
00564         /* Wait for initial seek to arrive, and record size */
00565         while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
00566                 ( pxe_tftp.max_offset == 0 ) ) {
00567                 step();
00568         }
00569         tftp_get_fsize->FileSize = pxe_tftp.max_offset;
00570         DBG ( " fsize=%d", tftp_get_fsize->FileSize );
00571 
00572         /* EINPROGRESS is normal; we don't wait for the whole transfer */
00573         if ( rc == -EINPROGRESS )
00574                 rc = 0;
00575 
00576         /* Close TFTP file */
00577         pxe_tftp_close ( &pxe_tftp, rc );
00578 
00579         tftp_get_fsize->Status = PXENV_STATUS ( rc );
00580         return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
00581 }
00582 
00583 /** PXE TFTP API */
00584 struct pxe_api_call pxe_tftp_api[] __pxe_api_call = {
00585         PXE_API_CALL ( PXENV_TFTP_OPEN, pxenv_tftp_open,
00586                        struct s_PXENV_TFTP_OPEN ),
00587         PXE_API_CALL ( PXENV_TFTP_CLOSE, pxenv_tftp_close,
00588                        struct s_PXENV_TFTP_CLOSE ),
00589         PXE_API_CALL ( PXENV_TFTP_READ, pxenv_tftp_read,
00590                        struct s_PXENV_TFTP_READ ),
00591         PXE_API_CALL ( PXENV_TFTP_READ_FILE, pxenv_tftp_read_file,
00592                        struct s_PXENV_TFTP_READ_FILE ),
00593         PXE_API_CALL ( PXENV_TFTP_GET_FSIZE, pxenv_tftp_get_fsize,
00594                        struct s_PXENV_TFTP_GET_FSIZE ),
00595 };