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