iPXE
Data Structures | Functions | Variables
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. More...
 
static size_t pxe_tftp_xfer_window (struct pxe_tftp_connection *pxe_tftp)
 Check flow control window. More...
 
static int pxe_tftp_xfer_deliver (struct pxe_tftp_connection *pxe_tftp, struct io_buffer *iobuf, struct xfer_metadata *meta)
 Receive new data. More...
 
static int pxe_tftp_open (IP4_t ipaddress, UDP_PORT_t port, UINT8_t *filename, UINT16_t blksize)
 Open PXE TFTP connection. More...
 
static PXENV_EXIT_t pxenv_tftp_open (struct s_PXENV_TFTP_OPEN *tftp_open)
 TFTP OPEN. More...
 
static PXENV_EXIT_t pxenv_tftp_close (struct s_PXENV_TFTP_CLOSE *tftp_close)
 TFTP CLOSE. More...
 
static PXENV_EXIT_t pxenv_tftp_read (struct s_PXENV_TFTP_READ *tftp_read)
 TFTP READ. More...
 
PXENV_EXIT_t pxenv_tftp_read_file (struct s_PXENV_TFTP_READ_FILE *tftp_read_file)
 TFTP/MTFTP read file. More...
 
static PXENV_EXIT_t pxenv_tftp_get_fsize (struct s_PXENV_TFTP_GET_FSIZE *tftp_get_fsize)
 TFTP GET FILE SIZE. More...
 

Variables

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

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()

static 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  {
76  pxe_tftp->rc = rc;
77 }
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
Definition: interface.c:278
struct interface xfer
Data transfer interface.
Definition: pxe_tftp.c:49
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:156
int rc
Overall return status code.
Definition: pxe_tftp.c:65

References intf_shutdown(), pxe_tftp, pxe_tftp_connection::rc, rc, and pxe_tftp_connection::xfer.

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()

static 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 }
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:156
size_t blksize
Block size.
Definition: pxe_tftp.c:61

References pxe_tftp_connection::blksize, and pxe_tftp.

◆ pxe_tftp_xfer_deliver()

static 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)",
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 {
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 */
133 
134  /* Terminate transfer on error */
135  if ( rc != 0 )
137 
138  free_iob ( iobuf );
139  return rc;
140 }
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define XFER_FL_ABS_OFFSET
Offset is absolute.
Definition: xfer.h:47
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:152
size_t size
Size of data buffer.
Definition: pxe_tftp.c:53
void * memcpy(void *dest, const void *src, size_t len) __nonnull
ring len
Length.
Definition: dwmac.h:231
static void pxe_tftp_close(struct pxe_tftp_connection *pxe_tftp, int rc)
Close PXE TFTP connection.
Definition: pxe_tftp.c:74
size_t max_offset
Maximum file position.
Definition: pxe_tftp.c:59
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:156
void * buffer
Data buffer.
Definition: pxe_tftp.c:51
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:159
size_t start
Starting offset of data buffer.
Definition: pxe_tftp.c:55
#define ENOBUFS
No buffer space available.
Definition: errno.h:498
void * data
Start of data.
Definition: iobuf.h:52
uint8_t meta
Metadata flags.
Definition: ena.h:14
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
size_t offset
File position.
Definition: pxe_tftp.c:57

References pxe_tftp_connection::buffer, io_buffer::data, DBG, ENOBUFS, free_iob(), iob_len(), len, pxe_tftp_connection::max_offset, memcpy(), meta, pxe_tftp_connection::offset, pxe_tftp, pxe_tftp_close(), rc, pxe_tftp_connection::size, pxe_tftp_connection::start, and XFER_FL_ABS_OFFSET.

◆ pxe_tftp_open()

static 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 ) );
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 }
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
struct uri * pxe_uri(struct sockaddr *sa_server, const char *filename)
Construct URI from server address and filename.
Definition: uri.c:808
int xfer_open_uri(struct interface *intf, struct uri *uri)
Open URI.
Definition: open.c:67
IPv4 socket address.
Definition: in.h:84
#define ntohs(value)
Definition: byteswap.h:136
#define ENOMEM
Not enough space.
Definition: errno.h:534
static struct interface_descriptor pxe_tftp_xfer_desc
PXE TFTP connection interface descriptor.
Definition: pxe_tftp.c:152
u8 port
Port number.
Definition: CIB_PRM.h:31
struct interface xfer
Data transfer interface.
Definition: pxe_tftp.c:49
struct sockaddr sa
Definition: syslog.c:56
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:156
#define EINPROGRESS
Operation in progress.
Definition: errno.h:418
Generalized socket address structure.
Definition: socket.h:96
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
int rc
Overall return status code.
Definition: pxe_tftp.c:65
const char * sock_ntoa(struct sockaddr *sa)
Transcribe socket address.
Definition: socket.c:42
#define TFTP_DEFAULT_BLKSIZE
Default TFTP data block size.
Definition: tftp.h:15
A Uniform Resource Identifier.
Definition: uri.h:64
uint32_t blksize
Cipher block size.
Definition: pccrr.h:14
struct sockaddr_in sin
Definition: syslog.c:58
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
Definition: interface.h:203
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
#define AF_INET
IPv4 Internet addresses.
Definition: socket.h:63
size_t blksize
Block size.
Definition: pxe_tftp.c:61
void * memset(void *dest, int character, size_t len) __nonnull

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

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

◆ pxenv_tftp_open()

static 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  }
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 }
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
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define PXENV_EXIT_FAILURE
An error occurred.
Definition: pxe_types.h:46
size_t xfer_window(struct interface *intf)
Check flow control window.
Definition: xfer.c:116
struct interface xfer
Data transfer interface.
Definition: pxe_tftp.c:49
static int tftp_open(struct interface *xfer, struct uri *uri)
Initiate TFTP download.
Definition: tftp.c:1148
static void pxe_tftp_close(struct pxe_tftp_connection *pxe_tftp, int rc)
Close PXE TFTP connection.
Definition: pxe_tftp.c:74
size_t max_offset
Maximum file position.
Definition: pxe_tftp.c:59
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:156
#define EINPROGRESS
Operation in progress.
Definition: errno.h:418
int rc
Overall return status code.
Definition: pxe_tftp.c:65
#define PXENV_EXIT_SUCCESS
No error occurred.
Definition: pxe_types.h:45
void step(void)
Single-step a single process.
Definition: process.c:98
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
#define PXENV_STATUS(rc)
Derive PXENV_STATUS code from iPXE error number.
Definition: pxe_error.h:121
size_t blksize
Block size.
Definition: pxe_tftp.c:61

References pxe_tftp_connection::blksize, DBG, EINPROGRESS, pxe_tftp_connection::max_offset, pxe_tftp, pxe_tftp_close(), pxe_tftp_open(), PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS, pxe_tftp_connection::rc, rc, step(), tftp_open(), pxe_tftp_connection::xfer, and xfer_window().

◆ pxenv_tftp_close()

static 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 }
static void pxe_tftp_close(struct pxe_tftp_connection *pxe_tftp, int rc)
Close PXE TFTP connection.
Definition: pxe_tftp.c:74
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:156
static void tftp_close(struct tftp_request *tftp, int rc)
Terminate download.
Definition: tftp.c:1060
#define PXENV_EXIT_SUCCESS
No error occurred.
Definition: pxe_types.h:45
#define PXENV_STATUS_SUCCESS
Definition: pxe_error.h:19
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498

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

◆ pxenv_tftp_read()

static 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 );
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 }
UINT16_t PacketNumber
TFTP packet number.
Definition: pxe_api.h:625
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define PXENV_EXIT_FAILURE
An error occurred.
Definition: pxe_types.h:46
size_t size
Size of data buffer.
Definition: pxe_tftp.c:53
unsigned int blkidx
Block index.
Definition: pxe_tftp.c:63
PXENV_STATUS_t Status
PXE status code.
Definition: pxe_api.h:624
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 BufferSize
Size of data buffer.
Definition: pxe_api.h:626
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:156
#define EINPROGRESS
Operation in progress.
Definition: errno.h:418
void * buffer
Data buffer.
Definition: pxe_tftp.c:51
int rc
Overall return status code.
Definition: pxe_tftp.c:65
#define PXENV_EXIT_SUCCESS
No error occurred.
Definition: pxe_types.h:45
size_t start
Starting offset of data buffer.
Definition: pxe_tftp.c:55
void step(void)
Single-step a single process.
Definition: process.c:98
SEGOFF16_t Buffer
Address of data buffer.
Definition: pxe_api.h:627
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
#define PXENV_STATUS(rc)
Derive PXENV_STATUS code from iPXE error number.
Definition: pxe_error.h:121
size_t blksize
Block size.
Definition: pxe_tftp.c:61
size_t offset
File position.
Definition: pxe_tftp.c:57

References pxe_tftp_connection::blkidx, pxe_tftp_connection::blksize, pxe_tftp_connection::buffer, s_PXENV_TFTP_READ::Buffer, s_PXENV_TFTP_READ::BufferSize, DBG, EINPROGRESS, NULL, pxe_tftp_connection::offset, s_PXENV_TFTP_READ::PacketNumber, pxe_tftp, PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS, pxe_tftp_connection::rc, rc, real_to_virt(), pxe_tftp_connection::size, pxe_tftp_connection::start, 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 */
501  pxe_tftp_close ( &pxe_tftp, rc );
502 
503  tftp_read_file->Status = PXENV_STATUS ( rc );
505 }
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
IP4_t ServerIPAddress
TFTP server IP address.
Definition: pxe_api.h:650
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define PXENV_EXIT_FAILURE
An error occurred.
Definition: pxe_types.h:46
size_t size
Size of data buffer.
Definition: pxe_tftp.c:53
UINT32_t BufferSize
Size of data buffer.
Definition: pxe_api.h:648
UINT8_t FileName[128]
File name.
Definition: pxe_api.h:647
static void pxe_tftp_close(struct pxe_tftp_connection *pxe_tftp, int rc)
Close PXE TFTP connection.
Definition: pxe_tftp.c:74
size_t max_offset
Maximum file position.
Definition: pxe_tftp.c:59
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:156
#define EINPROGRESS
Operation in progress.
Definition: errno.h:418
void * buffer
Data buffer.
Definition: pxe_tftp.c:51
int rc
Overall return status code.
Definition: pxe_tftp.c:65
PXENV_STATUS_t Status
PXE status code.
Definition: pxe_api.h:646
#define PXENV_EXIT_SUCCESS
No error occurred.
Definition: pxe_types.h:45
void step(void)
Single-step a single process.
Definition: process.c:98
ADDR32_t Buffer
Address of data buffer.
Definition: pxe_api.h:649
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
#define PXENV_STATUS(rc)
Derive PXENV_STATUS code from iPXE error number.
Definition: pxe_error.h:121

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

Referenced by pxenv_restart_tftp().

◆ pxenv_tftp_get_fsize()

static 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 */
575  pxe_tftp_close ( &pxe_tftp, rc );
576 
577  tftp_get_fsize->Status = PXENV_STATUS ( rc );
579 }
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
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define PXENV_EXIT_FAILURE
An error occurred.
Definition: pxe_types.h:46
IP4_t ServerIPAddress
TFTP server IP address.
Definition: pxe_api.h:690
static void pxe_tftp_close(struct pxe_tftp_connection *pxe_tftp, int rc)
Close PXE TFTP connection.
Definition: pxe_tftp.c:74
size_t max_offset
Maximum file position.
Definition: pxe_tftp.c:59
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:156
#define EINPROGRESS
Operation in progress.
Definition: errno.h:418
UINT8_t FileName[128]
File name.
Definition: pxe_api.h:692
int rc
Overall return status code.
Definition: pxe_tftp.c:65
#define PXENV_EXIT_SUCCESS
No error occurred.
Definition: pxe_types.h:45
PXENV_STATUS_t Status
PXE status code.
Definition: pxe_api.h:689
void step(void)
Single-step a single process.
Definition: process.c:98
UINT32_t FileSize
Size of the file.
Definition: pxe_api.h:693
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
#define PXENV_STATUS(rc)
Derive PXENV_STATUS code from iPXE error number.
Definition: pxe_error.h:121

References DBG, EINPROGRESS, s_PXENV_TFTP_GET_FSIZE::FileName, s_PXENV_TFTP_GET_FSIZE::FileSize, pxe_tftp_connection::max_offset, pxe_tftp, pxe_tftp_close(), pxe_tftp_open(), PXENV_EXIT_FAILURE, PXENV_EXIT_SUCCESS, PXENV_STATUS, pxe_tftp_connection::rc, 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:249
static size_t pxe_tftp_xfer_window(struct pxe_tftp_connection *pxe_tftp)
Check flow control window.
Definition: pxe_tftp.c:85
size_t xfer_window(struct interface *intf)
Check flow control window.
Definition: xfer.c:116
static void pxe_tftp_close(struct pxe_tftp_connection *pxe_tftp, int rc)
Close PXE TFTP connection.
Definition: pxe_tftp.c:74
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition: interface.h:32
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
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition: xfer.c:194
A PXE TFTP connection.
Definition: pxe_tftp.c:47

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:80
A PXE TFTP connection.
Definition: pxe_tftp.c:47
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:217
static struct interface_descriptor pxe_tftp_xfer_desc
PXE TFTP connection interface descriptor.
Definition: pxe_tftp.c:152

The PXE TFTP connection.

Definition at line 156 of file pxe_tftp.c.

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(), and pxenv_tftp_read_file().

◆ __pxe_api_call

struct pxe_api_call pxe_tftp_api [] __pxe_api_call
Initial value:
= {
}
Parameter block for pxenv_tftp_read()
Definition: pxe_api.h:623
#define PXENV_TFTP_READ
PXE API function code for pxenv_tftp_read()
Definition: pxe_api.h:620
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
#define PXE_API_CALL(_opcode, _entry, _params_type)
Define a PXE API call.
Definition: pxe.h:106
#define PXENV_TFTP_READ_FILE
PXE API function code for pxenv_tftp_read_file()
Definition: pxe_api.h:642
Parameter block for pxenv_tftp_get_fsize()
Definition: pxe_api.h:688
#define PXENV_TFTP_OPEN
PXE API function code for pxenv_tftp_open()
Definition: pxe_api.h:571
Parameter block for pxenv_tftp_close()
Definition: pxe_api.h:604
#define PXENV_TFTP_CLOSE
PXE API function code for pxenv_tftp_close()
Definition: pxe_api.h:601
Parameter block for pxenv_tftp_read_file()
Definition: pxe_api.h:645
Parameter block for pxenv_tftp_open()
Definition: pxe_api.h:574
#define PXENV_TFTP_GET_FSIZE
PXE API function code for pxenv_tftp_get_fsize()
Definition: pxe_api.h:685
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
static PXENV_EXIT_t pxenv_tftp_open(struct s_PXENV_TFTP_OPEN *tftp_open)
TFTP OPEN.
Definition: pxe_tftp.c:252
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

PXE TFTP API.

Definition at line 582 of file pxe_tftp.c.