iPXE
pxe_tftp.c File Reference

PXE TFTP API. More...

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/in.h>
#include <ipxe/tftp.h>
#include <ipxe/iobuf.h>
#include <ipxe/xfer.h>
#include <ipxe/open.h>
#include <ipxe/process.h>
#include <ipxe/uri.h>
#include <realmode.h>
#include <pxe.h>

Go to the source code of this file.

Data Structures

struct  pxe_tftp_connection
 A PXE TFTP connection. More...

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static void pxe_tftp_close (struct pxe_tftp_connection *pxe_tftp, int rc)
 Close PXE TFTP connection.
static size_t pxe_tftp_xfer_window (struct pxe_tftp_connection *pxe_tftp)
 Check flow control window.
static int pxe_tftp_xfer_deliver (struct pxe_tftp_connection *pxe_tftp, struct io_buffer *iobuf, struct xfer_metadata *meta)
 Receive new data.
static int pxe_tftp_open (IP4_t ipaddress, UDP_PORT_t port, UINT8_t *filename, UINT16_t blksize)
 Open PXE TFTP connection.
static PXENV_EXIT_t pxenv_tftp_open (struct s_PXENV_TFTP_OPEN *tftp_open)
 TFTP OPEN.
static PXENV_EXIT_t pxenv_tftp_close (struct s_PXENV_TFTP_CLOSE *tftp_close)
 TFTP CLOSE.
static PXENV_EXIT_t pxenv_tftp_read (struct s_PXENV_TFTP_READ *tftp_read)
 TFTP READ.
PXENV_EXIT_t pxenv_tftp_read_file (struct s_PXENV_TFTP_READ_FILE *tftp_read_file)
 TFTP/MTFTP read file.
static PXENV_EXIT_t pxenv_tftp_get_fsize (struct s_PXENV_TFTP_GET_FSIZE *tftp_get_fsize)
 TFTP GET FILE SIZE.

Variables

static struct interface_operation pxe_tftp_xfer_ops []
 PXE TFTP connection interface operations.
static struct interface_descriptor pxe_tftp_xfer_desc
 PXE TFTP connection interface descriptor.
static struct pxe_tftp_connection pxe_tftp
 The PXE TFTP connection.
struct pxe_api_call pxe_tftp_api[] __pxe_api_call
 PXE TFTP API.

Detailed Description

PXE TFTP API.

Definition in file pxe_tftp.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )

◆ pxe_tftp_close()

void pxe_tftp_close ( struct pxe_tftp_connection * pxe_tftp,
int rc )
static

Close PXE TFTP connection.

Parameters
pxe_tftpPXE TFTP connection
rcFinal status code

Definition at line 74 of file pxe_tftp.c.

74 {
75 intf_shutdown ( &pxe_tftp->xfer, rc );
76 pxe_tftp->rc = rc;
77}
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
Definition interface.c:279
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition pxe_tftp.c:156

References intf_shutdown(), pxe_tftp, and rc.

Referenced by pxe_tftp_xfer_deliver(), pxenv_tftp_close(), pxenv_tftp_get_fsize(), pxenv_tftp_open(), and pxenv_tftp_read_file().

◆ pxe_tftp_xfer_window()

size_t pxe_tftp_xfer_window ( struct pxe_tftp_connection * pxe_tftp)
static

Check flow control window.

Parameters
pxe_tftpPXE TFTP connection
Return values
lenLength of window

Definition at line 85 of file pxe_tftp.c.

85 {
86
87 return pxe_tftp->blksize;
88}

References pxe_tftp.

◆ pxe_tftp_xfer_deliver()

int pxe_tftp_xfer_deliver ( struct pxe_tftp_connection * pxe_tftp,
struct io_buffer * iobuf,
struct xfer_metadata * meta )
static

Receive new data.

Parameters
pxe_tftpPXE TFTP connection
iobufI/O buffer
metaTransfer metadata
Return values
rcReturn status code

Definition at line 98 of file pxe_tftp.c.

100 {
101 size_t len = iob_len ( iobuf );
102 int rc = 0;
103
104 /* Calculate new buffer position */
105 if ( meta->flags & XFER_FL_ABS_OFFSET )
106 pxe_tftp->offset = 0;
107 pxe_tftp->offset += meta->offset;
108
109 /* Copy data block to buffer */
110 if ( len == 0 ) {
111 /* No data (pure seek); treat as success */
112 } else if ( pxe_tftp->offset < pxe_tftp->start ) {
113 DBG ( " buffer underrun at %zx (min %zx)",
114 pxe_tftp->offset, pxe_tftp->start );
115 rc = -ENOBUFS;
116 } else if ( ( pxe_tftp->offset + len ) >
117 ( pxe_tftp->start + pxe_tftp->size ) ) {
118 DBG ( " buffer overrun at %zx (max %zx)",
119 ( pxe_tftp->offset + len ),
120 ( pxe_tftp->start + pxe_tftp->size ) );
121 rc = -ENOBUFS;
122 } else {
123 memcpy ( ( pxe_tftp->buffer + pxe_tftp->offset -
124 pxe_tftp->start ), iobuf->data, len );
125 }
126
127 /* Calculate new buffer position */
128 pxe_tftp->offset += len;
129
130 /* Record maximum offset as the file size */
131 if ( pxe_tftp->max_offset < pxe_tftp->offset )
132 pxe_tftp->max_offset = pxe_tftp->offset;
133
134 /* Terminate transfer on error */
135 if ( rc != 0 )
137
138 free_iob ( iobuf );
139 return rc;
140}
ring len
Length.
Definition dwmac.h:226
uint8_t meta
Metadata flags.
Definition ena.h:3
#define DBG(...)
Print a debugging message.
Definition compiler.h:498
#define ENOBUFS
No buffer space available.
Definition errno.h:499
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:160
static void pxe_tftp_close(struct pxe_tftp_connection *pxe_tftp, int rc)
Close PXE TFTP connection.
Definition pxe_tftp.c:74
void * data
Start of data.
Definition iobuf.h:53
#define XFER_FL_ABS_OFFSET
Offset is absolute.
Definition xfer.h:48

References io_buffer::data, DBG, ENOBUFS, free_iob(), iob_len(), len, memcpy(), meta, pxe_tftp, pxe_tftp_close(), rc, and XFER_FL_ABS_OFFSET.

◆ pxe_tftp_open()

int pxe_tftp_open ( IP4_t ipaddress,
UDP_PORT_t port,
UINT8_t * filename,
UINT16_t blksize )
static

Open PXE TFTP connection.

Parameters
ipaddressIP address
portTFTP server port (in network byte order)
filenameFile name
blksizeRequested block size
Return values
rcReturn status code

Definition at line 169 of file pxe_tftp.c.

170 {
171 union {
172 struct sockaddr sa;
173 struct sockaddr_in sin;
174 } server;
175 struct uri *uri;
176 int rc;
177
178 /* Reset PXE TFTP connection structure */
179 memset ( &pxe_tftp, 0, sizeof ( pxe_tftp ) );
183 pxe_tftp.blksize = blksize;
184 pxe_tftp.rc = -EINPROGRESS;
185
186 /* Construct URI */
187 memset ( &server, 0, sizeof ( server ) );
188 server.sin.sin_family = AF_INET;
189 server.sin.sin_addr.s_addr = ipaddress;
190 server.sin.sin_port = port;
191 DBG ( " %s", sock_ntoa ( &server.sa ) );
192 if ( port )
193 DBG ( ":%d", ntohs ( port ) );
194 DBG ( ":%s", filename );
195 uri = pxe_uri ( &server.sa, ( ( char * ) filename ) );
196 if ( ! uri ) {
197 DBG ( " could not create URI\n" );
198 return -ENOMEM;
199 }
200
201 /* Open PXE TFTP connection */
202 if ( ( rc = xfer_open_uri ( &pxe_tftp.xfer, uri ) ) != 0 ) {
203 DBG ( " could not open (%s)\n", strerror ( rc ) );
204 return rc;
205 }
206
207 return 0;
208}
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
u8 port
Port number.
Definition CIB_PRM.h:3
#define AF_INET
IPv4 Internet addresses.
Definition socket.h:64
#define ENOMEM
Not enough space.
Definition errno.h:535
#define EINPROGRESS
Operation in progress.
Definition errno.h:419
#define ntohs(value)
Definition byteswap.h:137
void * memset(void *dest, int character, size_t len) __nonnull
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
Definition interface.h:204
int xfer_open_uri(struct interface *intf, struct uri *uri)
Open URI.
Definition open.c:68
uint32_t blksize
Cipher block size.
Definition pccrr.h:1
static struct interface_descriptor pxe_tftp_xfer_desc
PXE TFTP connection interface descriptor.
Definition pxe_tftp.c:152
const char * sock_ntoa(struct sockaddr *sa)
Transcribe socket address.
Definition socket.c:43
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
IPv4 socket address.
Definition in.h:85
Generalized socket address structure.
Definition socket.h:97
A Uniform Resource Identifier.
Definition uri.h:65
struct sockaddr sa
Definition syslog.c:57
struct sockaddr_in sin
Definition syslog.c:59
#define TFTP_DEFAULT_BLKSIZE
Default TFTP data block size.
Definition tftp.h:16
struct uri * pxe_uri(struct sockaddr *sa_server, const char *filename)
Construct URI from server address and filename.
Definition uri.c:810

References AF_INET, blksize, DBG, EINPROGRESS, ENOMEM, intf_init(), memset(), ntohs, NULL, port, pxe_tftp, pxe_tftp_xfer_desc, pxe_uri(), rc, sa, sin, sock_ntoa(), strerror(), TFTP_DEFAULT_BLKSIZE, and xfer_open_uri().

Referenced by pxenv_tftp_get_fsize(), pxenv_tftp_open(), and pxenv_tftp_read_file().

◆ pxenv_tftp_open()

PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN * tftp_open)
static

TFTP OPEN.

Parameters
tftp_openPointer to a struct s_PXENV_TFTP_OPEN
s_PXENV_TFTP_OPEN::ServerIPAddressTFTP server IP address
s_PXENV_TFTP_OPEN::GatewayIPAddressRelay agent IP address, or 0.0.0.0
s_PXENV_TFTP_OPEN::FileNameName of file to open
s_PXENV_TFTP_OPEN::TFTPPortTFTP server UDP port
s_PXENV_TFTP_OPEN::PacketSizeTFTP blksize option to request
Return values
PXENV_EXIT_SUCCESSFile was opened
PXENV_EXIT_FAILUREFile was not opened
s_PXENV_TFTP_OPEN::StatusPXE status code
s_PXENV_TFTP_OPEN::PacketSizeNegotiated blksize
Exceptions
PXENV_STATUS_TFTP_INVALID_PACKET_SIZERequested blksize too small

Opens a TFTP connection for downloading a file a block at a time using pxenv_tftp_read().

If s_PXENV_TFTP_OPEN::GatewayIPAddress is 0.0.0.0, normal IP routing will take place. See the relevant implementation note for more details.

On x86, you must set the s_PXE::StatusCallout field to a nonzero value before calling this function in protected mode. You cannot call this function with a 32-bit stack segment. (See the relevant implementation note for more details.)

Note
According to the PXE specification version 2.1, this call "opens a file for reading/writing", though how writing is to be achieved without the existence of an API call pxenv_tftp_write() is not made clear.
Despite the existence of the numerous statements within the PXE specification of the form "...if a TFTP/MTFTP or UDP connection is active...", you cannot use pxenv_tftp_open() and pxenv_tftp_read() to read a file via MTFTP; only via plain old TFTP. If you want to use MTFTP, use pxenv_tftp_read_file() instead. Astute readers will note that, since pxenv_tftp_read_file() is an atomic operation from the point of view of the PXE API, it is conceptually impossible to issue any other PXE API call "if an MTFTP connection is active".

Definition at line 252 of file pxe_tftp.c.

252 {
253 int rc;
254
255 DBG ( "PXENV_TFTP_OPEN" );
256
257 /* Guard against callers that fail to close before re-opening */
258 pxe_tftp_close ( &pxe_tftp, 0 );
259
260 /* Open connection */
261 if ( ( rc = pxe_tftp_open ( tftp_open->ServerIPAddress,
262 tftp_open->TFTPPort,
263 tftp_open->FileName,
264 tftp_open->PacketSize ) ) != 0 ) {
265 tftp_open->Status = PXENV_STATUS ( rc );
266 return PXENV_EXIT_FAILURE;
267 }
268
269 /* Wait for OACK to arrive so that we have the block size */
270 while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
271 ( pxe_tftp.max_offset == 0 ) ) {
272 step();
273 }
274 pxe_tftp.blksize = xfer_window ( &pxe_tftp.xfer );
275 tftp_open->PacketSize = pxe_tftp.blksize;
276 DBG ( " blksize=%d", tftp_open->PacketSize );
277
278 /* EINPROGRESS is normal; we don't wait for the whole transfer */
279 if ( rc == -EINPROGRESS )
280 rc = 0;
281
282 tftp_open->Status = PXENV_STATUS ( rc );
284}
#define PXENV_EXIT_FAILURE
An error occurred.
Definition pxe_types.h:46
#define PXENV_EXIT_SUCCESS
No error occurred.
Definition pxe_types.h:45
void step(void)
Single-step a single process.
Definition process.c:99
#define PXENV_STATUS(rc)
Derive PXENV_STATUS code from iPXE error number.
Definition pxe_error.h:121
static int pxe_tftp_open(IP4_t ipaddress, UDP_PORT_t port, UINT8_t *filename, UINT16_t blksize)
Open PXE TFTP connection.
Definition pxe_tftp.c:169
static int tftp_open(struct interface *xfer, struct uri *uri)
Initiate TFTP download.
Definition tftp.c:1149
size_t xfer_window(struct interface *intf)
Check flow control window.
Definition xfer.c:117

References DBG, EINPROGRESS, pxe_tftp, pxe_tftp_close(), pxe_tftp_open(), PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS, rc, step(), tftp_open(), and xfer_window().

◆ pxenv_tftp_close()

PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE * tftp_close)
static

TFTP CLOSE.

Parameters
tftp_closePointer to a struct s_PXENV_TFTP_CLOSE
Return values
PXENV_EXIT_SUCCESSFile was closed successfully
PXENV_EXIT_FAILUREFile was not closed
s_PXENV_TFTP_CLOSE::StatusPXE status code
Exceptions
None-

Close a connection previously opened with pxenv_tftp_open(). You must have previously opened a connection with pxenv_tftp_open().

On x86, you must set the s_PXE::StatusCallout field to a nonzero value before calling this function in protected mode. You cannot call this function with a 32-bit stack segment. (See the relevant implementation note for more details.)

Definition at line 303 of file pxe_tftp.c.

303 {
304 DBG ( "PXENV_TFTP_CLOSE" );
305
306 pxe_tftp_close ( &pxe_tftp, 0 );
308 return PXENV_EXIT_SUCCESS;
309}
#define PXENV_STATUS_SUCCESS
Definition pxe_error.h:19
static void tftp_close(struct tftp_request *tftp, int rc)
Terminate download.
Definition tftp.c:1061

References DBG, pxe_tftp, pxe_tftp_close(), PXENV_EXIT_SUCCESS, PXENV_STATUS_SUCCESS, and tftp_close().

◆ pxenv_tftp_read()

PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ * tftp_read)
static

TFTP READ.

Parameters
tftp_readPointer to a struct s_PXENV_TFTP_READ
s_PXENV_TFTP_READ::BufferAddress of data buffer
Return values
PXENV_EXIT_SUCCESSData was read successfully
PXENV_EXIT_FAILUREData was not read
s_PXENV_TFTP_READ::StatusPXE status code
s_PXENV_TFTP_READ::PacketNumberTFTP packet number
s_PXENV_TFTP_READ::BufferSizeLength of data written into buffer

Reads a single packet from a connection previously opened with pxenv_tftp_open() into the data buffer pointed to by s_PXENV_TFTP_READ::Buffer. You must have previously opened a connection with pxenv_tftp_open(). The data written into s_PXENV_TFTP_READ::Buffer is just the file data; the various network headers have already been removed.

The buffer must be large enough to contain a packet of the size negotiated via the s_PXENV_TFTP_OPEN::PacketSize field in the pxenv_tftp_open() call. It is worth noting that the PXE specification does not require the caller to fill in s_PXENV_TFTP_READ::BufferSize before calling pxenv_tftp_read(), so the PXE stack is free to ignore whatever value the caller might place there and just assume that the buffer is large enough. That said, it may be worth the caller always filling in s_PXENV_TFTP_READ::BufferSize to guard against PXE stacks that mistake it for an input parameter.

The length of the TFTP data packet will be returned via s_PXENV_TFTP_READ::BufferSize. If this length is less than the blksize negotiated via s_PXENV_TFTP_OPEN::PacketSize in the call to pxenv_tftp_open(), this indicates that the block is the last block in the file. Note that zero is a valid length for s_PXENV_TFTP_READ::BufferSize, and will occur when the length of the file is a multiple of the blksize.

The PXE specification doesn't actually state that calls to pxenv_tftp_read() will return the data packets in strict sequential order, though most PXE stacks will probably do so. The sequence number of the packet will be returned in s_PXENV_TFTP_READ::PacketNumber. The first packet in the file has a sequence number of one, not zero.

To guard against flawed PXE stacks, the caller should probably set s_PXENV_TFTP_READ::PacketNumber to one less than the expected returned value (i.e. set it to zero for the first call to pxenv_tftp_read() and then re-use the returned s_PXENV_TFTP_READ parameter block for subsequent calls without modifying s_PXENV_TFTP_READ::PacketNumber between calls). The caller should also guard against potential problems caused by flawed implementations returning the occasional duplicate packet, by checking that the value returned in s_PXENV_TFTP_READ::PacketNumber is as expected (i.e. one greater than that returned from the previous call to pxenv_tftp_read()).

On x86, you must set the s_PXE::StatusCallout field to a nonzero value before calling this function in protected mode. You cannot call this function with a 32-bit stack segment. (See the relevant implementation note for more details.)

Definition at line 372 of file pxe_tftp.c.

372 {
373 int rc;
374
375 DBG ( "PXENV_TFTP_READ to %04x:%04x",
376 tftp_read->Buffer.segment, tftp_read->Buffer.offset );
377
378 /* Read single block into buffer */
379 pxe_tftp.buffer = real_to_virt ( tftp_read->Buffer.segment,
380 tftp_read->Buffer.offset );
381 pxe_tftp.size = pxe_tftp.blksize;
382 pxe_tftp.start = pxe_tftp.offset;
383 while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
384 ( pxe_tftp.offset == pxe_tftp.start ) )
385 step();
386 pxe_tftp.buffer = NULL;
387 tftp_read->BufferSize = ( pxe_tftp.offset - pxe_tftp.start );
388 tftp_read->PacketNumber = ++pxe_tftp.blkidx;
389
390 /* EINPROGRESS is normal if we haven't reached EOF yet */
391 if ( rc == -EINPROGRESS )
392 rc = 0;
393
394 tftp_read->Status = PXENV_STATUS ( rc );
396}
static __always_inline void * real_to_virt(unsigned int segment, unsigned int offset)
Convert segment:offset address to virtual address.
Definition realmode.h:77
UINT16_t PacketNumber
TFTP packet number.
Definition pxe_api.h:625
SEGOFF16_t Buffer
Address of data buffer.
Definition pxe_api.h:627
UINT16_t BufferSize
Size of data buffer.
Definition pxe_api.h:626
PXENV_STATUS_t Status
PXE status code.
Definition pxe_api.h:624

References s_PXENV_TFTP_READ::Buffer, s_PXENV_TFTP_READ::BufferSize, DBG, EINPROGRESS, NULL, s_PXENV_TFTP_READ::PacketNumber, pxe_tftp, PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS, rc, real_to_virt(), s_PXENV_TFTP_READ::Status, and step().

◆ pxenv_tftp_read_file()

PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE * tftp_read_file)

TFTP/MTFTP read file.

Parameters
tftp_read_filePointer to a struct s_PXENV_TFTP_READ_FILE
s_PXENV_TFTP_READ_FILE::FileNameFile name
s_PXENV_TFTP_READ_FILE::BufferSizeSize of the receive buffer
s_PXENV_TFTP_READ_FILE::BufferAddress of the receive buffer
s_PXENV_TFTP_READ_FILE::ServerIPAddressTFTP server IP address
s_PXENV_TFTP_READ_FILE::GatewayIPAddressRelay agent IP address
s_PXENV_TFTP_READ_FILE::McastIPAddressFile's multicast IP address
s_PXENV_TFTP_READ_FILE::TFTPClntPortClient multicast UDP port
s_PXENV_TFTP_READ_FILE::TFTPSrvPortServer multicast UDP port
s_PXENV_TFTP_READ_FILE::TFTPOpenTimeOutTime to wait for first packet
s_PXENV_TFTP_READ_FILE::TFTPReopenDelayMTFTP inactivity timeout
Return values
PXENV_EXIT_SUCCESSFile downloaded successfully
PXENV_EXIT_FAILUREFile not downloaded
s_PXENV_TFTP_READ_FILE::StatusPXE status code
s_PXENV_TFTP_READ_FILE::BufferSizeLength of downloaded file

Downloads an entire file via either TFTP or MTFTP into the buffer pointed to by s_PXENV_TFTP_READ_FILE::Buffer.

The PXE specification does not make it clear how the caller requests that MTFTP be used rather than TFTP (or vice versa). One reasonable guess is that setting s_PXENV_TFTP_READ_FILE::McastIPAddress to 0.0.0.0 would cause TFTP to be used instead of MTFTP, though it is conceivable that some PXE stacks would interpret that as "use the DHCP-provided multicast IP address" instead. Some PXE stacks will not implement MTFTP at all, and will always use TFTP.

It is not specified whether or not s_PXENV_TFTP_READ_FILE::TFTPSrvPort will be used as the TFTP server port for TFTP (rather than MTFTP) downloads. Callers should assume that the only way to access a TFTP server on a non-standard port is to use pxenv_tftp_open() and pxenv_tftp_read().

If s_PXENV_TFTP_READ_FILE::GatewayIPAddress is 0.0.0.0, normal IP routing will take place. See the relevant implementation note for more details.

It is interesting to note that s_PXENV_TFTP_READ_FILE::Buffer is an ADDR32_t type, i.e. nominally a flat physical address. Some PXE NBPs (e.g. NTLDR) are known to call pxenv_tftp_read_file() in real mode with s_PXENV_TFTP_READ_FILE::Buffer set to an address above 1MB. This means that PXE stacks must be prepared to write to areas outside base memory. Exactly how this is to be achieved is not specified, though using INT 15,87 is as close to a standard method as any, and should probably be used. Switching to protected-mode in order to access high memory will fail if pxenv_tftp_read_file() is called in V86 mode; it is reasonably to expect that a V86 monitor would intercept the relatively well-defined INT 15,87 if it wants the PXE stack to be able to write to high memory.

Things get even more interesting if pxenv_tftp_read_file() is called in protected mode, because there is then absolutely no way for the PXE stack to write to an absolute physical address. You can't even get around the problem by creating a special "access everything" segment in the s_PXE data structure, because the #SEGDESC_t descriptors are limited to 64kB in size.

Previous versions of the PXE specification (e.g. WfM 1.1a) provide a separate API call, pxenv_tftp_read_file_pmode(), specifically to work around this problem. The s_PXENV_TFTP_READ_FILE_PMODE parameter block splits s_PXENV_TFTP_READ_FILE::Buffer into s_PXENV_TFTP_READ_FILE_PMODE::BufferSelector and s_PXENV_TFTP_READ_FILE_PMODE::BufferOffset, i.e. it provides a protected-mode segment:offset address for the data buffer. This API call is no longer present in version 2.1 of the PXE specification.

Etherboot makes the assumption that s_PXENV_TFTP_READ_FILE::Buffer is an offset relative to the caller's data segment, when pxenv_tftp_read_file() is called in protected mode.

On x86, you must set the s_PXE::StatusCallout field to a nonzero value before calling this function in protected mode. You cannot call this function with a 32-bit stack segment. (See the relevant implementation note for more details.)

Definition at line 478 of file pxe_tftp.c.

479 {
480 int rc;
481
482 DBG ( "PXENV_TFTP_READ_FILE to %08x+%x", tftp_read_file->Buffer,
483 tftp_read_file->BufferSize );
484
485 /* Open TFTP file */
486 if ( ( rc = pxe_tftp_open ( tftp_read_file->ServerIPAddress, 0,
487 tftp_read_file->FileName, 0 ) ) != 0 ) {
488 tftp_read_file->Status = PXENV_STATUS ( rc );
489 return PXENV_EXIT_FAILURE;
490 }
491
492 /* Read entire file */
493 pxe_tftp.buffer = phys_to_virt ( tftp_read_file->Buffer );
494 pxe_tftp.size = tftp_read_file->BufferSize;
495 while ( ( rc = pxe_tftp.rc ) == -EINPROGRESS )
496 step();
497 pxe_tftp.buffer = NULL;
498 tftp_read_file->BufferSize = pxe_tftp.max_offset;
499
500 /* Close TFTP file */
502
503 tftp_read_file->Status = PXENV_STATUS ( rc );
505}
IP4_t ServerIPAddress
TFTP server IP address.
Definition pxe_api.h:650
UINT8_t FileName[128]
File name.
Definition pxe_api.h:647
ADDR32_t Buffer
Address of data buffer.
Definition pxe_api.h:649
PXENV_STATUS_t Status
PXE status code.
Definition pxe_api.h:646
UINT32_t BufferSize
Size of data buffer.
Definition pxe_api.h:648

References s_PXENV_TFTP_READ_FILE::Buffer, s_PXENV_TFTP_READ_FILE::BufferSize, DBG, EINPROGRESS, s_PXENV_TFTP_READ_FILE::FileName, NULL, pxe_tftp, pxe_tftp_close(), pxe_tftp_open(), PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS, rc, s_PXENV_TFTP_READ_FILE::ServerIPAddress, s_PXENV_TFTP_READ_FILE::Status, and step().

Referenced by pxenv_restart_tftp().

◆ pxenv_tftp_get_fsize()

PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE * tftp_get_fsize)
static

TFTP GET FILE SIZE.

Parameters
tftp_get_fsizePointer to a struct s_PXENV_TFTP_GET_FSIZE
s_PXENV_TFTP_GET_FSIZE::ServerIPAddressTFTP server IP address
s_PXENV_TFTP_GET_FSIZE::GatewayIPAddressRelay agent IP address
s_PXENV_TFTP_GET_FSIZE::FileNameFile name
Return values
PXENV_EXIT_SUCCESSFile size was determined successfully
PXENV_EXIT_FAILUREFile size was not determined
s_PXENV_TFTP_GET_FSIZE::StatusPXE status code
s_PXENV_TFTP_GET_FSIZE::FileSizeFile size

Determine the size of a file on a TFTP server. This uses the "tsize" TFTP option, and so will not work with a TFTP server that does not support TFTP options, or that does not support the "tsize" option.

The PXE specification states that this API call will not open a TFTP connection for subsequent use with pxenv_tftp_read(). (This is somewhat daft, since the only way to obtain the file size via the "tsize" option involves issuing a TFTP open request, but that's life.)

You cannot call pxenv_tftp_get_fsize() while a TFTP or UDP connection is open.

If s_PXENV_TFTP_GET_FSIZE::GatewayIPAddress is 0.0.0.0, normal IP routing will take place. See the relevant implementation note for more details.

On x86, you must set the s_PXE::StatusCallout field to a nonzero value before calling this function in protected mode. You cannot call this function with a 32-bit stack segment. (See the relevant implementation note for more details.)

Note
There is no way to specify the TFTP server port with this API call. Though you can open a file using a non-standard TFTP server port (via s_PXENV_TFTP_OPEN::TFTPPort or, potentially, s_PXENV_TFTP_READ_FILE::TFTPSrvPort), you can only get the size of a file from a TFTP server listening on the standard TFTP port. "Consistency" is not a word in Intel's vocabulary.

Definition at line 549 of file pxe_tftp.c.

550 {
551 int rc;
552
553 DBG ( "PXENV_TFTP_GET_FSIZE" );
554
555 /* Open TFTP file */
556 if ( ( rc = pxe_tftp_open ( tftp_get_fsize->ServerIPAddress, 0,
557 tftp_get_fsize->FileName, 0 ) ) != 0 ) {
558 tftp_get_fsize->Status = PXENV_STATUS ( rc );
559 return PXENV_EXIT_FAILURE;
560 }
561
562 /* Wait for initial seek to arrive, and record size */
563 while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
564 ( pxe_tftp.max_offset == 0 ) ) {
565 step();
566 }
567 tftp_get_fsize->FileSize = pxe_tftp.max_offset;
568 DBG ( " fsize=%d", tftp_get_fsize->FileSize );
569
570 /* EINPROGRESS is normal; we don't wait for the whole transfer */
571 if ( rc == -EINPROGRESS )
572 rc = 0;
573
574 /* Close TFTP file */
576
577 tftp_get_fsize->Status = PXENV_STATUS ( rc );
579}
UINT32_t FileSize
Size of the file.
Definition pxe_api.h:693
PXENV_STATUS_t Status
PXE status code.
Definition pxe_api.h:689
UINT8_t FileName[128]
File name.
Definition pxe_api.h:692
IP4_t ServerIPAddress
TFTP server IP address.
Definition pxe_api.h:690

References DBG, EINPROGRESS, s_PXENV_TFTP_GET_FSIZE::FileName, s_PXENV_TFTP_GET_FSIZE::FileSize, pxe_tftp, pxe_tftp_close(), pxe_tftp_open(), PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS, rc, s_PXENV_TFTP_GET_FSIZE::ServerIPAddress, s_PXENV_TFTP_GET_FSIZE::Status, and step().

Variable Documentation

◆ pxe_tftp_xfer_ops

struct interface_operation pxe_tftp_xfer_ops[]
static
Initial value:
= {
}
void intf_close(struct interface *intf, int rc)
Close an object interface.
Definition interface.c:250
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition interface.h:33
static int pxe_tftp_xfer_deliver(struct pxe_tftp_connection *pxe_tftp, struct io_buffer *iobuf, struct xfer_metadata *meta)
Receive new data.
Definition pxe_tftp.c:98
static size_t pxe_tftp_xfer_window(struct pxe_tftp_connection *pxe_tftp)
Check flow control window.
Definition pxe_tftp.c:85
A PXE TFTP connection.
Definition pxe_tftp.c:47
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition xfer.c:195

PXE TFTP connection interface operations.

Definition at line 143 of file pxe_tftp.c.

◆ pxe_tftp_xfer_desc

struct interface_descriptor pxe_tftp_xfer_desc
static
Initial value:
=
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
Definition interface.h:81
static struct interface_operation pxe_tftp_xfer_ops[]
PXE TFTP connection interface operations.
Definition pxe_tftp.c:143

PXE TFTP connection interface descriptor.

Definition at line 152 of file pxe_tftp.c.

Referenced by pxe_tftp_open().

◆ pxe_tftp

struct pxe_tftp_connection pxe_tftp
static
Initial value:
= {
}
#define INTF_INIT(descriptor)
Initialise a static object interface.
Definition interface.h:218

The PXE TFTP connection.

Definition at line 156 of file pxe_tftp.c.

156 {
157 .xfer = INTF_INIT ( pxe_tftp_xfer_desc ),
158};

Referenced by pxe_tftp_close(), pxe_tftp_open(), pxe_tftp_xfer_deliver(), pxe_tftp_xfer_window(), pxenv_tftp_close(), pxenv_tftp_get_fsize(), pxenv_tftp_open(), pxenv_tftp_read(), pxenv_tftp_read_file(), and REQUIRE_OBJECT().

◆ __pxe_api_call

struct pxe_api_call pxe_tftp_api [] __pxe_api_call
Initial value:
= {
}
#define PXENV_TFTP_CLOSE
PXE API function code for pxenv_tftp_close()
Definition pxe_api.h:601
#define PXENV_TFTP_GET_FSIZE
PXE API function code for pxenv_tftp_get_fsize()
Definition pxe_api.h:685
#define PXENV_TFTP_OPEN
PXE API function code for pxenv_tftp_open()
Definition pxe_api.h:571
#define PXENV_TFTP_READ_FILE
PXE API function code for pxenv_tftp_read_file()
Definition pxe_api.h:642
#define PXENV_TFTP_READ
PXE API function code for pxenv_tftp_read()
Definition pxe_api.h:620
#define PXE_API_CALL(_opcode, _entry, _params_type)
Define a PXE API call.
Definition pxe.h:106
static PXENV_EXIT_t pxenv_tftp_read(struct s_PXENV_TFTP_READ *tftp_read)
TFTP READ.
Definition pxe_tftp.c:372
static PXENV_EXIT_t pxenv_tftp_close(struct s_PXENV_TFTP_CLOSE *tftp_close)
TFTP CLOSE.
Definition pxe_tftp.c:303
PXENV_EXIT_t pxenv_tftp_read_file(struct s_PXENV_TFTP_READ_FILE *tftp_read_file)
TFTP/MTFTP read file.
Definition pxe_tftp.c:478
static PXENV_EXIT_t pxenv_tftp_get_fsize(struct s_PXENV_TFTP_GET_FSIZE *tftp_get_fsize)
TFTP GET FILE SIZE.
Definition pxe_tftp.c:549
static PXENV_EXIT_t pxenv_tftp_open(struct s_PXENV_TFTP_OPEN *tftp_open)
TFTP OPEN.
Definition pxe_tftp.c:252
Parameter block for pxenv_tftp_close()
Definition pxe_api.h:604
Parameter block for pxenv_tftp_get_fsize()
Definition pxe_api.h:688
Parameter block for pxenv_tftp_open()
Definition pxe_api.h:574
Parameter block for pxenv_tftp_read_file()
Definition pxe_api.h:645
Parameter block for pxenv_tftp_read()
Definition pxe_api.h:623

PXE TFTP API.

Definition at line 582 of file pxe_tftp.c.