summaryrefslogtreecommitdiffstats
path: root/src/proto/tftp.c
diff options
context:
space:
mode:
authorMichael Brown2005-06-01 20:00:01 +0200
committerMichael Brown2005-06-01 20:00:01 +0200
commitf2198e8a654581f97daaeda301cd8735aa9e3254 (patch)
treec4cd52cc9c647771ba08f4e627b8e4e04cd69930 /src/proto/tftp.c
parentRemove prototypes for obsolete functions (diff)
downloadipxe-f2198e8a654581f97daaeda301cd8735aa9e3254.tar.gz
ipxe-f2198e8a654581f97daaeda301cd8735aa9e3254.tar.xz
ipxe-f2198e8a654581f97daaeda301cd8735aa9e3254.zip
Don't choke on duplicate OACK packets.
Make await_tftp() static and create tftp_get() for fetching the next TFTP packet instead.
Diffstat (limited to 'src/proto/tftp.c')
-rw-r--r--src/proto/tftp.c55
1 files changed, 31 insertions, 24 deletions
diff --git a/src/proto/tftp.c b/src/proto/tftp.c
index 53706448d..9231c5162 100644
--- a/src/proto/tftp.c
+++ b/src/proto/tftp.c
@@ -103,40 +103,47 @@ static int tftp ( char *url __unused, struct sockaddr_in *server, char *file,
return 0;
}
- /* Process OACK, if any */
- if ( ntohs ( reply->common.opcode ) == TFTP_OACK ) {
- if ( ! tftp_process_opts ( &state, &reply->oack ) ) {
- DBG ( "TFTP: option processing failed : %m\n" );
- return 0;
- }
- reply = NULL;
- }
-
/* Fetch file, a block at a time */
do {
- /* Get next block to process. (On the first time
- * through, we may already have a block from
- * tftp_open()).
- */
- if ( ! reply ) {
- if ( ! tftp_ack ( &state, &reply ) ) {
- DBG ( "TFTP: could not get next block: %m\n" );
+ twiddle();
+ switch ( ntohs ( reply->common.opcode ) ) {
+ case TFTP_DATA:
+ if ( ! process_tftp_data ( &state, &reply->data,
+ buffer, &eof ) ) {
+ tftp_error ( &state, TFTP_ERR_ILLEGAL_OP,
+ NULL );
return 0;
}
- }
- twiddle();
- /* Check it's a DATA block */
- if ( ntohs ( reply->common.opcode ) != TFTP_DATA ) {
+ break;
+ case TFTP_OACK:
+ if ( state.block ) {
+ /* OACK must be first block, if present */
+ DBG ( "TFTP: OACK after block %d\n",
+ state.block );
+ errno = PXENV_STATUS_TFTP_UNKNOWN_OPCODE;
+ tftp_error ( &state, TFTP_ERR_ILLEGAL_OP,
+ NULL );
+ return 0;
+ }
+ if ( ! tftp_process_opts ( &state, &reply->oack ) ) {
+ DBG ( "TFTP: option processing failed: %m\n" );
+ tftp_error ( &state, TFTP_ERR_BAD_OPTS, NULL );
+ return 0;
+ }
+ break;
+ default:
DBG ( "TFTP: unexpected opcode %d\n",
ntohs ( reply->common.opcode ) );
errno = PXENV_STATUS_TFTP_UNKNOWN_OPCODE;
+ tftp_error ( &state, TFTP_ERR_ILLEGAL_OP, NULL );
return 0;
}
- /* Process the DATA block */
- if ( ! process_tftp_data ( &state, &reply->data, buffer,
- &eof ) )
+ /* Fetch the next data block */
+ if ( ! tftp_ack ( &state, &reply ) ) {
+ DBG ( "TFTP: could not get next block: %m\n" );
+ tftp_error ( &state, TFTP_ERR_ILLEGAL_OP, NULL );
return 0;
- reply = NULL;
+ }
} while ( ! eof );
/* ACK the final packet, as a courtesy to the server */