8 * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License, or any later version.
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 * You can also choose to distribute this program under the terms of
26 * the Unmodified Binary Distribution Licence (as given in the file
27 * COPYING.UBDL), provided that you have satisfied its requirements.
30 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
36 #include <ipxe/uaccess.h>
38 #include <ipxe/tftp.h>
39 #include <ipxe/iobuf.h>
40 #include <ipxe/xfer.h>
41 #include <ipxe/open.h>
42 #include <ipxe/process.h>
47 /** A PXE TFTP connection */
48 struct pxe_tftp_connection {
49 /** Data transfer interface */
50 struct interface xfer;
53 /** Size of data buffer */
55 /** Starting offset of data buffer */
59 /** Maximum file position */
65 /** Overall return status code */
70 * Close PXE TFTP connection
72 * @v pxe_tftp PXE TFTP connection
73 * @v rc Final status code
75 static void pxe_tftp_close ( struct pxe_tftp_connection *pxe_tftp, int rc ) {
76 intf_shutdown ( &pxe_tftp->xfer, rc );
81 * Check flow control window
83 * @v pxe_tftp PXE TFTP connection
84 * @ret len Length of window
86 static size_t pxe_tftp_xfer_window ( struct pxe_tftp_connection *pxe_tftp ) {
88 return pxe_tftp->blksize;
94 * @v pxe_tftp PXE TFTP connection
96 * @v meta Transfer metadata
97 * @ret rc Return status code
99 static int pxe_tftp_xfer_deliver ( struct pxe_tftp_connection *pxe_tftp,
100 struct io_buffer *iobuf,
101 struct xfer_metadata *meta ) {
102 size_t len = iob_len ( iobuf );
105 /* Calculate new buffer position */
106 if ( meta->flags & XFER_FL_ABS_OFFSET )
107 pxe_tftp->offset = 0;
108 pxe_tftp->offset += meta->offset;
110 /* Copy data block to buffer */
112 /* No data (pure seek); treat as success */
113 } else if ( pxe_tftp->offset < pxe_tftp->start ) {
114 DBG ( " buffer underrun at %zx (min %zx)",
115 pxe_tftp->offset, pxe_tftp->start );
117 } else if ( ( pxe_tftp->offset + len ) >
118 ( pxe_tftp->start + pxe_tftp->size ) ) {
119 DBG ( " buffer overrun at %zx (max %zx)",
120 ( pxe_tftp->offset + len ),
121 ( pxe_tftp->start + pxe_tftp->size ) );
124 copy_to_user ( pxe_tftp->buffer,
125 ( pxe_tftp->offset - pxe_tftp->start ),
129 /* Calculate new buffer position */
130 pxe_tftp->offset += len;
132 /* Record maximum offset as the file size */
133 if ( pxe_tftp->max_offset < pxe_tftp->offset )
134 pxe_tftp->max_offset = pxe_tftp->offset;
136 /* Terminate transfer on error */
138 pxe_tftp_close ( pxe_tftp, rc );
144 /** PXE TFTP connection interface operations */
145 static struct interface_operation pxe_tftp_xfer_ops[] = {
146 INTF_OP ( xfer_deliver, struct pxe_tftp_connection *,
147 pxe_tftp_xfer_deliver ),
148 INTF_OP ( xfer_window, struct pxe_tftp_connection *,
149 pxe_tftp_xfer_window ),
150 INTF_OP ( intf_close, struct pxe_tftp_connection *, pxe_tftp_close ),
153 /** PXE TFTP connection interface descriptor */
154 static struct interface_descriptor pxe_tftp_xfer_desc =
155 INTF_DESC ( struct pxe_tftp_connection, xfer, pxe_tftp_xfer_ops );
157 /** The PXE TFTP connection */
158 static struct pxe_tftp_connection pxe_tftp = {
159 .xfer = INTF_INIT ( pxe_tftp_xfer_desc ),
163 * Maximum length of a PXE TFTP URI
165 * The PXE TFTP API provides 128 characters for the filename; the
166 * extra 128 bytes allow for the remainder of the URI.
168 #define PXE_TFTP_URI_LEN 256
171 * Open PXE TFTP connection
173 * @v ipaddress IP address
174 * @v port TFTP server port
175 * @v filename File name
176 * @v blksize Requested block size
177 * @ret rc Return status code
179 static int pxe_tftp_open ( IP4_t ipaddress, UDP_PORT_t port,
180 UINT8_t *filename, UINT16_t blksize ) {
181 struct in_addr address;
185 /* Reset PXE TFTP connection structure */
186 memset ( &pxe_tftp, 0, sizeof ( pxe_tftp ) );
187 intf_init ( &pxe_tftp.xfer, &pxe_tftp_xfer_desc, NULL );
188 if ( blksize < TFTP_DEFAULT_BLKSIZE )
189 blksize = TFTP_DEFAULT_BLKSIZE;
190 pxe_tftp.blksize = blksize;
191 pxe_tftp.rc = -EINPROGRESS;
194 address.s_addr = ipaddress;
195 DBG ( " %s", inet_ntoa ( address ) );
197 DBG ( ":%d", ntohs ( port ) );
198 DBG ( ":%s", filename );
199 uri = tftp_uri ( address, ntohs ( port ), ( ( char * ) filename ) );
201 DBG ( " could not create URI\n" );
205 /* Open PXE TFTP connection */
206 if ( ( rc = xfer_open_uri ( &pxe_tftp.xfer, uri ) ) != 0 ) {
207 DBG ( " could not open (%s)\n", strerror ( rc ) );
217 * @v tftp_open Pointer to a struct s_PXENV_TFTP_OPEN
218 * @v s_PXENV_TFTP_OPEN::ServerIPAddress TFTP server IP address
219 * @v s_PXENV_TFTP_OPEN::GatewayIPAddress Relay agent IP address, or 0.0.0.0
220 * @v s_PXENV_TFTP_OPEN::FileName Name of file to open
221 * @v s_PXENV_TFTP_OPEN::TFTPPort TFTP server UDP port
222 * @v s_PXENV_TFTP_OPEN::PacketSize TFTP blksize option to request
223 * @ret #PXENV_EXIT_SUCCESS File was opened
224 * @ret #PXENV_EXIT_FAILURE File was not opened
225 * @ret s_PXENV_TFTP_OPEN::Status PXE status code
226 * @ret s_PXENV_TFTP_OPEN::PacketSize Negotiated blksize
227 * @err #PXENV_STATUS_TFTP_INVALID_PACKET_SIZE Requested blksize too small
229 * Opens a TFTP connection for downloading a file a block at a time
230 * using pxenv_tftp_read().
232 * If s_PXENV_TFTP_OPEN::GatewayIPAddress is 0.0.0.0, normal IP
233 * routing will take place. See the relevant
234 * @ref pxe_routing "implementation note" for more details.
236 * On x86, you must set the s_PXE::StatusCallout field to a nonzero
237 * value before calling this function in protected mode. You cannot
238 * call this function with a 32-bit stack segment. (See the relevant
239 * @ref pxe_x86_pmode16 "implementation note" for more details.)
241 * @note According to the PXE specification version 2.1, this call
242 * "opens a file for reading/writing", though how writing is to be
243 * achieved without the existence of an API call %pxenv_tftp_write()
246 * @note Despite the existence of the numerous statements within the
247 * PXE specification of the form "...if a TFTP/MTFTP or UDP connection
248 * is active...", you cannot use pxenv_tftp_open() and
249 * pxenv_tftp_read() to read a file via MTFTP; only via plain old
250 * TFTP. If you want to use MTFTP, use pxenv_tftp_read_file()
251 * instead. Astute readers will note that, since
252 * pxenv_tftp_read_file() is an atomic operation from the point of
253 * view of the PXE API, it is conceptually impossible to issue any
254 * other PXE API call "if an MTFTP connection is active".
256 static PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) {
259 DBG ( "PXENV_TFTP_OPEN" );
261 /* Guard against callers that fail to close before re-opening */
262 pxe_tftp_close ( &pxe_tftp, 0 );
264 /* Open connection */
265 if ( ( rc = pxe_tftp_open ( tftp_open->ServerIPAddress,
268 tftp_open->PacketSize ) ) != 0 ) {
269 tftp_open->Status = PXENV_STATUS ( rc );
270 return PXENV_EXIT_FAILURE;
273 /* Wait for OACK to arrive so that we have the block size */
274 while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
275 ( pxe_tftp.max_offset == 0 ) ) {
278 pxe_tftp.blksize = xfer_window ( &pxe_tftp.xfer );
279 tftp_open->PacketSize = pxe_tftp.blksize;
280 DBG ( " blksize=%d", tftp_open->PacketSize );
282 /* EINPROGRESS is normal; we don't wait for the whole transfer */
283 if ( rc == -EINPROGRESS )
286 tftp_open->Status = PXENV_STATUS ( rc );
287 return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
293 * @v tftp_close Pointer to a struct s_PXENV_TFTP_CLOSE
294 * @ret #PXENV_EXIT_SUCCESS File was closed successfully
295 * @ret #PXENV_EXIT_FAILURE File was not closed
296 * @ret s_PXENV_TFTP_CLOSE::Status PXE status code
299 * Close a connection previously opened with pxenv_tftp_open(). You
300 * must have previously opened a connection with pxenv_tftp_open().
302 * On x86, you must set the s_PXE::StatusCallout field to a nonzero
303 * value before calling this function in protected mode. You cannot
304 * call this function with a 32-bit stack segment. (See the relevant
305 * @ref pxe_x86_pmode16 "implementation note" for more details.)
307 static PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close ) {
308 DBG ( "PXENV_TFTP_CLOSE" );
310 pxe_tftp_close ( &pxe_tftp, 0 );
311 tftp_close->Status = PXENV_STATUS_SUCCESS;
312 return PXENV_EXIT_SUCCESS;
318 * @v tftp_read Pointer to a struct s_PXENV_TFTP_READ
319 * @v s_PXENV_TFTP_READ::Buffer Address of data buffer
320 * @ret #PXENV_EXIT_SUCCESS Data was read successfully
321 * @ret #PXENV_EXIT_FAILURE Data was not read
322 * @ret s_PXENV_TFTP_READ::Status PXE status code
323 * @ret s_PXENV_TFTP_READ::PacketNumber TFTP packet number
324 * @ret s_PXENV_TFTP_READ::BufferSize Length of data written into buffer
326 * Reads a single packet from a connection previously opened with
327 * pxenv_tftp_open() into the data buffer pointed to by
328 * s_PXENV_TFTP_READ::Buffer. You must have previously opened a
329 * connection with pxenv_tftp_open(). The data written into
330 * s_PXENV_TFTP_READ::Buffer is just the file data; the various
331 * network headers have already been removed.
333 * The buffer must be large enough to contain a packet of the size
334 * negotiated via the s_PXENV_TFTP_OPEN::PacketSize field in the
335 * pxenv_tftp_open() call. It is worth noting that the PXE
336 * specification does @b not require the caller to fill in
337 * s_PXENV_TFTP_READ::BufferSize before calling pxenv_tftp_read(), so
338 * the PXE stack is free to ignore whatever value the caller might
339 * place there and just assume that the buffer is large enough. That
340 * said, it may be worth the caller always filling in
341 * s_PXENV_TFTP_READ::BufferSize to guard against PXE stacks that
342 * mistake it for an input parameter.
344 * The length of the TFTP data packet will be returned via
345 * s_PXENV_TFTP_READ::BufferSize. If this length is less than the
346 * blksize negotiated via s_PXENV_TFTP_OPEN::PacketSize in the call to
347 * pxenv_tftp_open(), this indicates that the block is the last block
348 * in the file. Note that zero is a valid length for
349 * s_PXENV_TFTP_READ::BufferSize, and will occur when the length of
350 * the file is a multiple of the blksize.
352 * The PXE specification doesn't actually state that calls to
353 * pxenv_tftp_read() will return the data packets in strict sequential
354 * order, though most PXE stacks will probably do so. The sequence
355 * number of the packet will be returned in
356 * s_PXENV_TFTP_READ::PacketNumber. The first packet in the file has
357 * a sequence number of one, not zero.
359 * To guard against flawed PXE stacks, the caller should probably set
360 * s_PXENV_TFTP_READ::PacketNumber to one less than the expected
361 * returned value (i.e. set it to zero for the first call to
362 * pxenv_tftp_read() and then re-use the returned s_PXENV_TFTP_READ
363 * parameter block for subsequent calls without modifying
364 * s_PXENV_TFTP_READ::PacketNumber between calls). The caller should
365 * also guard against potential problems caused by flawed
366 * implementations returning the occasional duplicate packet, by
367 * checking that the value returned in s_PXENV_TFTP_READ::PacketNumber
368 * is as expected (i.e. one greater than that returned from the
369 * previous call to pxenv_tftp_read()).
371 * On x86, you must set the s_PXE::StatusCallout field to a nonzero
372 * value before calling this function in protected mode. You cannot
373 * call this function with a 32-bit stack segment. (See the relevant
374 * @ref pxe_x86_pmode16 "implementation note" for more details.)
376 static PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) {
379 DBG ( "PXENV_TFTP_READ to %04x:%04x",
380 tftp_read->Buffer.segment, tftp_read->Buffer.offset );
382 /* Read single block into buffer */
383 pxe_tftp.buffer = real_to_user ( tftp_read->Buffer.segment,
384 tftp_read->Buffer.offset );
385 pxe_tftp.size = pxe_tftp.blksize;
386 pxe_tftp.start = pxe_tftp.offset;
387 while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
388 ( pxe_tftp.offset == pxe_tftp.start ) )
390 pxe_tftp.buffer = UNULL;
391 tftp_read->BufferSize = ( pxe_tftp.offset - pxe_tftp.start );
392 tftp_read->PacketNumber = ++pxe_tftp.blkidx;
394 /* EINPROGRESS is normal if we haven't reached EOF yet */
395 if ( rc == -EINPROGRESS )
398 tftp_read->Status = PXENV_STATUS ( rc );
399 return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
403 * TFTP/MTFTP read file
405 * @v tftp_read_file Pointer to a struct s_PXENV_TFTP_READ_FILE
406 * @v s_PXENV_TFTP_READ_FILE::FileName File name
407 * @v s_PXENV_TFTP_READ_FILE::BufferSize Size of the receive buffer
408 * @v s_PXENV_TFTP_READ_FILE::Buffer Address of the receive buffer
409 * @v s_PXENV_TFTP_READ_FILE::ServerIPAddress TFTP server IP address
410 * @v s_PXENV_TFTP_READ_FILE::GatewayIPAddress Relay agent IP address
411 * @v s_PXENV_TFTP_READ_FILE::McastIPAddress File's multicast IP address
412 * @v s_PXENV_TFTP_READ_FILE::TFTPClntPort Client multicast UDP port
413 * @v s_PXENV_TFTP_READ_FILE::TFTPSrvPort Server multicast UDP port
414 * @v s_PXENV_TFTP_READ_FILE::TFTPOpenTimeOut Time to wait for first packet
415 * @v s_PXENV_TFTP_READ_FILE::TFTPReopenDelay MTFTP inactivity timeout
416 * @ret #PXENV_EXIT_SUCCESS File downloaded successfully
417 * @ret #PXENV_EXIT_FAILURE File not downloaded
418 * @ret s_PXENV_TFTP_READ_FILE::Status PXE status code
419 * @ret s_PXENV_TFTP_READ_FILE::BufferSize Length of downloaded file
421 * Downloads an entire file via either TFTP or MTFTP into the buffer
422 * pointed to by s_PXENV_TFTP_READ_FILE::Buffer.
424 * The PXE specification does not make it clear how the caller
425 * requests that MTFTP be used rather than TFTP (or vice versa). One
426 * reasonable guess is that setting
427 * s_PXENV_TFTP_READ_FILE::McastIPAddress to 0.0.0.0 would cause TFTP
428 * to be used instead of MTFTP, though it is conceivable that some PXE
429 * stacks would interpret that as "use the DHCP-provided multicast IP
430 * address" instead. Some PXE stacks will not implement MTFTP at all,
431 * and will always use TFTP.
433 * It is not specified whether or not
434 * s_PXENV_TFTP_READ_FILE::TFTPSrvPort will be used as the TFTP server
435 * port for TFTP (rather than MTFTP) downloads. Callers should assume
436 * that the only way to access a TFTP server on a non-standard port is
437 * to use pxenv_tftp_open() and pxenv_tftp_read().
439 * If s_PXENV_TFTP_READ_FILE::GatewayIPAddress is 0.0.0.0, normal IP
440 * routing will take place. See the relevant
441 * @ref pxe_routing "implementation note" for more details.
443 * It is interesting to note that s_PXENV_TFTP_READ_FILE::Buffer is an
444 * #ADDR32_t type, i.e. nominally a flat physical address. Some PXE
445 * NBPs (e.g. NTLDR) are known to call pxenv_tftp_read_file() in real
446 * mode with s_PXENV_TFTP_READ_FILE::Buffer set to an address above
447 * 1MB. This means that PXE stacks must be prepared to write to areas
448 * outside base memory. Exactly how this is to be achieved is not
449 * specified, though using INT 15,87 is as close to a standard method
450 * as any, and should probably be used. Switching to protected-mode
451 * in order to access high memory will fail if pxenv_tftp_read_file()
452 * is called in V86 mode; it is reasonably to expect that a V86
453 * monitor would intercept the relatively well-defined INT 15,87 if it
454 * wants the PXE stack to be able to write to high memory.
456 * Things get even more interesting if pxenv_tftp_read_file() is
457 * called in protected mode, because there is then absolutely no way
458 * for the PXE stack to write to an absolute physical address. You
459 * can't even get around the problem by creating a special "access
460 * everything" segment in the s_PXE data structure, because the
461 * #SEGDESC_t descriptors are limited to 64kB in size.
463 * Previous versions of the PXE specification (e.g. WfM 1.1a) provide
464 * a separate API call, %pxenv_tftp_read_file_pmode(), specifically to
465 * work around this problem. The s_PXENV_TFTP_READ_FILE_PMODE
466 * parameter block splits s_PXENV_TFTP_READ_FILE::Buffer into
467 * s_PXENV_TFTP_READ_FILE_PMODE::BufferSelector and
468 * s_PXENV_TFTP_READ_FILE_PMODE::BufferOffset, i.e. it provides a
469 * protected-mode segment:offset address for the data buffer. This
470 * API call is no longer present in version 2.1 of the PXE
473 * Etherboot makes the assumption that s_PXENV_TFTP_READ_FILE::Buffer
474 * is an offset relative to the caller's data segment, when
475 * pxenv_tftp_read_file() is called in protected mode.
477 * On x86, you must set the s_PXE::StatusCallout field to a nonzero
478 * value before calling this function in protected mode. You cannot
479 * call this function with a 32-bit stack segment. (See the relevant
480 * @ref pxe_x86_pmode16 "implementation note" for more details.)
482 PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
486 DBG ( "PXENV_TFTP_READ_FILE to %08x+%x", tftp_read_file->Buffer,
487 tftp_read_file->BufferSize );
490 if ( ( rc = pxe_tftp_open ( tftp_read_file->ServerIPAddress, 0,
491 tftp_read_file->FileName, 0 ) ) != 0 ) {
492 tftp_read_file->Status = PXENV_STATUS ( rc );
493 return PXENV_EXIT_FAILURE;
496 /* Read entire file */
497 pxe_tftp.buffer = phys_to_user ( tftp_read_file->Buffer );
498 pxe_tftp.size = tftp_read_file->BufferSize;
499 while ( ( rc = pxe_tftp.rc ) == -EINPROGRESS )
501 pxe_tftp.buffer = UNULL;
502 tftp_read_file->BufferSize = pxe_tftp.max_offset;
504 /* Close TFTP file */
505 pxe_tftp_close ( &pxe_tftp, rc );
507 tftp_read_file->Status = PXENV_STATUS ( rc );
508 return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
514 * @v tftp_get_fsize Pointer to a struct s_PXENV_TFTP_GET_FSIZE
515 * @v s_PXENV_TFTP_GET_FSIZE::ServerIPAddress TFTP server IP address
516 * @v s_PXENV_TFTP_GET_FSIZE::GatewayIPAddress Relay agent IP address
517 * @v s_PXENV_TFTP_GET_FSIZE::FileName File name
518 * @ret #PXENV_EXIT_SUCCESS File size was determined successfully
519 * @ret #PXENV_EXIT_FAILURE File size was not determined
520 * @ret s_PXENV_TFTP_GET_FSIZE::Status PXE status code
521 * @ret s_PXENV_TFTP_GET_FSIZE::FileSize File size
523 * Determine the size of a file on a TFTP server. This uses the
524 * "tsize" TFTP option, and so will not work with a TFTP server that
525 * does not support TFTP options, or that does not support the "tsize"
528 * The PXE specification states that this API call will @b not open a
529 * TFTP connection for subsequent use with pxenv_tftp_read(). (This
530 * is somewhat daft, since the only way to obtain the file size via
531 * the "tsize" option involves issuing a TFTP open request, but that's
534 * You cannot call pxenv_tftp_get_fsize() while a TFTP or UDP
535 * connection is open.
537 * If s_PXENV_TFTP_GET_FSIZE::GatewayIPAddress is 0.0.0.0, normal IP
538 * routing will take place. See the relevant
539 * @ref pxe_routing "implementation note" for more details.
541 * On x86, you must set the s_PXE::StatusCallout field to a nonzero
542 * value before calling this function in protected mode. You cannot
543 * call this function with a 32-bit stack segment. (See the relevant
544 * @ref pxe_x86_pmode16 "implementation note" for more details.)
546 * @note There is no way to specify the TFTP server port with this API
547 * call. Though you can open a file using a non-standard TFTP server
548 * port (via s_PXENV_TFTP_OPEN::TFTPPort or, potentially,
549 * s_PXENV_TFTP_READ_FILE::TFTPSrvPort), you can only get the size of
550 * a file from a TFTP server listening on the standard TFTP port.
551 * "Consistency" is not a word in Intel's vocabulary.
553 static PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE
557 DBG ( "PXENV_TFTP_GET_FSIZE" );
560 if ( ( rc = pxe_tftp_open ( tftp_get_fsize->ServerIPAddress, 0,
561 tftp_get_fsize->FileName, 0 ) ) != 0 ) {
562 tftp_get_fsize->Status = PXENV_STATUS ( rc );
563 return PXENV_EXIT_FAILURE;
566 /* Wait for initial seek to arrive, and record size */
567 while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
568 ( pxe_tftp.max_offset == 0 ) ) {
571 tftp_get_fsize->FileSize = pxe_tftp.max_offset;
572 DBG ( " fsize=%d", tftp_get_fsize->FileSize );
574 /* EINPROGRESS is normal; we don't wait for the whole transfer */
575 if ( rc == -EINPROGRESS )
578 /* Close TFTP file */
579 pxe_tftp_close ( &pxe_tftp, rc );
581 tftp_get_fsize->Status = PXENV_STATUS ( rc );
582 return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
586 struct pxe_api_call pxe_tftp_api[] __pxe_api_call = {
587 PXE_API_CALL ( PXENV_TFTP_OPEN, pxenv_tftp_open,
588 struct s_PXENV_TFTP_OPEN ),
589 PXE_API_CALL ( PXENV_TFTP_CLOSE, pxenv_tftp_close,
590 struct s_PXENV_TFTP_CLOSE ),
591 PXE_API_CALL ( PXENV_TFTP_READ, pxenv_tftp_read,
592 struct s_PXENV_TFTP_READ ),
593 PXE_API_CALL ( PXENV_TFTP_READ_FILE, pxenv_tftp_read_file,
594 struct s_PXENV_TFTP_READ_FILE ),
595 PXE_API_CALL ( PXENV_TFTP_GET_FSIZE, pxenv_tftp_get_fsize,
596 struct s_PXENV_TFTP_GET_FSIZE ),