Browse Source

Initial (untested) implementation of TFTP over the new UDP API.

tags/v0.9.3
Michael Brown 18 years ago
parent
commit
3611cb17b7
3 changed files with 491 additions and 167 deletions
  1. 20
    2
      src/include/gpxe/tftp.h
  2. 471
    0
      src/net/udp/tftp.c
  3. 0
    165
      src/proto/tftp.c

+ 20
- 2
src/include/gpxe/tftp.h View File

@@ -9,6 +9,8 @@
9 9
 
10 10
 #include <stdint.h>
11 11
 #include <gpxe/udp.h>
12
+#include <gpxe/async.h>
13
+#include <gpxe/retry.h>
12 14
 
13 15
 #define TFTP_PORT	       69 /**< Default TFTP server port */
14 16
 #define	TFTP_DEFAULT_BLKSIZE  512 /**< Default TFTP data block size */
@@ -59,7 +61,7 @@ struct tftp_error {
59 61
 /** A TFTP options acknowledgement (OACK) packet */
60 62
 struct tftp_oack {
61 63
 	uint16_t opcode;
62
-	uint8_t data[0];
64
+	char data[0];
63 65
 } __attribute__ (( packed ));
64 66
 
65 67
 /** The common header of all TFTP packets */
@@ -87,6 +89,17 @@ struct tftp_session {
87 89
 	struct udp_connection udp;
88 90
 	/** Filename */
89 91
 	const char *filename;
92
+
93
+	/**
94
+	 * Callback function
95
+	 *
96
+	 * @v tftp		TFTP connection
97
+	 * @v block		Block number
98
+	 * @v data		Data
99
+	 * @v len		Length of data
100
+	 */
101
+	void ( * callback ) ( struct tftp_session *tftp, unsigned int block,
102
+			      void *data, size_t len );
90 103
 	/**
91 104
 	 * Transfer ID
92 105
 	 *
@@ -119,7 +132,12 @@ struct tftp_session {
119 132
 	 * TFTP server.  If the TFTP server does not support the
120 133
 	 * "tsize" option, this value will be zero.
121 134
 	 */
122
-	off_t tsize;
135
+	unsigned long tsize;
136
+	
137
+	/** Asynchronous operation for this session */
138
+	struct async_operation aop;
139
+	/** Retransmission timer */
140
+	struct retry_timer timer;
123 141
 };
124 142
 
125 143
 #endif /* _GPXE_TFTP_H */

+ 471
- 0
src/net/udp/tftp.c View File

@@ -0,0 +1,471 @@
1
+/*
2
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+#include <stdint.h>
20
+#include <stdlib.h>
21
+#include <string.h>
22
+#include <strings.h>
23
+#include <byteswap.h>
24
+#include <errno.h>
25
+#include <assert.h>
26
+#include <vsprintf.h>
27
+#include <gpxe/async.h>
28
+#include <gpxe/tftp.h>
29
+
30
+/** @file
31
+ *
32
+ * TFTP protocol
33
+ *
34
+ */
35
+
36
+/** A TFTP option */
37
+struct tftp_option {
38
+	/** Option name */
39
+	const char *name;
40
+	/** Option processor
41
+	 *
42
+	 * @v tftp	TFTP connection
43
+	 * @v value	Option value
44
+	 * @ret rc	Return status code
45
+	 */
46
+	int ( * process ) ( struct tftp_session *tftp, const char *value );
47
+};
48
+
49
+/**
50
+ * Process TFTP "blksize" option
51
+ *
52
+ * @v tftp		TFTP connection
53
+ * @v value		Option value
54
+ * @ret rc		Return status code
55
+ */
56
+static int tftp_process_blksize ( struct tftp_session *tftp,
57
+				  const char *value ) {
58
+	char *end;
59
+
60
+	tftp->blksize = strtoul ( value, &end, 10 );
61
+	if ( *end ) {
62
+		DBG ( "TFTP %p got invalid blksize \"%s\"\n", tftp, value );
63
+		return -EINVAL;
64
+	}
65
+	DBG ( "TFTP %p blksize=%d\n", tftp, tftp->blksize );
66
+
67
+	return 0;
68
+}
69
+
70
+/**
71
+ * Process TFTP "tsize" option
72
+ *
73
+ * @v tftp		TFTP connection
74
+ * @v value		Option value
75
+ * @ret rc		Return status code
76
+ */
77
+static int tftp_process_tsize ( struct tftp_session *tftp,
78
+				const char *value ) {
79
+	char *end;
80
+
81
+	tftp->tsize = strtoul ( value, &end, 10 );
82
+	if ( *end ) {
83
+		DBG ( "TFTP %p got invalid tsize \"%s\"\n", tftp, value );
84
+		return -EINVAL;
85
+	}
86
+	DBG ( "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
87
+
88
+	return 0;
89
+}
90
+
91
+/** Recognised TFTP options */
92
+static struct tftp_option tftp_options[] = {
93
+	{ "blksize", tftp_process_blksize },
94
+	{ "tsize", tftp_process_tsize },
95
+	{ NULL, NULL }
96
+};
97
+
98
+/**
99
+ * Process TFTP option
100
+ *
101
+ * @v tftp		TFTP connection
102
+ * @v name		Option name
103
+ * @v value		Option value
104
+ * @ret rc		Return status code
105
+ */
106
+static int tftp_process_option ( struct tftp_session *tftp,
107
+				 const char *name, const char *value ) {
108
+	struct tftp_option *option;
109
+
110
+	for ( option = tftp_options ; option->name ; option++ ) {
111
+		if ( strcasecmp ( name, option->name ) == 0 )
112
+			return option->process ( tftp, value );
113
+	}
114
+
115
+	DBG ( "TFTP %p received unknown option \"%s\" = \"%s\"\n",
116
+	      tftp, name, value );
117
+
118
+	return -EINVAL;
119
+}
120
+
121
+/** Translation between TFTP errors and internal error numbers */
122
+static const uint8_t tftp_errors[] = {
123
+	[TFTP_ERR_FILE_NOT_FOUND]	= PXENV_STATUS_TFTP_FILE_NOT_FOUND,
124
+	[TFTP_ERR_ACCESS_DENIED]	= PXENV_STATUS_TFTP_ACCESS_VIOLATION,
125
+	[TFTP_ERR_ILLEGAL_OP]		= PXENV_STATUS_TFTP_UNKNOWN_OPCODE,
126
+};
127
+
128
+/**
129
+ * Mark TFTP session as complete
130
+ *
131
+ * @v tftp		TFTP connection
132
+ * @v rc		Return status code
133
+ */
134
+static void tftp_done ( struct tftp_session *tftp, int rc ) {
135
+
136
+	/* Stop the retry timer */
137
+	stop_timer ( &tftp->timer );
138
+
139
+	/* Close UDP connection */
140
+	udp_close ( &tftp->udp );
141
+
142
+	/* Mark async operation as complete */
143
+	async_done ( &tftp->aop, rc );
144
+}
145
+
146
+/**
147
+ * Send next packet in TFTP session
148
+ *
149
+ * @v tftp		TFTP connection
150
+ */
151
+static void tftp_send_packet ( struct tftp_session *tftp ) {
152
+	start_timer ( &tftp->timer );
153
+	udp_senddata ( &tftp->udp );
154
+}
155
+
156
+/**
157
+ * Handle TFTP retransmission timer expiry
158
+ *
159
+ * @v timer		Retry timer
160
+ * @v fail		Failure indicator
161
+ */
162
+static void tftp_timer_expired ( struct retry_timer *timer, int fail ) {
163
+	struct tftp_session *tftp =
164
+		container_of ( timer, struct tftp_session, timer );
165
+
166
+	if ( fail ) {
167
+		tftp_done ( tftp, -ETIMEDOUT );
168
+	} else {
169
+		tftp_send_packet ( tftp );
170
+	}
171
+}
172
+
173
+/**
174
+ * Mark TFTP block as received
175
+ *
176
+ * @v tftp		TFTP connection
177
+ * @v block		Block number
178
+ */
179
+static void tftp_received ( struct tftp_session *tftp, unsigned int block ) {
180
+
181
+	/* Stop the retry timer */
182
+	stop_timer ( &tftp->timer );
183
+
184
+	/* Update state to indicate which block we're now waiting for */
185
+	tftp->state = block;
186
+
187
+	/* Send next packet */
188
+	tftp_send_packet ( tftp );
189
+}
190
+
191
+/**
192
+ * Transmit RRQ
193
+ *
194
+ * @v tftp		TFTP connection
195
+ * @v buf		Temporary data buffer
196
+ * @v len		Length of temporary data buffer
197
+ * @ret rc		Return status code
198
+ */
199
+static int tftp_send_rrq ( struct tftp_session *tftp, void *buf, size_t len ) {
200
+	struct tftp_rrq *rrq = buf;
201
+	void *data;
202
+	void *end;
203
+
204
+	DBG ( "TFTP %p requesting \"%s\"\n", tftp, tftp->filename );
205
+
206
+	data = rrq->data;
207
+	end = ( buf + len );
208
+	if ( data > end )
209
+		goto overflow;
210
+	data += snprintf ( data, ( end - data ),
211
+			   "%s%coctet%cblksize%c%d%ctsize%c0",
212
+			   tftp->filename, 0, 0, 0, tftp->blksize, 0, 0 ) + 1;
213
+	if ( data > end )
214
+		goto overflow;
215
+	rrq->opcode = htons ( TFTP_RRQ );
216
+
217
+	return udp_send ( &tftp->udp, buf, ( data - buf ) );
218
+
219
+ overflow:
220
+	DBG ( "TFTP %p RRQ out of space\n", tftp );
221
+	return -ENOBUFS;
222
+}
223
+
224
+/**
225
+ * Receive OACK
226
+ *
227
+ * @v tftp		TFTP connection
228
+ * @v buf		Temporary data buffer
229
+ * @v len		Length of temporary data buffer
230
+ * @ret rc		Return status code
231
+ */
232
+static int tftp_rx_oack ( struct tftp_session *tftp, void *buf, size_t len ) {
233
+	struct tftp_oack *oack = buf;
234
+	char *end = buf + len;
235
+	char *name;
236
+	char *value;
237
+	int rc;
238
+
239
+	/* Sanity check */
240
+	if ( len < sizeof ( *oack ) ) {
241
+		DBG ( "TFTP %p received underlength OACK packet length %d\n",
242
+		      tftp, len );
243
+		return -EINVAL;
244
+	}
245
+	if ( end[-1] != '\0' ) {
246
+		DBG ( "TFTP %p received OACK missing final NUL\n", tftp );
247
+		return -EINVAL;
248
+	}
249
+
250
+	/* Process each option in turn */
251
+	name = oack->data;
252
+	while ( name < end ) {
253
+		value = ( name + strlen ( name ) + 1 );
254
+		if ( value == end ) {
255
+			DBG ( "TFTP %p received OACK missing value for option "
256
+			      "\"%s\"\n", tftp, name );
257
+			return -EINVAL;
258
+		}
259
+		if ( ( rc = tftp_process_option ( tftp, name, value ) ) != 0 )
260
+			return rc;
261
+		name = ( value + strlen ( value ) + 1 );
262
+	}
263
+
264
+	/* Mark as received block 0 (the OACK) */
265
+	tftp_received ( tftp, 0 );
266
+
267
+	return 0;
268
+}
269
+
270
+/**
271
+ * Receive DATA
272
+ *
273
+ * @v tftp		TFTP connection
274
+ * @v buf		Temporary data buffer
275
+ * @v len		Length of temporary data buffer
276
+ * @ret rc		Return status code
277
+ */
278
+static int tftp_rx_data ( struct tftp_session *tftp, void *buf, size_t len ) {
279
+	struct tftp_data *data = buf;
280
+	unsigned int block;
281
+	size_t data_len;
282
+
283
+	/* Sanity check */
284
+	if ( len < sizeof ( *data ) ) {
285
+		DBG ( "TFTP %p received underlength DATA packet length %d\n",
286
+		      tftp, len );
287
+		return -EINVAL;
288
+	}
289
+
290
+	/* Pass to callback */
291
+	block = ntohs ( data->block );
292
+	data_len = ( len - offsetof ( typeof ( *data ), data ) );
293
+	tftp->callback ( tftp, block, data->data, data_len );
294
+
295
+	/* Mark block as received */
296
+	tftp_received ( tftp, block );
297
+
298
+	/* Finish when final block received */
299
+	if ( data_len < tftp->blksize )
300
+		tftp_done ( tftp, 0 );
301
+
302
+	return 0;
303
+}
304
+
305
+/**
306
+ * Transmit ACK
307
+ *
308
+ * @v tftp		TFTP connection
309
+ * @v buf		Temporary data buffer
310
+ * @v len		Length of temporary data buffer
311
+ * @ret rc		Return status code
312
+ */
313
+static int tftp_send_ack ( struct tftp_session *tftp ) {
314
+	struct tftp_ack ack;
315
+
316
+	ack.opcode = htons ( TFTP_ACK );
317
+	ack.block = htons ( tftp->state );
318
+	return udp_send ( &tftp->udp, &ack, sizeof ( ack ) );
319
+}
320
+
321
+/**
322
+ * Receive ERROR
323
+ *
324
+ * @v tftp		TFTP connection
325
+ * @v buf		Temporary data buffer
326
+ * @v len		Length of temporary data buffer
327
+ * @ret rc		Return status code
328
+ */
329
+static int tftp_rx_error ( struct tftp_session *tftp, void *buf, size_t len ) {
330
+	struct tftp_error *error = buf;
331
+	unsigned int err;
332
+	int rc = 0;
333
+
334
+	/* Sanity check */
335
+	if ( len < sizeof ( *error ) ) {
336
+		DBG ( "TFTP %p received underlength ERROR packet length %d\n",
337
+		      tftp, len );
338
+		return -EINVAL;
339
+	}
340
+
341
+	DBG ( "TFTP %p received ERROR packet with code %d, message \"%s\"\n",
342
+	      tftp, ntohs ( error->errcode ), error->errmsg );
343
+	
344
+	/* Determine final operation result */
345
+	err = ntohs ( error->errcode );
346
+	if ( err < ( sizeof ( tftp_errors ) / sizeof ( tftp_errors[0] ) ) )
347
+		rc = -tftp_errors[err];
348
+	if ( ! rc )
349
+		rc = -PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION;
350
+
351
+	/* Close TFTP session */
352
+	tftp_done ( tftp, rc );
353
+
354
+	return 0;
355
+}
356
+
357
+/**
358
+ * Transmit data
359
+ *
360
+ * @v conn		UDP connection
361
+ * @v buf		Temporary data buffer
362
+ * @v len		Length of temporary data buffer
363
+ * @ret rc		Return status code
364
+ */
365
+static int tftp_senddata ( struct udp_connection *conn,
366
+			   void *buf, size_t len ) {
367
+	struct tftp_session *tftp = 
368
+		container_of ( conn, struct tftp_session, udp );
369
+
370
+	if ( tftp->state < 0 ) {
371
+		return tftp_send_rrq ( tftp, buf, len );
372
+	} else {
373
+		return tftp_send_ack ( tftp );
374
+	}
375
+}
376
+
377
+/**
378
+ * Receive new data
379
+ *
380
+ * @v udp		UDP connection
381
+ * @v data		Received data
382
+ * @v len		Length of received data
383
+ * @v st_src		Partially-filled source address
384
+ * @v st_dest		Partially-filled destination address
385
+ */
386
+static int tftp_newdata ( struct udp_connection *conn, void *data, size_t len,
387
+			  struct sockaddr_tcpip *st_src __unused,
388
+			  struct sockaddr_tcpip *st_dest __unused ) {
389
+	struct tftp_session *tftp = 
390
+		container_of ( conn, struct tftp_session, udp );
391
+	struct tftp_common *common = data;
392
+	
393
+	if ( len < sizeof ( *common ) ) {
394
+		DBG ( "TFTP %p received underlength packet length %d\n",
395
+		      tftp, len );
396
+		return -EINVAL;
397
+	}
398
+
399
+	/* Filter by TID.  Set TID on first response received */
400
+	if ( tftp->tid ) {
401
+		if ( tftp->tid != st_src->st_port ) {
402
+			DBG ( "TFTP %p received packet from wrong port "
403
+			      "(got %d, wanted %d)\n", tftp,
404
+			      ntohs ( st_src->st_port ), ntohs ( tftp->tid ) );
405
+			return -EINVAL;
406
+		}
407
+	} else {
408
+		tftp->tid = st_src->st_port;
409
+		DBG ( "TFTP %p using remote port %d\n", tftp,
410
+		      ntohs ( tftp->tid ) );
411
+		udp_connect_port ( &tftp->udp, tftp->tid );
412
+	}
413
+
414
+	/* Filter by source address */
415
+	if ( memcmp ( st_src, udp_peer ( &tftp->udp ),
416
+		      sizeof ( *st_src ) ) != 0 ) {
417
+		DBG ( "TFTP %p received packet from foreign source\n", tftp );
418
+		return -EINVAL;
419
+	}
420
+
421
+	switch ( common->opcode ) {
422
+	case htons ( TFTP_OACK ):
423
+		return tftp_rx_oack ( tftp, data, len );
424
+	case htons ( TFTP_DATA ):
425
+		return tftp_rx_data ( tftp, data, len );
426
+	case htons ( TFTP_ERROR ):
427
+		return tftp_rx_error ( tftp, data, len );
428
+	default:
429
+		DBG ( "TFTP %p received strange packet type %d\n", tftp,
430
+		      ntohs ( common->opcode ) );
431
+		return -EINVAL;
432
+	};
433
+}
434
+
435
+/** TFTP UDP operations */
436
+static struct udp_operations tftp_udp_operations = {
437
+	.senddata = tftp_senddata,
438
+	.newdata = tftp_newdata,
439
+};
440
+
441
+/**
442
+ * Initiate TFTP download
443
+ *
444
+ * @v tftp		TFTP session
445
+ * @ret aop		Asynchronous operation
446
+ */
447
+struct async_operation * tftp_get ( struct tftp_session *tftp ) {
448
+	int rc;
449
+
450
+	assert ( tftp->filename != NULL );
451
+	assert ( tftp->callback != NULL );
452
+	assert ( tftp->udp.peer.st_family != 0 );
453
+
454
+	/* Initialise TFTP session */
455
+	tftp->udp.udp_op = &tftp_udp_operations;
456
+	tftp->timer.expired = tftp_timer_expired;
457
+	tftp->state = -1;
458
+	tftp->blksize = TFTP_DEFAULT_BLKSIZE;
459
+
460
+	/* Open UDP connection */
461
+	if ( ( rc = udp_open ( &tftp->udp, 0 ) ) != 0 ) {
462
+		async_done ( &tftp->aop, rc );
463
+		goto out;
464
+	}
465
+
466
+	/* Transmit initial RRQ */
467
+	tftp_send_packet ( tftp );
468
+
469
+ out:
470
+	return &tftp->aop;
471
+}

+ 0
- 165
src/proto/tftp.c View File

@@ -1,165 +0,0 @@
1
-#include "etherboot.h"
2
-#include "proto.h"
3
-#include "errno.h"
4
-#include "tftp.h"
5
-#include "tftpcore.h"
6
-
7
-/** @file
8
- *
9
- * TFTP protocol
10
- */
11
-
12
-/**
13
- * Process a TFTP block
14
- *
15
- * @v state			TFTP transfer state
16
- * @v tftp_state::block		Last received data block
17
- * @v tftp_state::blksize	Transfer block size
18
- * @v data			The data block to process
19
- * @v buffer			The buffer to fill with the data
20
- * @ret True			Block processed successfully
21
- * @ret False			Block not processed successfully
22
- * @ret tftp_state::block	Incremented if applicable
23
- * @ret *eof			End-of-file marker
24
- * @err #PXENV_STATUS_TFTP_INVALID_PACKET_SIZE Packet is too large
25
- * @err other			As returned by fill_buffer()
26
- *
27
- * Process a TFTP DATA packet that has been received.  If the data
28
- * packet is the next data packet in the stream, its contents will be
29
- * placed in the #buffer and tftp_state::block will be incremented.
30
- * If the packet is the final packet, end-of-file will be indicated
31
- * via #eof.
32
- *
33
- * If the data packet is a duplicate, then process_tftp_data() will
34
- * still return True, though nothing will be done with the packet.  A
35
- * False return value always indicates an error that should abort the
36
- * transfer.
37
- */
38
-static inline int tftp_process_data ( struct tftp_state *state,
39
-				      struct tftp_data *data,
40
-				      struct buffer *buffer,
41
-				      int *eof ) {
42
-	unsigned int blksize;
43
-
44
-	/* Check it's the correct DATA block */
45
-	if ( ntohs ( data->block ) != ( state->block + 1 ) ) {
46
-		DBG ( "TFTP: got block %d, wanted block %d\n",
47
-		      ntohs ( data->block ), state->block + 1 );
48
-		return 1;
49
-	}
50
-	/* Check it's an acceptable size */
51
-	blksize = ( ntohs ( data->udp.len )
52
-		    + offsetof ( typeof ( *data ), udp )
53
-		    - offsetof ( typeof ( *data ), data ) );
54
-	if ( blksize > state->blksize ) {
55
-		DBG ( "TFTP: oversized block size %d (max %d)\n",
56
-		      blksize, state->blksize );
57
-		errno = PXENV_STATUS_TFTP_INVALID_PACKET_SIZE;
58
-		return 0;
59
-	}
60
-	/* Place block in the buffer */
61
-	if ( ! fill_buffer ( buffer, data->data, state->block * state->blksize,
62
-			     blksize ) ) {
63
-		DBG ( "TFTP: could not place data in buffer: %m\n" );
64
-		return 0;
65
-	}
66
-	/* Increment block counter */
67
-	state->block++;
68
-	/* Set EOF marker */
69
-	*eof = ( blksize < state->blksize );
70
-	return 1;
71
-}
72
-
73
-/**
74
- * Download a file via TFTP
75
- *
76
- * @v server				TFTP server
77
- * @v file				File name
78
- * @v buffer				Buffer into which to load file
79
- * @ret True				File was downloaded successfully
80
- * @ret False				File was not downloaded successfully
81
- * @err #PXENV_STATUS_TFTP_UNKNOWN_OPCODE Unknown type of TFTP block received
82
- * @err other				As returned by tftp_open()
83
- * @err other				As returned by tftp_process_opts()
84
- * @err other				As returned by tftp_ack()
85
- * @err other				As returned by tftp_process_data()
86
- *
87
- * Download a file from a TFTP server into the specified buffer.
88
- */
89
-static int tftp ( char *url __unused, struct sockaddr_in *server, char *file,
90
-		  struct buffer *buffer ) {
91
-	struct tftp_state state;
92
-	union tftp_any *reply;
93
-	int eof = 0;
94
-
95
-	/* Initialise TFTP state */
96
-	memset ( &state, 0, sizeof ( state ) );
97
-	state.server = *server;
98
-	
99
-	/* Open the file */
100
-	if ( ! tftp_open ( &state, file, &reply, 0 ) ) {
101
-		DBG ( "TFTP: could not open %@:%d/%s : %m\n",
102
-		      server->sin_addr.s_addr, server->sin_port, file );
103
-		return 0;
104
-	}
105
-	
106
-	/* Fetch file, a block at a time */
107
-	while ( 1 ) {
108
-		twiddle();
109
-		switch ( ntohs ( reply->common.opcode ) ) {
110
-		case TFTP_DATA:
111
-			if ( ! tftp_process_data ( &state, &reply->data,
112
-						   buffer, &eof ) ) {
113
-				tftp_error ( &state, TFTP_ERR_ILLEGAL_OP,
114
-					     NULL );
115
-				return 0;
116
-			}
117
-			break;
118
-		case TFTP_OACK:
119
-			if ( state.block ) {
120
-				/* OACK must be first block, if present */
121
-				DBG ( "TFTP: OACK after block %d\n",
122
-				      state.block );
123
-				errno = PXENV_STATUS_TFTP_UNKNOWN_OPCODE;
124
-				tftp_error ( &state, TFTP_ERR_ILLEGAL_OP,
125
-					     NULL ); 
126
-				return 0;
127
-			}
128
-			if ( ! tftp_process_opts ( &state, &reply->oack ) ) {
129
-				DBG ( "TFTP: option processing failed: %m\n" );
130
-				tftp_error ( &state, TFTP_ERR_BAD_OPTS, NULL );
131
-				return 0;
132
-			}
133
-			break;
134
-		default:
135
-			DBG ( "TFTP: unexpected opcode %d\n",
136
-			      ntohs ( reply->common.opcode ) );
137
-			errno = PXENV_STATUS_TFTP_UNKNOWN_OPCODE;
138
-			tftp_error ( &state, TFTP_ERR_ILLEGAL_OP, NULL );
139
-			return 0;
140
-		}
141
-		/* If we have reached EOF, stop here */
142
-		if ( eof )
143
-			break;
144
-		/* Fetch the next data block */
145
-		if ( ! tftp_ack ( &state, &reply ) ) {
146
-			DBG ( "TFTP: could not get next block: %m\n" );
147
-			if ( ! reply ) {
148
-				tftp_error ( &state, TFTP_ERR_ILLEGAL_OP,
149
-					     NULL );
150
-			}
151
-			return 0;
152
-		}
153
-	}
154
-
155
-	/* ACK the final packet, as a courtesy to the server */
156
-	tftp_ack_nowait ( &state );
157
-
158
-	return 1;
159
-}
160
-
161
-struct protocol tftp_protocol __default_protocol = {
162
-	.name = "tftp",
163
-	.default_port = TFTP_PORT,
164
-	.load = tftp,
165
-};

Loading…
Cancel
Save