Browse Source

Add RFC2090 TFTP multicast support.

tags/v0.9.3
Michael Brown 17 years ago
parent
commit
3b1efba864
4 changed files with 481 additions and 82 deletions
  1. 97
    0
      src/core/bitmap.c
  2. 83
    0
      src/include/gpxe/bitmap.h
  3. 1
    0
      src/include/gpxe/errfile.h
  4. 300
    82
      src/net/udp/tftp.c

+ 97
- 0
src/core/bitmap.c View File

1
+/*
2
+ * Copyright (C) 2007 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 <errno.h>
20
+#include <gpxe/bitmap.h>
21
+
22
+/** @file
23
+ *
24
+ * Bitmaps for multicast downloads
25
+ *
26
+ */
27
+
28
+/**
29
+ * Resize bitmap
30
+ *
31
+ * @v bitmap		Bitmap
32
+ * @v new_length	New length of bitmap, in bits
33
+ * @ret rc		Return status code
34
+ */
35
+int bitmap_resize ( struct bitmap *bitmap, unsigned int new_length ) {
36
+	unsigned int old_num_blocks;
37
+	unsigned int new_num_blocks;
38
+	size_t new_size;
39
+	bitmap_block_t *new_blocks;
40
+
41
+	old_num_blocks = BITMAP_INDEX ( bitmap->length + BITMAP_BLKSIZE - 1 );
42
+	new_num_blocks = BITMAP_INDEX ( new_length + BITMAP_BLKSIZE - 1 );
43
+
44
+	new_size = ( new_num_blocks * sizeof ( bitmap->blocks[0] ) );
45
+	new_blocks = realloc ( bitmap->blocks, new_size );
46
+	if ( ! new_blocks ) {
47
+		DBGC ( bitmap, "Bitmap %p could not resize to %d bits\n",
48
+		       bitmap, new_length );
49
+		return -ENOMEM;
50
+	}
51
+	bitmap->blocks = new_blocks;
52
+	bitmap->length = new_length;
53
+
54
+	while ( old_num_blocks < new_num_blocks ) {
55
+		bitmap->blocks[old_num_blocks++] = 0;
56
+	}
57
+
58
+	DBGC ( bitmap, "Bitmap %p resized to %d bits\n", bitmap, new_length );
59
+	return 0;
60
+}
61
+
62
+/**
63
+ * Test bit in bitmap
64
+ *
65
+ * @v bitmap		Bitmap
66
+ * @v bit		Bit index
67
+ * @ret is_set		Bit is set
68
+ */
69
+int bitmap_test ( struct bitmap *bitmap, unsigned int bit ) {
70
+	unsigned int index = BITMAP_INDEX ( bit );
71
+        bitmap_block_t mask = BITMAP_MASK ( bit );
72
+
73
+	if ( bit >= bitmap->length )
74
+		return 0;
75
+	return ( bitmap->blocks[index] & mask );
76
+}
77
+
78
+/**
79
+ * Set bit in bitmap
80
+ *
81
+ * @v bitmap		Bitmap
82
+ * @v bit		Bit index
83
+ */
84
+void bitmap_set ( struct bitmap *bitmap, unsigned int bit ) {
85
+	unsigned int index = BITMAP_INDEX ( bit );
86
+        bitmap_block_t mask = BITMAP_MASK ( bit );
87
+
88
+	DBGC ( bitmap, "Bitmap %p setting bit %d\n", bitmap, bit );
89
+
90
+	/* Update bitmap */
91
+	bitmap->blocks[index] |= mask;
92
+
93
+	/* Update first gap counter */
94
+	while ( bitmap_test ( bitmap, bitmap->first_gap ) ) {
95
+		bitmap->first_gap++;
96
+	}
97
+}

+ 83
- 0
src/include/gpxe/bitmap.h View File

1
+#ifndef _GPXE_BITMAP_H
2
+#define _GPXE_BITMAP_H
3
+
4
+/** @file
5
+ *
6
+ * Bitmaps for multicast downloads
7
+ *
8
+ */
9
+
10
+#include <stdint.h>
11
+#include <stddef.h>
12
+#include <stdlib.h>
13
+
14
+/** A single block of bits within a bitmap */
15
+typedef unsigned long bitmap_block_t;
16
+
17
+/** Size of a block of bits (in bits) */
18
+#define BITMAP_BLKSIZE ( sizeof ( bitmap_block_t ) * 8 )
19
+
20
+/**
21
+ * Block index within bitmap
22
+ *
23
+ * @v bit		Bit index
24
+ * @ret index		Block index
25
+ */
26
+#define BITMAP_INDEX( bit ) ( (bit) / BITMAP_BLKSIZE )
27
+
28
+/**
29
+ * Block mask within bitmap
30
+ *
31
+ * @v bit		Bit index
32
+ * @ret mask		Block mask
33
+ */
34
+#define BITMAP_MASK( bit ) ( 1 << ( (bit) % BITMAP_BLKSIZE ) )
35
+
36
+/** A bitmap */
37
+struct bitmap {
38
+	/** Bitmap data */
39
+	bitmap_block_t *blocks;
40
+	/** Length of the bitmap, in bits */
41
+	unsigned int length;
42
+	/** Index of first gap in the bitmap */
43
+	unsigned int first_gap;
44
+};
45
+
46
+extern int bitmap_resize ( struct bitmap *bitmap, unsigned int new_length );
47
+extern int bitmap_test ( struct bitmap *bitmap, unsigned int bit );
48
+extern void bitmap_set ( struct bitmap *bitmap, unsigned int bit );
49
+
50
+/**
51
+ * Free bitmap resources
52
+ *
53
+ * @v bitmap		Bitmap
54
+ */
55
+static inline void bitmap_free ( struct bitmap *bitmap ) {
56
+	free ( bitmap->blocks );
57
+}
58
+
59
+/**
60
+ * Get first gap within bitmap
61
+ *
62
+ * @v bitmap		Bitmap
63
+ * @ret first_gap	First gap
64
+ *
65
+ * The first gap is the first unset bit within the bitmap.
66
+ */
67
+static inline unsigned int bitmap_first_gap ( struct bitmap *bitmap ) {
68
+	return bitmap->first_gap;
69
+}
70
+
71
+/**
72
+ * Check to see if bitmap is full
73
+ *
74
+ * @v bitmap		Bitmap
75
+ * @ret is_full		Bitmap is full
76
+ *
77
+ * The bitmap is full if it has no gaps (i.e. no unset bits).
78
+ */
79
+static inline int bitmap_full ( struct bitmap *bitmap ) {
80
+	return ( bitmap->first_gap == bitmap->length );
81
+}
82
+
83
+#endif /* _GPXE_BITMAP_H */

+ 1
- 0
src/include/gpxe/errfile.h View File

50
 #define ERRFILE_settings	       ( ERRFILE_CORE | 0x000c0000 )
50
 #define ERRFILE_settings	       ( ERRFILE_CORE | 0x000c0000 )
51
 #define ERRFILE_vsprintf	       ( ERRFILE_CORE | 0x000d0000 )
51
 #define ERRFILE_vsprintf	       ( ERRFILE_CORE | 0x000d0000 )
52
 #define ERRFILE_xfer		       ( ERRFILE_CORE | 0x000e0000 )
52
 #define ERRFILE_xfer		       ( ERRFILE_CORE | 0x000e0000 )
53
+#define ERRFILE_bitmap		       ( ERRFILE_CORE | 0x000f0000 )
53
 
54
 
54
 #define ERRFILE_eisa		     ( ERRFILE_DRIVER | 0x00000000 )
55
 #define ERRFILE_eisa		     ( ERRFILE_DRIVER | 0x00000000 )
55
 #define ERRFILE_isa		     ( ERRFILE_DRIVER | 0x00010000 )
56
 #define ERRFILE_isa		     ( ERRFILE_DRIVER | 0x00010000 )

+ 300
- 82
src/net/udp/tftp.c View File

31
 #include <gpxe/tcpip.h>
31
 #include <gpxe/tcpip.h>
32
 #include <gpxe/retry.h>
32
 #include <gpxe/retry.h>
33
 #include <gpxe/features.h>
33
 #include <gpxe/features.h>
34
+#include <gpxe/bitmap.h>
34
 #include <gpxe/tftp.h>
35
 #include <gpxe/tftp.h>
35
 
36
 
36
 /** @file
37
 /** @file
56
 	struct uri *uri;
57
 	struct uri *uri;
57
 	/** Transport layer interface */
58
 	/** Transport layer interface */
58
 	struct xfer_interface socket;
59
 	struct xfer_interface socket;
60
+	/** Multicast transport layer interface */
61
+	struct xfer_interface mc_socket;
59
 
62
 
60
 	/** Data block size
63
 	/** Data block size
61
 	 *
64
 	 *
71
 	 * "tsize" option, this value will be zero.
74
 	 * "tsize" option, this value will be zero.
72
 	 */
75
 	 */
73
 	unsigned long tsize;
76
 	unsigned long tsize;
74
-
75
-	/** Request state
77
+	/** Multicast address
78
+	 *
79
+	 * This is the destination address for multicast data
80
+	 * transmissions.
81
+	 */
82
+	struct sockaddr_tcpip multicast;
83
+	/** Master client
76
 	 *
84
 	 *
77
-	 * This is the block number to be used in the next ACK sent
78
-	 * back to the server, i.e. the number of the last received
79
-	 * data block.  The value zero indicates that the last
80
-	 * received block was an OACK (i.e. that the next ACK will
81
-	 * contain a block number of zero), and any value less than
82
-	 * zero indicates that the connection has not yet been opened
83
-	 * (i.e. that no blocks have yet been received).
85
+	 * True if this is the client responsible for sending ACKs.
84
 	 */
86
 	 */
85
-	int state;
87
+	int master;
88
+	
86
 	/** Peer address
89
 	/** Peer address
87
 	 *
90
 	 *
88
 	 * The peer address is determined by the first response
91
 	 * The peer address is determined by the first response
89
 	 * received to the TFTP RRQ.
92
 	 * received to the TFTP RRQ.
90
 	 */
93
 	 */
91
 	struct sockaddr_tcpip peer;
94
 	struct sockaddr_tcpip peer;
95
+	/** Block bitmap */
96
+	struct bitmap bitmap;
97
+	/** Maximum known length
98
+	 *
99
+	 * We don't always know the file length in advance.  In
100
+	 * particular, if the TFTP server doesn't support the tsize
101
+	 * option, or we are using MTFTP, then we don't know the file
102
+	 * length until we see the end-of-file block (which, in the
103
+	 * case of MTFTP, may not be the last block we see).
104
+	 *
105
+	 * This value is updated whenever we obtain information about
106
+	 * the file length.
107
+	 */
108
+	size_t filesize;
92
 	/** Retransmission timer */
109
 	/** Retransmission timer */
93
 	struct retry_timer timer;
110
 	struct retry_timer timer;
94
 };
111
 };
103
 		container_of ( refcnt, struct tftp_request, refcnt );
120
 		container_of ( refcnt, struct tftp_request, refcnt );
104
 
121
 
105
 	uri_put ( tftp->uri );
122
 	uri_put ( tftp->uri );
123
+	bitmap_free ( &tftp->bitmap );
106
 	free ( tftp );
124
 	free ( tftp );
107
 }
125
 }
108
 
126
 
123
 	/* Close all data transfer interfaces */
141
 	/* Close all data transfer interfaces */
124
 	xfer_nullify ( &tftp->socket );
142
 	xfer_nullify ( &tftp->socket );
125
 	xfer_close ( &tftp->socket, rc );
143
 	xfer_close ( &tftp->socket, rc );
144
+	xfer_nullify ( &tftp->mc_socket );
145
+	xfer_close ( &tftp->mc_socket, rc );
126
 	xfer_nullify ( &tftp->xfer );
146
 	xfer_nullify ( &tftp->xfer );
127
 	xfer_close ( &tftp->xfer, rc );
147
 	xfer_close ( &tftp->xfer, rc );
128
 }
148
 }
129
 
149
 
150
+/**
151
+ * Presize TFTP receive buffers and block bitmap
152
+ *
153
+ * @v tftp		TFTP connection
154
+ * @v filesize		Known minimum file size
155
+ * @ret rc		Return status code
156
+ */
157
+static int tftp_presize ( struct tftp_request *tftp, size_t filesize ) {
158
+	unsigned int num_blocks;
159
+	int rc;
160
+
161
+	/* Do nothing if we are already large enough */
162
+	if ( filesize <= tftp->filesize )
163
+		return 0;
164
+
165
+	/* Record filesize */
166
+	tftp->filesize = filesize;
167
+
168
+	/* Notify recipient of file size */
169
+	xfer_seek ( &tftp->xfer, filesize, SEEK_SET );
170
+	xfer_seek ( &tftp->xfer, 0, SEEK_SET );
171
+
172
+	/* Calculate expected number of blocks.  Note that files whose
173
+	 * length is an exact multiple of the blocksize will have a
174
+	 * trailing zero-length block, which must be included.
175
+	 */
176
+	num_blocks = ( ( filesize / tftp->blksize ) + 1 );
177
+	if ( ( rc = bitmap_resize ( &tftp->bitmap, num_blocks ) ) != 0 ) {
178
+		DBGC ( tftp, "TFTP %p could not resize bitmap to %d blocks: "
179
+		       "%s\n", tftp, num_blocks, strerror ( rc ) );
180
+		return rc;
181
+	}
182
+
183
+	return 0;
184
+}
185
+
130
 /**
186
 /**
131
  * TFTP requested blocksize
187
  * TFTP requested blocksize
132
  *
188
  *
157
 	size_t len = ( sizeof ( *rrq ) + strlen ( path ) + 1 /* NUL */
213
 	size_t len = ( sizeof ( *rrq ) + strlen ( path ) + 1 /* NUL */
158
 		       + 5 + 1 /* "octet" + NUL */
214
 		       + 5 + 1 /* "octet" + NUL */
159
 		       + 7 + 1 + 5 + 1 /* "blksize" + NUL + ddddd + NUL */
215
 		       + 7 + 1 + 5 + 1 /* "blksize" + NUL + ddddd + NUL */
160
-		       + 5 + 1 + 1 + 1 /* "tsize" + NUL + "0" + NUL */ );
216
+		       + 5 + 1 + 1 + 1 /* "tsize" + NUL + "0" + NUL */ 
217
+		       + 9 + 1 + 1 /* "multicast" + NUL + NUL */ );
161
 	struct io_buffer *iobuf;
218
 	struct io_buffer *iobuf;
162
 
219
 
163
 	DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, path );
220
 	DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, path );
172
 	rrq->opcode = htons ( TFTP_RRQ );
229
 	rrq->opcode = htons ( TFTP_RRQ );
173
 	iob_put ( iobuf,
230
 	iob_put ( iobuf,
174
 		  snprintf ( rrq->data, iob_tailroom ( iobuf ),
231
 		  snprintf ( rrq->data, iob_tailroom ( iobuf ),
175
-			     "%s%coctet%cblksize%c%d%ctsize%c0", path, 0,
176
-			     0, 0, tftp_request_blksize, 0, 0 ) + 1 );
232
+			     "%s%coctet%cblksize%c%d%ctsize%c0%cmulticast%c",
233
+			     path, 0, 0, 0, tftp_request_blksize, 0,
234
+			     0, 0, 0 ) + 1 );
177
 
235
 
178
 	/* RRQ always goes to the address specified in the initial
236
 	/* RRQ always goes to the address specified in the initial
179
 	 * xfer_open() call
237
 	 * xfer_open() call
193
 	struct xfer_metadata meta = {
251
 	struct xfer_metadata meta = {
194
 		.dest = ( struct sockaddr * ) &tftp->peer,
252
 		.dest = ( struct sockaddr * ) &tftp->peer,
195
 	};
253
 	};
254
+	unsigned int block;
196
 
255
 
197
-	DBGC2 ( tftp, "TFTP %p sending ACK for block %d\n",
198
-		tftp, tftp->state );
256
+	/* Determine next required block number */
257
+	block = bitmap_first_gap ( &tftp->bitmap );
258
+	DBGC2 ( tftp, "TFTP %p sending ACK for block %d\n", tftp, block );
199
 
259
 
200
 	/* Allocate buffer */
260
 	/* Allocate buffer */
201
 	iobuf = xfer_alloc_iob ( &tftp->socket, sizeof ( *ack ) );
261
 	iobuf = xfer_alloc_iob ( &tftp->socket, sizeof ( *ack ) );
205
 	/* Build ACK */
265
 	/* Build ACK */
206
 	ack = iob_put ( iobuf, sizeof ( *ack ) );
266
 	ack = iob_put ( iobuf, sizeof ( *ack ) );
207
 	ack->opcode = htons ( TFTP_ACK );
267
 	ack->opcode = htons ( TFTP_ACK );
208
-	ack->block = htons ( tftp->state );
268
+	ack->block = htons ( block );
209
 
269
 
210
 	/* ACK always goes to the peer recorded from the RRQ response */
270
 	/* ACK always goes to the peer recorded from the RRQ response */
211
 	return xfer_deliver_iob_meta ( &tftp->socket, iobuf, &meta );
271
 	return xfer_deliver_iob_meta ( &tftp->socket, iobuf, &meta );
212
 }
272
 }
213
 
273
 
214
 /**
274
 /**
215
- * Transmit data
275
+ * Transmit next relevant packet
216
  *
276
  *
217
  * @v tftp		TFTP connection
277
  * @v tftp		TFTP connection
218
  * @ret rc		Return status code
278
  * @ret rc		Return status code
219
  */
279
  */
220
 static int tftp_send_packet ( struct tftp_request *tftp ) {
280
 static int tftp_send_packet ( struct tftp_request *tftp ) {
221
 
281
 
222
-	/* Start retransmission timer */
282
+	/* Update retransmission timer */
283
+	stop_timer ( &tftp->timer );
223
 	start_timer ( &tftp->timer );
284
 	start_timer ( &tftp->timer );
224
 
285
 
225
-	/* Send RRQ or ACK as appropriate */
226
-	if ( tftp->state < 0 ) {
227
-		return tftp_send_rrq ( tftp );
286
+	/* If we are the master client, send RRQ or ACK as appropriate */
287
+	if ( tftp->master ) {
288
+		if ( ! tftp->peer.st_family ) {
289
+			return tftp_send_rrq ( tftp );
290
+		} else {
291
+			return tftp_send_ack ( tftp );
292
+		}
228
 	} else {
293
 	} else {
229
-		return tftp_send_ack ( tftp );
294
+		/* Do nothing when not the master client */
295
+		return 0;
230
 	}
296
 	}
231
 }
297
 }
232
 
298
 
247
 	}
313
 	}
248
 }
314
 }
249
 
315
 
250
-/**
251
- * Mark TFTP block as received
252
- *
253
- * @v tftp		TFTP connection
254
- * @v block		Block number
255
- */
256
-static void tftp_received ( struct tftp_request *tftp, unsigned int block ) {
257
-
258
-	/* Stop the retry timer */
259
-	stop_timer ( &tftp->timer );
260
-
261
-	/* Update state to indicate which block we're now waiting for */
262
-	tftp->state = block;
263
-
264
-	/* Send next packet */
265
-	tftp_send_packet ( tftp );
266
-}
267
-
268
 /**
316
 /**
269
  * Process TFTP "blksize" option
317
  * Process TFTP "blksize" option
270
  *
318
  *
306
 	}
354
 	}
307
 	DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
355
 	DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
308
 
356
 
309
-	/* Notify recipient of file size */
310
-	xfer_seek ( &tftp->xfer, tftp->tsize, SEEK_SET );
311
-	xfer_seek ( &tftp->xfer, 0, SEEK_SET );
357
+	return 0;
358
+}
359
+
360
+/**
361
+ * Process TFTP "multicast" option
362
+ *
363
+ * @v tftp		TFTP connection
364
+ * @v value		Option value
365
+ * @ret rc		Return status code
366
+ */
367
+static int tftp_process_multicast ( struct tftp_request *tftp,
368
+				    const char *value ) {
369
+	struct sockaddr_in *sin = ( struct sockaddr_in * ) &tftp->multicast;
370
+	char buf[ strlen ( value ) + 1 ];
371
+	char *addr;
372
+	char *port;
373
+	char *port_end;
374
+	char *mc;
375
+	char *mc_end;
376
+	struct sockaddr *mc_peer;
377
+	struct sockaddr *mc_local;
378
+	int rc;
379
+
380
+	/* Split value into "addr,port,mc" fields */
381
+	memcpy ( buf, value, sizeof ( buf ) );
382
+	addr = buf;
383
+	port = strchr ( addr, ',' );
384
+	if ( ! port ) {
385
+		DBGC ( tftp, "TFTP %p multicast missing port,mc\n", tftp );
386
+		return -EINVAL;
387
+	}
388
+	*(port++) = '\0';
389
+	mc = strchr ( port, ',' );
390
+	if ( ! mc ) {
391
+		DBGC ( tftp, "TFTP %p multicast missing mc\n", tftp );
392
+		return -EINVAL;
393
+	}
394
+	*(mc++) = '\0';
395
+
396
+	/* Parse parameters */
397
+	if ( *addr ) {
398
+		if ( inet_aton ( addr, &sin->sin_addr ) == 0 ) {
399
+			DBGC ( tftp, "TFTP %p multicast invalid IP address "
400
+			       "%s\n", tftp, addr );
401
+			return -EINVAL;
402
+		}
403
+		DBGC ( tftp, "TFTP %p multicast IP address %s\n",
404
+		       tftp, inet_ntoa ( sin->sin_addr ) );
405
+	}
406
+	if ( *port ) {
407
+		sin->sin_port = htons ( strtoul ( port, &port_end, 0 ) );
408
+		if ( *port_end ) {
409
+			DBGC ( tftp, "TFTP %p multicast invalid port %s\n",
410
+			       tftp, port );
411
+			return -EINVAL;
412
+		}
413
+		DBGC ( tftp, "TFTP %p multicast port %d\n",
414
+		       tftp, ntohs ( sin->sin_port ) );
415
+	}
416
+	tftp->master = strtoul ( mc, &mc_end, 0 );
417
+	if ( *mc_end ) {
418
+		DBGC ( tftp, "TFTP %p multicast invalid mc %s\n", tftp, mc );
419
+		return -EINVAL;
420
+	}
421
+	DBGC ( tftp, "TFTP %p is%s the master client\n",
422
+	       tftp, ( tftp->master ? "" : " not" ) );
423
+
424
+	/* Open multicast socket, if new address specified */
425
+	if ( *addr || *port ) {
426
+		xfer_close ( &tftp->mc_socket, 0 );
427
+		mc_peer = ( ( struct sockaddr * ) &tftp->peer );
428
+		mc_local = ( ( struct sockaddr * ) &tftp->multicast );
429
+		mc_local->sa_family = mc_peer->sa_family;
430
+		if ( ( rc = xfer_open_socket ( &tftp->mc_socket, SOCK_DGRAM,
431
+					       mc_peer, mc_local ) ) != 0 ) {
432
+			DBGC ( tftp, "TFTP %p could not open multicast "
433
+			       "socket: %s\n", tftp, strerror ( rc ) );
434
+			return rc;
435
+		}
436
+	}
312
 
437
 
313
 	return 0;
438
 	return 0;
314
 }
439
 }
330
 static struct tftp_option tftp_options[] = {
455
 static struct tftp_option tftp_options[] = {
331
 	{ "blksize", tftp_process_blksize },
456
 	{ "blksize", tftp_process_blksize },
332
 	{ "tsize", tftp_process_tsize },
457
 	{ "tsize", tftp_process_tsize },
458
+	{ "multicast", tftp_process_multicast },
333
 	{ NULL, NULL }
459
 	{ NULL, NULL }
334
 };
460
 };
335
 
461
 
353
 	DBGC ( tftp, "TFTP %p received unknown option \"%s\" = \"%s\"\n",
479
 	DBGC ( tftp, "TFTP %p received unknown option \"%s\" = \"%s\"\n",
354
 	       tftp, name, value );
480
 	       tftp, name, value );
355
 
481
 
356
-	return -EINVAL;
482
+	/* Unknown options should be silently ignored */
483
+	return 0;
357
 }
484
 }
358
 
485
 
359
 /**
486
 /**
375
 	if ( len < sizeof ( *oack ) ) {
502
 	if ( len < sizeof ( *oack ) ) {
376
 		DBGC ( tftp, "TFTP %p received underlength OACK packet "
503
 		DBGC ( tftp, "TFTP %p received underlength OACK packet "
377
 		       "length %d\n", tftp, len );
504
 		       "length %d\n", tftp, len );
378
-		return -EINVAL;
505
+		rc = -EINVAL;
506
+		goto done;
379
 	}
507
 	}
380
 	if ( end[-1] != '\0' ) {
508
 	if ( end[-1] != '\0' ) {
381
 		DBGC ( tftp, "TFTP %p received OACK missing final NUL\n",
509
 		DBGC ( tftp, "TFTP %p received OACK missing final NUL\n",
382
 		       tftp );
510
 		       tftp );
383
-		return -EINVAL;
511
+		rc = -EINVAL;
512
+		goto done;
384
 	}
513
 	}
385
 
514
 
386
 	/* Process each option in turn */
515
 	/* Process each option in turn */
390
 		if ( value == end ) {
519
 		if ( value == end ) {
391
 			DBGC ( tftp, "TFTP %p received OACK missing value "
520
 			DBGC ( tftp, "TFTP %p received OACK missing value "
392
 			       "for option \"%s\"\n", tftp, name );
521
 			       "for option \"%s\"\n", tftp, name );
393
-			return -EINVAL;
522
+			rc = -EINVAL;
523
+			goto done;
394
 		}
524
 		}
395
 		if ( ( rc = tftp_process_option ( tftp, name, value ) ) != 0 )
525
 		if ( ( rc = tftp_process_option ( tftp, name, value ) ) != 0 )
396
-			return rc;
526
+			goto done;
397
 		name = ( value + strlen ( value ) + 1 );
527
 		name = ( value + strlen ( value ) + 1 );
398
 	}
528
 	}
399
 
529
 
400
-	/* Mark as received block 0 (the OACK) */
401
-	tftp_received ( tftp, 0 );
530
+	/* Process tsize information, if available */
531
+	if ( tftp->tsize ) {
532
+		if ( ( rc = tftp_presize ( tftp, tftp->tsize ) ) != 0 )
533
+			goto done;
534
+	}
402
 
535
 
403
-	return 0;
536
+	/* Request next data block */
537
+	tftp_send_packet ( tftp );
538
+
539
+ done:
540
+	if ( rc )
541
+		tftp_done ( tftp, rc );
542
+	return rc;
404
 }
543
 }
405
 
544
 
406
 /**
545
 /**
416
 			  struct io_buffer *iobuf ) {
555
 			  struct io_buffer *iobuf ) {
417
 	struct tftp_data *data = iobuf->data;
556
 	struct tftp_data *data = iobuf->data;
418
 	int block;
557
 	int block;
558
+	off_t offset;
419
 	size_t data_len;
559
 	size_t data_len;
420
 	int rc;
560
 	int rc;
421
 
561
 
423
 	if ( iob_len ( iobuf ) < sizeof ( *data ) ) {
563
 	if ( iob_len ( iobuf ) < sizeof ( *data ) ) {
424
 		DBGC ( tftp, "TFTP %p received underlength DATA packet "
564
 		DBGC ( tftp, "TFTP %p received underlength DATA packet "
425
 		       "length %d\n", tftp, iob_len ( iobuf ) );
565
 		       "length %d\n", tftp, iob_len ( iobuf ) );
426
-		free_iob ( iobuf );
427
-		return -EINVAL;
566
+		rc = -EINVAL;
567
+		goto done;
428
 	}
568
 	}
429
 
569
 
430
 	/* Extract data */
570
 	/* Extract data */
431
-	block = ntohs ( data->block );
571
+	block = ( ntohs ( data->block ) - 1 );
572
+	offset = ( block * tftp->blksize );
432
 	iob_pull ( iobuf, sizeof ( *data ) );
573
 	iob_pull ( iobuf, sizeof ( *data ) );
433
 	data_len = iob_len ( iobuf );
574
 	data_len = iob_len ( iobuf );
434
-
435
-	/* Check for correct block */
436
-	if ( ( tftp->state == -1 ) && ( block == 1 ) )
437
-		tftp->state = 0;
438
-	if ( block != ( tftp->state + 1 ) ) {
439
-		DBGC ( tftp, "TFTP %p received out-of-order block %d "
440
-		       "(expecting %d)\n", tftp, block, ( tftp->state + 1 ) );
441
-		free_iob ( iobuf );
442
-		return 0;
575
+	if ( data_len > tftp->blksize ) {
576
+		DBGC ( tftp, "TFTP %p received overlength DATA packet "
577
+		       "length %d\n", tftp, data_len );
578
+		rc = -EINVAL;
579
+		goto done;
443
 	}
580
 	}
444
 
581
 
445
 	/* Deliver data */
582
 	/* Deliver data */
446
-	if ( ( rc = xfer_deliver_iob ( &tftp->xfer, iobuf ) ) != 0 ) {
583
+	xfer_seek ( &tftp->xfer, offset, SEEK_SET );
584
+	rc = xfer_deliver_iob ( &tftp->xfer, iobuf );
585
+	iobuf = NULL;
586
+	if ( rc != 0 ) {
447
 		DBGC ( tftp, "TFTP %p could not deliver data: %s\n",
587
 		DBGC ( tftp, "TFTP %p could not deliver data: %s\n",
448
 		       tftp, strerror ( rc ) );
588
 		       tftp, strerror ( rc ) );
449
-		tftp_done ( tftp, rc );
450
-		return rc;
589
+		goto done;
451
 	}
590
 	}
452
 
591
 
592
+	/* Ensure block bitmap is ready */
593
+	if ( ( rc = tftp_presize ( tftp, ( offset + data_len ) ) ) != 0 )
594
+		goto done;
595
+
453
 	/* Mark block as received */
596
 	/* Mark block as received */
454
-	tftp_received ( tftp, block );
597
+	bitmap_set ( &tftp->bitmap, block );
598
+
599
+	/* Acknowledge block */
600
+	tftp_send_packet ( tftp );
455
 
601
 
456
-	/* Finish when final block received */
457
-	if ( data_len < tftp->blksize )
602
+	/* If all blocks have been received, finish. */
603
+	if ( bitmap_full ( &tftp->bitmap ) )
458
 		tftp_done ( tftp, 0 );
604
 		tftp_done ( tftp, 0 );
459
 
605
 
460
-	return 0;
606
+ done:
607
+	free_iob ( iobuf );
608
+	if ( rc )
609
+		tftp_done ( tftp, rc );
610
+	return rc;
461
 }
611
 }
462
 
612
 
463
 /** Translation between TFTP errors and internal error numbers */
613
 /** Translation between TFTP errors and internal error numbers */
506
 /**
656
 /**
507
  * Receive new data
657
  * Receive new data
508
  *
658
  *
509
- * @v udp		UDP connection
510
- * @v data		Received data
511
- * @v len		Length of received data
512
- * @v st_src		Partially-filled source address
513
- * @v st_dest		Partially-filled destination address
659
+ * @v tftp		TFTP connection
660
+ * @v iobuf		I/O buffer
661
+ * @v meta		Transfer metadata, or NULL
662
+ * @ret rc		Return status code
514
  */
663
  */
515
-static int tftp_socket_deliver_iob ( struct xfer_interface *socket,
516
-				     struct io_buffer *iobuf,
517
-				     struct xfer_metadata *meta ) {
518
-	struct tftp_request *tftp =
519
-		container_of ( socket, struct tftp_request, socket );
664
+static int tftp_rx ( struct tftp_request *tftp,
665
+		     struct io_buffer *iobuf,
666
+		     struct xfer_metadata *meta ) {
520
 	struct sockaddr_tcpip *st_src;
667
 	struct sockaddr_tcpip *st_src;
521
 	struct tftp_common *common = iobuf->data;
668
 	struct tftp_common *common = iobuf->data;
522
 	size_t len = iob_len ( iobuf );
669
 	size_t len = iob_len ( iobuf );
541
 
688
 
542
 	/* Filter by TID.  Set TID on first response received */
689
 	/* Filter by TID.  Set TID on first response received */
543
 	st_src = ( struct sockaddr_tcpip * ) meta->src;
690
 	st_src = ( struct sockaddr_tcpip * ) meta->src;
544
-	if ( tftp->state < 0 ) {
691
+	if ( ! tftp->peer.st_family ) {
545
 		memcpy ( &tftp->peer, st_src, sizeof ( tftp->peer ) );
692
 		memcpy ( &tftp->peer, st_src, sizeof ( tftp->peer ) );
546
 		DBGC ( tftp, "TFTP %p using remote port %d\n", tftp,
693
 		DBGC ( tftp, "TFTP %p using remote port %d\n", tftp,
547
 		       ntohs ( tftp->peer.st_port ) );
694
 		       ntohs ( tftp->peer.st_port ) );
575
 	return rc;
722
 	return rc;
576
 }
723
 }
577
 
724
 
725
+/**
726
+ * Receive new data via socket
727
+ *
728
+ * @v socket		Transport layer interface
729
+ * @v iobuf		I/O buffer
730
+ * @v meta		Transfer metadata, or NULL
731
+ * @ret rc		Return status code
732
+ */
733
+static int tftp_socket_deliver_iob ( struct xfer_interface *socket,
734
+				     struct io_buffer *iobuf,
735
+				     struct xfer_metadata *meta ) {
736
+	struct tftp_request *tftp =
737
+		container_of ( socket, struct tftp_request, socket );
738
+
739
+	return tftp_rx ( tftp, iobuf, meta );
740
+}
741
+
578
 /**
742
 /**
579
  * TFTP connection closed by network stack
743
  * TFTP connection closed by network stack
580
  *
744
  *
588
 	DBGC ( tftp, "TFTP %p socket closed: %s\n",
752
 	DBGC ( tftp, "TFTP %p socket closed: %s\n",
589
 	       tftp, strerror ( rc ) );
753
 	       tftp, strerror ( rc ) );
590
 
754
 
755
+	/* Any close counts as an error */
756
+	if ( ! rc )
757
+		rc = -ECONNRESET;
758
+
591
 	tftp_done ( tftp, rc );
759
 	tftp_done ( tftp, rc );
592
 }
760
 }
593
 
761
 
601
 	.deliver_iob	= tftp_socket_deliver_iob,
769
 	.deliver_iob	= tftp_socket_deliver_iob,
602
 	.deliver_raw	= xfer_deliver_as_iob,
770
 	.deliver_raw	= xfer_deliver_as_iob,
603
 };
771
 };
772
+
773
+/**
774
+ * Receive new data via multicast socket
775
+ *
776
+ * @v mc_socket		Multicast transport layer interface
777
+ * @v iobuf		I/O buffer
778
+ * @v meta		Transfer metadata, or NULL
779
+ * @ret rc		Return status code
780
+ */
781
+static int tftp_mc_socket_deliver_iob ( struct xfer_interface *mc_socket,
782
+					struct io_buffer *iobuf,
783
+					struct xfer_metadata *meta ) {
784
+	struct tftp_request *tftp =
785
+		container_of ( mc_socket, struct tftp_request, mc_socket );
786
+
787
+	return tftp_rx ( tftp, iobuf, meta );
788
+}
789
+
790
+/**
791
+ * TFTP multicast connection closed by network stack
792
+ *
793
+ * @v socket		Multicast transport layer interface
794
+ * @v rc		Reason for close
795
+ */
796
+static void tftp_mc_socket_close ( struct xfer_interface *mc_socket,
797
+				   int rc ) {
798
+	struct tftp_request *tftp =
799
+		container_of ( mc_socket, struct tftp_request, mc_socket );
800
+
801
+	DBGC ( tftp, "TFTP %p multicast socket closed: %s\n",
802
+	       tftp, strerror ( rc ) );
803
+
804
+	/* The multicast socket may be closed when we receive a new
805
+	 * OACK and open/reopen the socket; we should not call
806
+	 * tftp_done() at this point.
807
+	 */
808
+}
604
  
809
  
810
+/** TFTP multicast socket operations */
811
+static struct xfer_interface_operations tftp_mc_socket_operations = {
812
+	.close		= tftp_mc_socket_close,
813
+	.vredirect	= xfer_vopen,
814
+	.seek		= ignore_xfer_seek,
815
+	.window		= unlimited_xfer_window,
816
+	.alloc_iob	= default_xfer_alloc_iob,
817
+	.deliver_iob	= tftp_mc_socket_deliver_iob,
818
+	.deliver_raw	= xfer_deliver_as_iob,
819
+};
820
+
605
 /**
821
 /**
606
  * Close TFTP data transfer interface
822
  * Close TFTP data transfer interface
607
  *
823
  *
655
 	xfer_init ( &tftp->xfer, &tftp_xfer_operations, &tftp->refcnt );
871
 	xfer_init ( &tftp->xfer, &tftp_xfer_operations, &tftp->refcnt );
656
 	tftp->uri = uri_get ( uri );
872
 	tftp->uri = uri_get ( uri );
657
 	xfer_init ( &tftp->socket, &tftp_socket_operations, &tftp->refcnt );
873
 	xfer_init ( &tftp->socket, &tftp_socket_operations, &tftp->refcnt );
874
+	xfer_init ( &tftp->mc_socket, &tftp_mc_socket_operations,
875
+		    &tftp->refcnt );
658
 	tftp->blksize = TFTP_DEFAULT_BLKSIZE;
876
 	tftp->blksize = TFTP_DEFAULT_BLKSIZE;
659
-	tftp->state = -1;
877
+	tftp->master = 1;
660
 	tftp->timer.expired = tftp_timer_expired;
878
 	tftp->timer.expired = tftp_timer_expired;
661
 
879
 
662
 	/* Open socket */
880
 	/* Open socket */

Loading…
Cancel
Save