|  | @@ -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 */
 |