#include <gpxe/udp.h>
#include <gpxe/async.h>
#include <gpxe/retry.h>
+#include <gpxe/buffer.h>
#define TFTP_PORT 69 /**< Default TFTP server port */
#define TFTP_DEFAULT_BLKSIZE 512 /**< Default TFTP data block size */
struct udp_connection udp;
/** Filename */
const char *filename;
+ /** Data buffer to fill */
+ struct buffer *buffer;
+ /** Requested data block size
+ *
+ * This is the "blksize" option requested from the TFTP
+ * server. It may or may not be honoured.
+ */
+ unsigned int request_blksize;
- /**
- * Callback function
+ /** Data block size
+ *
+ * This is the "blksize" option negotiated with the TFTP
+ * server. (If the TFTP server does not support TFTP options,
+ * this will default to 512).
+ */
+ unsigned int blksize;
+ /** File size
*
- * @v tftp TFTP connection
- * @v block Block number
- * @v data Data
- * @v len Length of data
+ * This is the value returned in the "tsize" option from the
+ * TFTP server. If the TFTP server does not support the
+ * "tsize" option, this value will be zero.
*/
- void ( * callback ) ( struct tftp_session *tftp, unsigned int block,
- void *data, size_t len );
+ unsigned long tsize;
+
/**
* Transfer ID
*
* (i.e. that no blocks have yet been received).
*/
int state;
- /** Requested data block size
- *
- * This is the "blksize" option requested from the TFTP
- * server. It may or may not be honoured.
- */
- unsigned int request_blksize;
- /** Data block size
- *
- * This is the "blksize" option negotiated with the TFTP
- * server. (If the TFTP server does not support TFTP options,
- * this will default to 512).
- */
- unsigned int blksize;
- /** File size
- *
- * This is the value returned in the "tsize" option from the
- * TFTP server. If the TFTP server does not support the
- * "tsize" option, this value will be zero.
- */
- unsigned long tsize;
/** Asynchronous operation for this session */
struct async_operation aop;
tftp->blksize = strtoul ( value, &end, 10 );
if ( *end ) {
- DBG ( "TFTP %p got invalid blksize \"%s\"\n", tftp, value );
+ DBGC ( tftp, "TFTP %p got invalid blksize \"%s\"\n",
+ tftp, value );
return -EINVAL;
}
- DBG ( "TFTP %p blksize=%d\n", tftp, tftp->blksize );
+ DBGC ( tftp, "TFTP %p blksize=%d\n", tftp, tftp->blksize );
return 0;
}
tftp->tsize = strtoul ( value, &end, 10 );
if ( *end ) {
- DBG ( "TFTP %p got invalid tsize \"%s\"\n", tftp, value );
+ DBGC ( tftp, "TFTP %p got invalid tsize \"%s\"\n",
+ tftp, value );
return -EINVAL;
}
- DBG ( "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
+ DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
return 0;
}
return option->process ( tftp, value );
}
- DBG ( "TFTP %p received unknown option \"%s\" = \"%s\"\n",
- tftp, name, value );
+ DBGC ( tftp, "TFTP %p received unknown option \"%s\" = \"%s\"\n",
+ tftp, name, value );
return -EINVAL;
}
void *data;
void *end;
- DBG ( "TFTP %p requesting \"%s\"\n", tftp, tftp->filename );
+ DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, tftp->filename );
data = rrq->data;
end = ( buf + len );
return udp_send ( &tftp->udp, buf, ( data - buf ) );
overflow:
- DBG ( "TFTP %p RRQ out of space\n", tftp );
+ DBGC ( tftp, "TFTP %p RRQ out of space\n", tftp );
return -ENOBUFS;
}
/* Sanity check */
if ( len < sizeof ( *oack ) ) {
- DBG ( "TFTP %p received underlength OACK packet length %d\n",
- tftp, len );
+ DBGC ( tftp, "TFTP %p received underlength OACK packet "
+ "length %d\n", tftp, len );
return -EINVAL;
}
if ( end[-1] != '\0' ) {
- DBG ( "TFTP %p received OACK missing final NUL\n", tftp );
+ DBGC ( tftp, "TFTP %p received OACK missing final NUL\n",
+ tftp );
return -EINVAL;
}
while ( name < end ) {
value = ( name + strlen ( name ) + 1 );
if ( value == end ) {
- DBG ( "TFTP %p received OACK missing value for option "
- "\"%s\"\n", tftp, name );
+ DBGC ( tftp, "TFTP %p received OACK missing value "
+ "for option \"%s\"\n", tftp, name );
return -EINVAL;
}
if ( ( rc = tftp_process_option ( tftp, name, value ) ) != 0 )
static int tftp_rx_data ( struct tftp_session *tftp, void *buf, size_t len ) {
struct tftp_data *data = buf;
unsigned int block;
+ size_t data_offset;
size_t data_len;
+ int rc;
/* Sanity check */
if ( len < sizeof ( *data ) ) {
- DBG ( "TFTP %p received underlength DATA packet length %d\n",
- tftp, len );
+ DBGC ( tftp, "TFTP %p received underlength DATA packet "
+ "length %d\n", tftp, len );
return -EINVAL;
}
- /* Pass to callback */
+ /* Fill data buffer */
block = ntohs ( data->block );
+ data_offset = ( ( block - 1 ) * tftp->blksize );
data_len = ( len - offsetof ( typeof ( *data ), data ) );
- tftp->callback ( tftp, block, data->data, data_len );
+ if ( ( rc = fill_buffer ( tftp->buffer, data->data, data_offset,
+ data_len ) ) != 0 ) {
+ DBGC ( tftp, "TFTP %p could not fill data buffer: %s\n",
+ tftp, strerror ( rc ) );
+ tftp_done ( tftp, rc );
+ return rc;
+ }
/* Mark block as received */
tftp_received ( tftp, block );
/* Sanity check */
if ( len < sizeof ( *error ) ) {
- DBG ( "TFTP %p received underlength ERROR packet length %d\n",
- tftp, len );
+ DBGC ( tftp, "TFTP %p received underlength ERROR packet "
+ "length %d\n", tftp, len );
return -EINVAL;
}
- DBG ( "TFTP %p received ERROR packet with code %d, message \"%s\"\n",
- tftp, ntohs ( error->errcode ), error->errmsg );
+ DBGC ( tftp, "TFTP %p received ERROR packet with code %d, message "
+ "\"%s\"\n", tftp, ntohs ( error->errcode ), error->errmsg );
/* Determine final operation result */
err = ntohs ( error->errcode );
struct tftp_common *common = data;
if ( len < sizeof ( *common ) ) {
- DBG ( "TFTP %p received underlength packet length %d\n",
- tftp, len );
+ DBGC ( tftp, "TFTP %p received underlength packet length %d\n",
+ tftp, len );
return -EINVAL;
}
/* Filter by TID. Set TID on first response received */
if ( tftp->tid ) {
if ( tftp->tid != st_src->st_port ) {
- DBG ( "TFTP %p received packet from wrong port "
- "(got %d, wanted %d)\n", tftp,
- ntohs ( st_src->st_port ), ntohs ( tftp->tid ) );
+ DBGC ( tftp, "TFTP %p received packet from wrong port "
+ "(got %d, wanted %d)\n", tftp,
+ ntohs ( st_src->st_port ), ntohs ( tftp->tid ));
return -EINVAL;
}
} else {
tftp->tid = st_src->st_port;
- DBG ( "TFTP %p using remote port %d\n", tftp,
- ntohs ( tftp->tid ) );
+ DBGC ( tftp, "TFTP %p using remote port %d\n", tftp,
+ ntohs ( tftp->tid ) );
udp_connect_port ( &tftp->udp, tftp->tid );
}
/* Filter by source address */
if ( memcmp ( st_src, udp_peer ( &tftp->udp ),
sizeof ( *st_src ) ) != 0 ) {
- DBG ( "TFTP %p received packet from foreign source\n", tftp );
+ DBGC ( tftp, "TFTP %p received packet from foreign source\n",
+ tftp );
return -EINVAL;
}
case htons ( TFTP_ERROR ):
return tftp_rx_error ( tftp, data, len );
default:
- DBG ( "TFTP %p received strange packet type %d\n", tftp,
- ntohs ( common->opcode ) );
+ DBGC ( tftp, "TFTP %p received strange packet type %d\n", tftp,
+ ntohs ( common->opcode ) );
return -EINVAL;
};
}
int rc;
assert ( tftp->filename != NULL );
- assert ( tftp->callback != NULL );
+ assert ( tftp->buffer != NULL );
assert ( tftp->udp.peer.st_family != 0 );
/* Initialise TFTP session */
- tftp->udp.udp_op = &tftp_udp_operations;
- tftp->timer.expired = tftp_timer_expired;
- tftp->state = -1;
- tftp->blksize = TFTP_DEFAULT_BLKSIZE;
if ( ! tftp->request_blksize )
tftp->request_blksize = TFTP_MAX_BLKSIZE;
+ tftp->blksize = TFTP_DEFAULT_BLKSIZE;
+ tftp->tsize = 0;
+ tftp->tid = 0;
+ tftp->state = -1;
+ tftp->udp.udp_op = &tftp_udp_operations;
+ tftp->timer.expired = tftp_timer_expired;
/* Open UDP connection */
if ( ( rc = udp_open ( &tftp->udp, 0 ) ) != 0 ) {