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/uaccess.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 75 of file pxe_tftp.c.

75  {
77  pxe_tftp->rc = rc;
78 }
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:273
struct interface xfer
Data transfer interface.
Definition: pxe_tftp.c:50
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:158
int rc
Overall return status code.
Definition: pxe_tftp.c:66

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 86 of file pxe_tftp.c.

86  {
87 
88  return pxe_tftp->blksize;
89 }
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:158
size_t blksize
Block size.
Definition: pxe_tftp.c:62

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 99 of file pxe_tftp.c.

101  {
102  size_t len = iob_len ( iobuf );
103  int rc = 0;
104 
105  /* Calculate new buffer position */
106  if ( meta->flags & XFER_FL_ABS_OFFSET )
107  pxe_tftp->offset = 0;
108  pxe_tftp->offset += meta->offset;
109 
110  /* Copy data block to buffer */
111  if ( len == 0 ) {
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)",
116  rc = -ENOBUFS;
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 ) );
122  rc = -ENOBUFS;
123  } else {
125  ( pxe_tftp->offset - pxe_tftp->start ),
126  iobuf->data, len );
127  }
128 
129  /* Calculate new buffer position */
130  pxe_tftp->offset += len;
131 
132  /* Record maximum offset as the file size */
135 
136  /* Terminate transfer on error */
137  if ( rc != 0 )
139 
140  free_iob ( iobuf );
141  return rc;
142 }
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:145
size_t size
Size of data buffer.
Definition: pxe_tftp.c:54
userptr_t buffer
Data buffer.
Definition: pxe_tftp.c:52
static void pxe_tftp_close(struct pxe_tftp_connection *pxe_tftp, int rc)
Close PXE TFTP connection.
Definition: pxe_tftp.c:75
size_t max_offset
Maximum file position.
Definition: pxe_tftp.c:60
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:158
int meta(WINDOW *, bool)
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:151
static __always_inline void copy_to_user(userptr_t dest, off_t dest_off, const void *src, size_t len)
Copy data to user buffer.
Definition: uaccess.h:324
size_t start
Starting offset of data buffer.
Definition: pxe_tftp.c:56
uint32_t len
Length.
Definition: ena.h:14
#define ENOBUFS
No buffer space available.
Definition: errno.h:498
void * data
Start of data.
Definition: iobuf.h:44
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
size_t offset
File position.
Definition: pxe_tftp.c:58

References pxe_tftp_connection::buffer, copy_to_user(), io_buffer::data, DBG, ENOBUFS, free_iob(), iob_len(), len, pxe_tftp_connection::max_offset, 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 171 of file pxe_tftp.c.

172  {
173  union {
174  struct sockaddr sa;
175  struct sockaddr_in sin;
176  } server;
177  struct uri *uri;
178  int rc;
179 
180  /* Reset PXE TFTP connection structure */
181  memset ( &pxe_tftp, 0, sizeof ( pxe_tftp ) );
187 
188  /* Construct URI */
189  memset ( &server, 0, sizeof ( server ) );
190  server.sin.sin_family = AF_INET;
191  server.sin.sin_addr.s_addr = ipaddress;
192  server.sin.sin_port = port;
193  DBG ( " %s", sock_ntoa ( &server.sa ) );
194  if ( port )
195  DBG ( ":%d", ntohs ( port ) );
196  DBG ( ":%s", filename );
197  uri = pxe_uri ( &server.sa, ( ( char * ) filename ) );
198  if ( ! uri ) {
199  DBG ( " could not create URI\n" );
200  return -ENOMEM;
201  }
202 
203  /* Open PXE TFTP connection */
204  if ( ( rc = xfer_open_uri ( &pxe_tftp.xfer, uri ) ) != 0 ) {
205  DBG ( " could not open (%s)\n", strerror ( rc ) );
206  return rc;
207  }
208 
209  return 0;
210 }
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
struct sockaddr sa
Definition: dns.c:68
struct uri * pxe_uri(struct sockaddr *sa_server, const char *filename)
Construct URI from server address and filename.
Definition: uri.c:774
int xfer_open_uri(struct interface *intf, struct uri *uri)
Open URI.
Definition: open.c:66
uint32_t blksize
Block size for this segment.
Definition: pccrc.h:24
IPv4 socket address.
Definition: in.h:82
#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:154
u8 port
Port number.
Definition: CIB_PRM.h:31
struct sockaddr_in sin
Definition: dns.c:70
struct interface xfer
Data transfer interface.
Definition: pxe_tftp.c:50
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:158
#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:66
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:50
#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:173
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
#define AF_INET
IPv4 Internet addresses.
Definition: socket.h:63
size_t blksize
Block size.
Definition: pxe_tftp.c:62
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 254 of file pxe_tftp.c.

254  {
255  int rc;
256 
257  DBG ( "PXENV_TFTP_OPEN" );
258 
259  /* Guard against callers that fail to close before re-opening */
260  pxe_tftp_close ( &pxe_tftp, 0 );
261 
262  /* Open connection */
263  if ( ( rc = pxe_tftp_open ( tftp_open->ServerIPAddress,
264  tftp_open->TFTPPort,
265  tftp_open->FileName,
266  tftp_open->PacketSize ) ) != 0 ) {
267  tftp_open->Status = PXENV_STATUS ( rc );
268  return PXENV_EXIT_FAILURE;
269  }
270 
271  /* Wait for OACK to arrive so that we have the block size */
272  while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
273  ( pxe_tftp.max_offset == 0 ) ) {
274  step();
275  }
277  tftp_open->PacketSize = pxe_tftp.blksize;
278  DBG ( " blksize=%d", tftp_open->PacketSize );
279 
280  /* EINPROGRESS is normal; we don't wait for the whole transfer */
281  if ( rc == -EINPROGRESS )
282  rc = 0;
283 
284  tftp_open->Status = PXENV_STATUS ( rc );
286 }
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:171
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:115
struct interface xfer
Data transfer interface.
Definition: pxe_tftp.c:50
static int tftp_open(struct interface *xfer, struct uri *uri)
Initiate TFTP download.
Definition: tftp.c:1117
static void pxe_tftp_close(struct pxe_tftp_connection *pxe_tftp, int rc)
Close PXE TFTP connection.
Definition: pxe_tftp.c:75
size_t max_offset
Maximum file position.
Definition: pxe_tftp.c:60
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:158
#define EINPROGRESS
Operation in progress.
Definition: errno.h:418
int rc
Overall return status code.
Definition: pxe_tftp.c:66
#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:62

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 305 of file pxe_tftp.c.

305  {
306  DBG ( "PXENV_TFTP_CLOSE" );
307 
308  pxe_tftp_close ( &pxe_tftp, 0 );
310  return PXENV_EXIT_SUCCESS;
311 }
static void pxe_tftp_close(struct pxe_tftp_connection *pxe_tftp, int rc)
Close PXE TFTP connection.
Definition: pxe_tftp.c:75
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:158
static void tftp_close(struct tftp_request *tftp, int rc)
Terminate download.
Definition: tftp.c:1029
#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 374 of file pxe_tftp.c.

374  {
375  int rc;
376 
377  DBG ( "PXENV_TFTP_READ to %04x:%04x",
378  tftp_read->Buffer.segment, tftp_read->Buffer.offset );
379 
380  /* Read single block into buffer */
381  pxe_tftp.buffer = real_to_user ( tftp_read->Buffer.segment,
382  tftp_read->Buffer.offset );
385  while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
386  ( pxe_tftp.offset == pxe_tftp.start ) )
387  step();
389  tftp_read->BufferSize = ( pxe_tftp.offset - pxe_tftp.start );
390  tftp_read->PacketNumber = ++pxe_tftp.blkidx;
391 
392  /* EINPROGRESS is normal if we haven't reached EOF yet */
393  if ( rc == -EINPROGRESS )
394  rc = 0;
395 
396  tftp_read->Status = PXENV_STATUS ( rc );
398 }
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:54
unsigned int blkidx
Block index.
Definition: pxe_tftp.c:64
PXENV_STATUS_t Status
PXE status code.
Definition: pxe_api.h:624
UINT16_t BufferSize
Size of data buffer.
Definition: pxe_api.h:626
userptr_t buffer
Data buffer.
Definition: pxe_tftp.c:52
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:158
#define EINPROGRESS
Operation in progress.
Definition: errno.h:418
int rc
Overall return status code.
Definition: pxe_tftp.c:66
#define PXENV_EXIT_SUCCESS
No error occurred.
Definition: pxe_types.h:45
size_t start
Starting offset of data buffer.
Definition: pxe_tftp.c:56
#define UNULL
Equivalent of NULL for user pointers.
Definition: uaccess.h:36
void step(void)
Single-step a single process.
Definition: process.c:98
SEGOFF16_t Buffer
Address of data buffer.
Definition: pxe_api.h:627
static __always_inline userptr_t real_to_user(unsigned int segment, unsigned int offset)
Convert segment:offset address to user buffer.
Definition: realmode.h:75
#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:62
size_t offset
File position.
Definition: pxe_tftp.c:58

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, 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_user(), pxe_tftp_connection::size, pxe_tftp_connection::start, s_PXENV_TFTP_READ::Status, step(), and UNULL.

◆ 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 480 of file pxe_tftp.c.

481  {
482  int rc;
483 
484  DBG ( "PXENV_TFTP_READ_FILE to %08x+%x", tftp_read_file->Buffer,
485  tftp_read_file->BufferSize );
486 
487  /* Open TFTP file */
488  if ( ( rc = pxe_tftp_open ( tftp_read_file->ServerIPAddress, 0,
489  tftp_read_file->FileName, 0 ) ) != 0 ) {
490  tftp_read_file->Status = PXENV_STATUS ( rc );
491  return PXENV_EXIT_FAILURE;
492  }
493 
494  /* Read entire file */
495  pxe_tftp.buffer = phys_to_user ( tftp_read_file->Buffer );
496  pxe_tftp.size = tftp_read_file->BufferSize;
497  while ( ( rc = pxe_tftp.rc ) == -EINPROGRESS )
498  step();
500  tftp_read_file->BufferSize = pxe_tftp.max_offset;
501 
502  /* Close TFTP file */
503  pxe_tftp_close ( &pxe_tftp, rc );
504 
505  tftp_read_file->Status = PXENV_STATUS ( rc );
507 }
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:171
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
userptr_t phys_to_user(unsigned long phys_addr)
Convert physical address to user pointer.
size_t size
Size of data buffer.
Definition: pxe_tftp.c:54
UINT32_t BufferSize
Size of data buffer.
Definition: pxe_api.h:648
UINT8_t FileName[128]
File name.
Definition: pxe_api.h:647
userptr_t buffer
Data buffer.
Definition: pxe_tftp.c:52
static void pxe_tftp_close(struct pxe_tftp_connection *pxe_tftp, int rc)
Close PXE TFTP connection.
Definition: pxe_tftp.c:75
size_t max_offset
Maximum file position.
Definition: pxe_tftp.c:60
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:158
#define EINPROGRESS
Operation in progress.
Definition: errno.h:418
int rc
Overall return status code.
Definition: pxe_tftp.c:66
PXENV_STATUS_t Status
PXE status code.
Definition: pxe_api.h:646
#define PXENV_EXIT_SUCCESS
No error occurred.
Definition: pxe_types.h:45
#define UNULL
Equivalent of NULL for user pointers.
Definition: uaccess.h:36
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 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, phys_to_user(), 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, step(), and UNULL.

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 551 of file pxe_tftp.c.

552  {
553  int rc;
554 
555  DBG ( "PXENV_TFTP_GET_FSIZE" );
556 
557  /* Open TFTP file */
558  if ( ( rc = pxe_tftp_open ( tftp_get_fsize->ServerIPAddress, 0,
559  tftp_get_fsize->FileName, 0 ) ) != 0 ) {
560  tftp_get_fsize->Status = PXENV_STATUS ( rc );
561  return PXENV_EXIT_FAILURE;
562  }
563 
564  /* Wait for initial seek to arrive, and record size */
565  while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
566  ( pxe_tftp.max_offset == 0 ) ) {
567  step();
568  }
569  tftp_get_fsize->FileSize = pxe_tftp.max_offset;
570  DBG ( " fsize=%d", tftp_get_fsize->FileSize );
571 
572  /* EINPROGRESS is normal; we don't wait for the whole transfer */
573  if ( rc == -EINPROGRESS )
574  rc = 0;
575 
576  /* Close TFTP file */
577  pxe_tftp_close ( &pxe_tftp, rc );
578 
579  tftp_get_fsize->Status = PXENV_STATUS ( rc );
581 }
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:171
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:75
size_t max_offset
Maximum file position.
Definition: pxe_tftp.c:60
static struct pxe_tftp_connection pxe_tftp
The PXE TFTP connection.
Definition: pxe_tftp.c:158
#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:66
#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:244
static size_t pxe_tftp_xfer_window(struct pxe_tftp_connection *pxe_tftp)
Check flow control window.
Definition: pxe_tftp.c:86
size_t xfer_window(struct interface *intf)
Check flow control window.
Definition: xfer.c:115
static void pxe_tftp_close(struct pxe_tftp_connection *pxe_tftp, int rc)
Close PXE TFTP connection.
Definition: pxe_tftp.c:75
#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:99
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition: xfer.c:193
A PXE TFTP connection.
Definition: pxe_tftp.c:48

PXE TFTP connection interface operations.

Definition at line 145 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:65
A PXE TFTP connection.
Definition: pxe_tftp.c:48
static struct interface_operation pxe_tftp_xfer_ops[]
PXE TFTP connection interface operations.
Definition: pxe_tftp.c:145

PXE TFTP connection interface descriptor.

Definition at line 154 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:187
static struct interface_descriptor pxe_tftp_xfer_desc
PXE TFTP connection interface descriptor.
Definition: pxe_tftp.c:154

The PXE TFTP connection.

Definition at line 158 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:480
#define PXE_API_CALL(_opcode, _entry, _params_type)
Define a PXE API call.
Definition: pxe.h:108
#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:374
static PXENV_EXIT_t pxenv_tftp_close(struct s_PXENV_TFTP_CLOSE *tftp_close)
TFTP CLOSE.
Definition: pxe_tftp.c:305
static PXENV_EXIT_t pxenv_tftp_open(struct s_PXENV_TFTP_OPEN *tftp_open)
TFTP OPEN.
Definition: pxe_tftp.c:254
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:551

PXE TFTP API.

Definition at line 584 of file pxe_tftp.c.