Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[tftp] Temporary fix for conveying TFTP block size to callers
pxe_tftp.c assumes that the first seek on its data-transfer interface
represents the block size.  Apart from being an ugly hack, this will
also screw up file size calculation for files smaller than one block.

The proper solution would be to extend the data-transfer interface to
support the reporting of stat()-like data.  This is not going to
happen until the cost of adding interface methods is reduced (a fix I
have planned since June 2008).

In the meantime, abuse the xfer_window() method to return the block
size, since it is not being used for anything else and is vaguely
justifiable.

Astonishingly, having returned the incorrect TFTP blocksize via
PXENV_TFTP_OPEN for almost a year seems not to have affected any of
the test cases run during that time; this bug was found only when
someone tried running the heavily-patched version of pxegrub found in
OpenSolaris.
  • Loading branch information
Michael Brown committed Jan 27, 2009
1 parent 027c72e commit 1284773
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 8 deletions.
11 changes: 4 additions & 7 deletions src/arch/i386/interface/pxe/pxe_tftp.c
Expand Up @@ -113,12 +113,6 @@ static int pxe_tftp_xfer_deliver_iob ( struct xfer_interface *xfer __unused,
/* Calculate new buffer position */
pxe_tftp.offset += len;

/* Mildly ugly hack; assume that the first non-zero seek
* indicates the block size.
*/
if ( pxe_tftp.blksize == 0 )
pxe_tftp.blksize = pxe_tftp.offset;

/* Record maximum offset as the file size */
if ( pxe_tftp.max_offset < pxe_tftp.offset )
pxe_tftp.max_offset = pxe_tftp.offset;
Expand Down Expand Up @@ -265,10 +259,12 @@ PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) {

/* Wait for OACK to arrive so that we have the block size */
while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) &&
( pxe_tftp.blksize == 0 ) ) {
( pxe_tftp.max_offset == 0 ) ) {
step();
}
pxe_tftp.blksize = xfer_window ( &pxe_tftp.xfer );
tftp_open->PacketSize = pxe_tftp.blksize;
DBG ( " blksize=%d", tftp_open->PacketSize );

/* EINPROGRESS is normal; we don't wait for the whole transfer */
if ( rc == -EINPROGRESS )
Expand Down Expand Up @@ -571,6 +567,7 @@ PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE
step();
}
tftp_get_fsize->FileSize = pxe_tftp.max_offset;
DBG ( " fsize=%d", tftp_get_fsize->FileSize );

/* EINPROGRESS is normal; we don't wait for the whole transfer */
if ( rc == -EINPROGRESS )
Expand Down
20 changes: 19 additions & 1 deletion src/net/udp/tftp.c
Expand Up @@ -986,11 +986,29 @@ static void tftp_xfer_close ( struct xfer_interface *xfer, int rc ) {
tftp_done ( tftp, rc );
}

/**
* Check flow control window
*
* @v xfer Data transfer interface
* @ret len Length of window
*/
static size_t tftp_xfer_window ( struct xfer_interface *xfer ) {
struct tftp_request *tftp =
container_of ( xfer, struct tftp_request, xfer );

/* We abuse this data-xfer method to convey the blocksize to
* the caller. This really should be done using some kind of
* stat() method, but we don't yet have the facility to do
* that.
*/
return tftp->blksize;
}

/** TFTP data transfer interface operations */
static struct xfer_interface_operations tftp_xfer_operations = {
.close = tftp_xfer_close,
.vredirect = ignore_xfer_vredirect,
.window = unlimited_xfer_window,
.window = tftp_xfer_window,
.alloc_iob = default_xfer_alloc_iob,
.deliver_iob = xfer_deliver_as_raw,
.deliver_raw = ignore_xfer_deliver_raw,
Expand Down

0 comments on commit 1284773

Please sign in to comment.