Browse Source

Add RFC2090 TFTP multicast support.

tags/v0.9.3
Michael Brown 16 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

@@ -0,0 +1,97 @@
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

@@ -0,0 +1,83 @@
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,6 +50,7 @@
50 50
 #define ERRFILE_settings	       ( ERRFILE_CORE | 0x000c0000 )
51 51
 #define ERRFILE_vsprintf	       ( ERRFILE_CORE | 0x000d0000 )
52 52
 #define ERRFILE_xfer		       ( ERRFILE_CORE | 0x000e0000 )
53
+#define ERRFILE_bitmap		       ( ERRFILE_CORE | 0x000f0000 )
53 54
 
54 55
 #define ERRFILE_eisa		     ( ERRFILE_DRIVER | 0x00000000 )
55 56
 #define ERRFILE_isa		     ( ERRFILE_DRIVER | 0x00010000 )

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

@@ -31,6 +31,7 @@
31 31
 #include <gpxe/tcpip.h>
32 32
 #include <gpxe/retry.h>
33 33
 #include <gpxe/features.h>
34
+#include <gpxe/bitmap.h>
34 35
 #include <gpxe/tftp.h>
35 36
 
36 37
 /** @file
@@ -56,6 +57,8 @@ struct tftp_request {
56 57
 	struct uri *uri;
57 58
 	/** Transport layer interface */
58 59
 	struct xfer_interface socket;
60
+	/** Multicast transport layer interface */
61
+	struct xfer_interface mc_socket;
59 62
 
60 63
 	/** Data block size
61 64
 	 *
@@ -71,24 +74,38 @@ struct tftp_request {
71 74
 	 * "tsize" option, this value will be zero.
72 75
 	 */
73 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 89
 	/** Peer address
87 90
 	 *
88 91
 	 * The peer address is determined by the first response
89 92
 	 * received to the TFTP RRQ.
90 93
 	 */
91 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 109
 	/** Retransmission timer */
93 110
 	struct retry_timer timer;
94 111
 };
@@ -103,6 +120,7 @@ static void tftp_free ( struct refcnt *refcnt ) {
103 120
 		container_of ( refcnt, struct tftp_request, refcnt );
104 121
 
105 122
 	uri_put ( tftp->uri );
123
+	bitmap_free ( &tftp->bitmap );
106 124
 	free ( tftp );
107 125
 }
108 126
 
@@ -123,10 +141,48 @@ static void tftp_done ( struct tftp_request *tftp, int rc ) {
123 141
 	/* Close all data transfer interfaces */
124 142
 	xfer_nullify ( &tftp->socket );
125 143
 	xfer_close ( &tftp->socket, rc );
144
+	xfer_nullify ( &tftp->mc_socket );
145
+	xfer_close ( &tftp->mc_socket, rc );
126 146
 	xfer_nullify ( &tftp->xfer );
127 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 187
  * TFTP requested blocksize
132 188
  *
@@ -157,7 +213,8 @@ static int tftp_send_rrq ( struct tftp_request *tftp ) {
157 213
 	size_t len = ( sizeof ( *rrq ) + strlen ( path ) + 1 /* NUL */
158 214
 		       + 5 + 1 /* "octet" + NUL */
159 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 218
 	struct io_buffer *iobuf;
162 219
 
163 220
 	DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, path );
@@ -172,8 +229,9 @@ static int tftp_send_rrq ( struct tftp_request *tftp ) {
172 229
 	rrq->opcode = htons ( TFTP_RRQ );
173 230
 	iob_put ( iobuf,
174 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 236
 	/* RRQ always goes to the address specified in the initial
179 237
 	 * xfer_open() call
@@ -193,9 +251,11 @@ static int tftp_send_ack ( struct tftp_request *tftp ) {
193 251
 	struct xfer_metadata meta = {
194 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 260
 	/* Allocate buffer */
201 261
 	iobuf = xfer_alloc_iob ( &tftp->socket, sizeof ( *ack ) );
@@ -205,28 +265,34 @@ static int tftp_send_ack ( struct tftp_request *tftp ) {
205 265
 	/* Build ACK */
206 266
 	ack = iob_put ( iobuf, sizeof ( *ack ) );
207 267
 	ack->opcode = htons ( TFTP_ACK );
208
-	ack->block = htons ( tftp->state );
268
+	ack->block = htons ( block );
209 269
 
210 270
 	/* ACK always goes to the peer recorded from the RRQ response */
211 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 277
  * @v tftp		TFTP connection
218 278
  * @ret rc		Return status code
219 279
  */
220 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 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 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,24 +313,6 @@ static void tftp_timer_expired ( struct retry_timer *timer, int fail ) {
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 317
  * Process TFTP "blksize" option
270 318
  *
@@ -306,9 +354,86 @@ static int tftp_process_tsize ( struct tftp_request *tftp,
306 354
 	}
307 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 438
 	return 0;
314 439
 }
@@ -330,6 +455,7 @@ struct tftp_option {
330 455
 static struct tftp_option tftp_options[] = {
331 456
 	{ "blksize", tftp_process_blksize },
332 457
 	{ "tsize", tftp_process_tsize },
458
+	{ "multicast", tftp_process_multicast },
333 459
 	{ NULL, NULL }
334 460
 };
335 461
 
@@ -353,7 +479,8 @@ static int tftp_process_option ( struct tftp_request *tftp,
353 479
 	DBGC ( tftp, "TFTP %p received unknown option \"%s\" = \"%s\"\n",
354 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,12 +502,14 @@ static int tftp_rx_oack ( struct tftp_request *tftp, void *buf, size_t len ) {
375 502
 	if ( len < sizeof ( *oack ) ) {
376 503
 		DBGC ( tftp, "TFTP %p received underlength OACK packet "
377 504
 		       "length %d\n", tftp, len );
378
-		return -EINVAL;
505
+		rc = -EINVAL;
506
+		goto done;
379 507
 	}
380 508
 	if ( end[-1] != '\0' ) {
381 509
 		DBGC ( tftp, "TFTP %p received OACK missing final NUL\n",
382 510
 		       tftp );
383
-		return -EINVAL;
511
+		rc = -EINVAL;
512
+		goto done;
384 513
 	}
385 514
 
386 515
 	/* Process each option in turn */
@@ -390,17 +519,27 @@ static int tftp_rx_oack ( struct tftp_request *tftp, void *buf, size_t len ) {
390 519
 		if ( value == end ) {
391 520
 			DBGC ( tftp, "TFTP %p received OACK missing value "
392 521
 			       "for option \"%s\"\n", tftp, name );
393
-			return -EINVAL;
522
+			rc = -EINVAL;
523
+			goto done;
394 524
 		}
395 525
 		if ( ( rc = tftp_process_option ( tftp, name, value ) ) != 0 )
396
-			return rc;
526
+			goto done;
397 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,6 +555,7 @@ static int tftp_rx_data ( struct tftp_request *tftp,
416 555
 			  struct io_buffer *iobuf ) {
417 556
 	struct tftp_data *data = iobuf->data;
418 557
 	int block;
558
+	off_t offset;
419 559
 	size_t data_len;
420 560
 	int rc;
421 561
 
@@ -423,41 +563,51 @@ static int tftp_rx_data ( struct tftp_request *tftp,
423 563
 	if ( iob_len ( iobuf ) < sizeof ( *data ) ) {
424 564
 		DBGC ( tftp, "TFTP %p received underlength DATA packet "
425 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 570
 	/* Extract data */
431
-	block = ntohs ( data->block );
571
+	block = ( ntohs ( data->block ) - 1 );
572
+	offset = ( block * tftp->blksize );
432 573
 	iob_pull ( iobuf, sizeof ( *data ) );
433 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 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 587
 		DBGC ( tftp, "TFTP %p could not deliver data: %s\n",
448 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 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 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 613
 /** Translation between TFTP errors and internal error numbers */
@@ -506,17 +656,14 @@ static int tftp_rx_error ( struct tftp_request *tftp, void *buf, size_t len ) {
506 656
 /**
507 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 667
 	struct sockaddr_tcpip *st_src;
521 668
 	struct tftp_common *common = iobuf->data;
522 669
 	size_t len = iob_len ( iobuf );
@@ -541,7 +688,7 @@ static int tftp_socket_deliver_iob ( struct xfer_interface *socket,
541 688
 
542 689
 	/* Filter by TID.  Set TID on first response received */
543 690
 	st_src = ( struct sockaddr_tcpip * ) meta->src;
544
-	if ( tftp->state < 0 ) {
691
+	if ( ! tftp->peer.st_family ) {
545 692
 		memcpy ( &tftp->peer, st_src, sizeof ( tftp->peer ) );
546 693
 		DBGC ( tftp, "TFTP %p using remote port %d\n", tftp,
547 694
 		       ntohs ( tftp->peer.st_port ) );
@@ -575,6 +722,23 @@ static int tftp_socket_deliver_iob ( struct xfer_interface *socket,
575 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 743
  * TFTP connection closed by network stack
580 744
  *
@@ -588,6 +752,10 @@ static void tftp_socket_close ( struct xfer_interface *socket, int rc ) {
588 752
 	DBGC ( tftp, "TFTP %p socket closed: %s\n",
589 753
 	       tftp, strerror ( rc ) );
590 754
 
755
+	/* Any close counts as an error */
756
+	if ( ! rc )
757
+		rc = -ECONNRESET;
758
+
591 759
 	tftp_done ( tftp, rc );
592 760
 }
593 761
 
@@ -601,7 +769,55 @@ static struct xfer_interface_operations tftp_socket_operations = {
601 769
 	.deliver_iob	= tftp_socket_deliver_iob,
602 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 822
  * Close TFTP data transfer interface
607 823
  *
@@ -655,8 +871,10 @@ int tftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
655 871
 	xfer_init ( &tftp->xfer, &tftp_xfer_operations, &tftp->refcnt );
656 872
 	tftp->uri = uri_get ( uri );
657 873
 	xfer_init ( &tftp->socket, &tftp_socket_operations, &tftp->refcnt );
874
+	xfer_init ( &tftp->mc_socket, &tftp_mc_socket_operations,
875
+		    &tftp->refcnt );
658 876
 	tftp->blksize = TFTP_DEFAULT_BLKSIZE;
659
-	tftp->state = -1;
877
+	tftp->master = 1;
660 878
 	tftp->timer.expired = tftp_timer_expired;
661 879
 
662 880
 	/* Open socket */

Loading…
Cancel
Save