Home | History | Annotate | Download | only in udp
      1 /*
      2  * Copyright (C) 2008 Michael Brown <mbrown (at) 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 FILE_LICENCE ( GPL2_OR_LATER );
     20 
     21 #include <stdint.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include <strings.h>
     25 #include <errno.h>
     26 #include <assert.h>
     27 #include <byteswap.h>
     28 #include <gpxe/features.h>
     29 #include <gpxe/iobuf.h>
     30 #include <gpxe/bitmap.h>
     31 #include <gpxe/xfer.h>
     32 #include <gpxe/open.h>
     33 #include <gpxe/uri.h>
     34 #include <gpxe/tcpip.h>
     35 #include <gpxe/timer.h>
     36 #include <gpxe/retry.h>
     37 
     38 /** @file
     39  *
     40  * Scalable Local Area Multicast protocol
     41  *
     42  * The SLAM protocol is supported only by Etherboot; it was designed
     43  * and implemented by Eric Biederman.  A server implementation is
     44  * available in contrib/mini-slamd.  There does not appear to be any
     45  * documentation beyond a few sparse comments in Etherboot's
     46  * proto_slam.c.
     47  *
     48  * SLAM packets use three types of data field:
     49  *
     50  *  Nul : A single NUL (0) byte, used as a list terminator
     51  *
     52  *  Raw : A block of raw data
     53  *
     54  *  Int : A variable-length integer, in big-endian order.  The length
     55  *        of the integer is encoded in the most significant three bits.
     56  *
     57  * Packets received by the client have the following layout:
     58  *
     59  *  Int : Transaction identifier.  This is an opaque value.
     60  *
     61  *  Int : Total number of bytes in the transfer.
     62  *
     63  *  Int : Block size, in bytes.
     64  *
     65  *  Int : Packet sequence number within the transfer (if this packet
     66  *        contains data).
     67  *
     68  *  Raw : Packet data (if this packet contains data).
     69  *
     70  * Packets transmitted by the client consist of a run-length-encoded
     71  * representation of the received-blocks bitmap, looking something
     72  * like:
     73  *
     74  *  Int : Number of consecutive successfully-received packets
     75  *  Int : Number of consecutive missing packets
     76  *  Int : Number of consecutive successfully-received packets
     77  *  Int : Number of consecutive missing packets
     78  *  ....
     79  *  Nul
     80  *
     81  */
     82 
     83 FEATURE ( FEATURE_PROTOCOL, "SLAM", DHCP_EB_FEATURE_SLAM, 1 );
     84 
     85 /** Default SLAM server port */
     86 #define SLAM_DEFAULT_PORT 10000
     87 
     88 /** Default SLAM multicast IP address */
     89 #define SLAM_DEFAULT_MULTICAST_IP \
     90 	( ( 239 << 24 ) | ( 255 << 16 ) | ( 1 << 8 ) | ( 1 << 0 ) )
     91 
     92 /** Default SLAM multicast port */
     93 #define SLAM_DEFAULT_MULTICAST_PORT 10000
     94 
     95 /** Maximum SLAM header length */
     96 #define SLAM_MAX_HEADER_LEN ( 7 /* transaction id */ + 7 /* total_bytes */ + \
     97 			      7 /* block_size */ )
     98 
     99 /** Maximum number of blocks to request per NACK
    100  *
    101  * This is a policy decision equivalent to selecting a TCP window
    102  * size.
    103  */
    104 #define SLAM_MAX_BLOCKS_PER_NACK 4
    105 
    106 /** Maximum SLAM NACK length
    107  *
    108  * We only ever send a NACK for a single range of up to @c
    109  * SLAM_MAX_BLOCKS_PER_NACK blocks.
    110  */
    111 #define SLAM_MAX_NACK_LEN ( 7 /* block */ + 7 /* #blocks */ + 1 /* NUL */ )
    112 
    113 /** SLAM slave timeout */
    114 #define SLAM_SLAVE_TIMEOUT ( 1 * TICKS_PER_SEC )
    115 
    116 /** A SLAM request */
    117 struct slam_request {
    118 	/** Reference counter */
    119 	struct refcnt refcnt;
    120 
    121 	/** Data transfer interface */
    122 	struct xfer_interface xfer;
    123 	/** Unicast socket */
    124 	struct xfer_interface socket;
    125 	/** Multicast socket */
    126 	struct xfer_interface mc_socket;
    127 
    128 	/** Master client retry timer */
    129 	struct retry_timer master_timer;
    130 	/** Slave client retry timer */
    131 	struct retry_timer slave_timer;
    132 
    133 	/** Cached header */
    134 	uint8_t header[SLAM_MAX_HEADER_LEN];
    135 	/** Size of cached header */
    136 	size_t header_len;
    137 	/** Total number of bytes in transfer */
    138 	unsigned long total_bytes;
    139 	/** Transfer block size */
    140 	unsigned long block_size;
    141 	/** Number of blocks in transfer */
    142 	unsigned long num_blocks;
    143 	/** Block bitmap */
    144 	struct bitmap bitmap;
    145 	/** NACK sent flag */
    146 	int nack_sent;
    147 };
    148 
    149 /**
    150  * Free a SLAM request
    151  *
    152  * @v refcnt		Reference counter
    153  */
    154 static void slam_free ( struct refcnt *refcnt ) {
    155 	struct slam_request *slam =
    156 		container_of ( refcnt, struct slam_request, refcnt );
    157 
    158 	bitmap_free ( &slam->bitmap );
    159 	free ( slam );
    160 }
    161 
    162 /**
    163  * Mark SLAM request as complete
    164  *
    165  * @v slam		SLAM request
    166  * @v rc		Return status code
    167  */
    168 static void slam_finished ( struct slam_request *slam, int rc ) {
    169 	static const uint8_t slam_disconnect[] = { 0 };
    170 
    171 	DBGC ( slam, "SLAM %p finished with status code %d (%s)\n",
    172 	       slam, rc, strerror ( rc ) );
    173 
    174 	/* Send a disconnect message if we ever sent anything to the
    175 	 * server.
    176 	 */
    177 	if ( slam->nack_sent ) {
    178 		xfer_deliver_raw ( &slam->socket, slam_disconnect,
    179 				   sizeof ( slam_disconnect ) );
    180 	}
    181 
    182 	/* Stop the retry timers */
    183 	stop_timer ( &slam->master_timer );
    184 	stop_timer ( &slam->slave_timer );
    185 
    186 	/* Close all data transfer interfaces */
    187 	xfer_nullify ( &slam->socket );
    188 	xfer_close ( &slam->socket, rc );
    189 	xfer_nullify ( &slam->mc_socket );
    190 	xfer_close ( &slam->mc_socket, rc );
    191 	xfer_nullify ( &slam->xfer );
    192 	xfer_close ( &slam->xfer, rc );
    193 }
    194 
    195 /****************************************************************************
    196  *
    197  * TX datapath
    198  *
    199  */
    200 
    201 /**
    202  * Add a variable-length value to a SLAM packet
    203  *
    204  * @v slam		SLAM request
    205  * @v iobuf		I/O buffer
    206  * @v value		Value to add
    207  * @ret rc		Return status code
    208  *
    209  * Adds a variable-length value to the end of an I/O buffer.  Will
    210  * always leave at least one byte of tailroom in the I/O buffer (to
    211  * allow space for the terminating NUL).
    212  */
    213 static int slam_put_value ( struct slam_request *slam,
    214 			    struct io_buffer *iobuf, unsigned long value ) {
    215 	uint8_t *data;
    216 	size_t len;
    217 	unsigned int i;
    218 
    219 	/* Calculate variable length required to store value.  Always
    220 	 * leave at least one byte in the I/O buffer.
    221 	 */
    222 	len = ( ( flsl ( value ) + 10 ) / 8 );
    223 	if ( len >= iob_tailroom ( iobuf ) ) {
    224 		DBGC2 ( slam, "SLAM %p cannot add %zd-byte value\n",
    225 			slam, len );
    226 		return -ENOBUFS;
    227 	}
    228 	/* There is no valid way within the protocol that we can end
    229 	 * up trying to push a full-sized long (i.e. without space for
    230 	 * the length encoding).
    231 	 */
    232 	assert ( len <= sizeof ( value ) );
    233 
    234 	/* Add value */
    235 	data = iob_put ( iobuf, len );
    236 	for ( i = len ; i-- ; ) {
    237 		data[i] = value;
    238 		value >>= 8;
    239 	}
    240 	*data |= ( len << 5 );
    241 	assert ( value == 0 );
    242 
    243 	return 0;
    244 }
    245 
    246 /**
    247  * Send SLAM NACK packet
    248  *
    249  * @v slam		SLAM request
    250  * @ret rc		Return status code
    251  */
    252 static int slam_tx_nack ( struct slam_request *slam ) {
    253 	struct io_buffer *iobuf;
    254 	unsigned long first_block;
    255 	unsigned long num_blocks;
    256 	uint8_t *nul;
    257 	int rc;
    258 
    259 	/* Mark NACK as sent, so that we know we have to disconnect later */
    260 	slam->nack_sent = 1;
    261 
    262 	/* Allocate I/O buffer */
    263 	iobuf = xfer_alloc_iob ( &slam->socket,	SLAM_MAX_NACK_LEN );
    264 	if ( ! iobuf ) {
    265 		DBGC ( slam, "SLAM %p could not allocate I/O buffer\n",
    266 		       slam );
    267 		return -ENOMEM;
    268 	}
    269 
    270 	/* Construct NACK.  We always request only a single packet;
    271 	 * this allows us to force multicast-TFTP-style flow control
    272 	 * on the SLAM server, which will otherwise just blast the
    273 	 * data out as fast as it can.  On a gigabit network, without
    274 	 * RX checksumming, this would inevitably cause packet drops.
    275 	 */
    276 	first_block = bitmap_first_gap ( &slam->bitmap );
    277 	for ( num_blocks = 1 ; ; num_blocks++ ) {
    278 		if ( num_blocks >= SLAM_MAX_BLOCKS_PER_NACK )
    279 			break;
    280 		if ( ( first_block + num_blocks ) >= slam->num_blocks )
    281 			break;
    282 		if ( bitmap_test ( &slam->bitmap,
    283 				   ( first_block + num_blocks ) ) )
    284 			break;
    285 	}
    286 	if ( first_block ) {
    287 		DBGCP ( slam, "SLAM %p transmitting NACK for blocks "
    288 			"%ld-%ld\n", slam, first_block,
    289 			( first_block + num_blocks - 1 ) );
    290 	} else {
    291 		DBGC ( slam, "SLAM %p transmitting initial NACK for blocks "
    292 		       "0-%ld\n", slam, ( num_blocks - 1 ) );
    293 	}
    294 	if ( ( rc = slam_put_value ( slam, iobuf, first_block ) ) != 0 )
    295 		return rc;
    296 	if ( ( rc = slam_put_value ( slam, iobuf, num_blocks ) ) != 0 )
    297 		return rc;
    298 	nul = iob_put ( iobuf, 1 );
    299 	*nul = 0;
    300 
    301 	/* Transmit packet */
    302 	return xfer_deliver_iob ( &slam->socket, iobuf );
    303 }
    304 
    305 /**
    306  * Handle SLAM master client retry timer expiry
    307  *
    308  * @v timer		Master retry timer
    309  * @v fail		Failure indicator
    310  */
    311 static void slam_master_timer_expired ( struct retry_timer *timer,
    312 					int fail ) {
    313 	struct slam_request *slam =
    314 		container_of ( timer, struct slam_request, master_timer );
    315 
    316 	if ( fail ) {
    317 		/* Allow timer to stop running.  We will terminate the
    318 		 * connection only if the slave timer times out.
    319 		 */
    320 		DBGC ( slam, "SLAM %p giving up acting as master client\n",
    321 		       slam );
    322 	} else {
    323 		/* Retransmit NACK */
    324 		start_timer ( timer );
    325 		slam_tx_nack ( slam );
    326 	}
    327 }
    328 
    329 /**
    330  * Handle SLAM slave client retry timer expiry
    331  *
    332  * @v timer		Master retry timer
    333  * @v fail		Failure indicator
    334  */
    335 static void slam_slave_timer_expired ( struct retry_timer *timer,
    336 					int fail ) {
    337 	struct slam_request *slam =
    338 		container_of ( timer, struct slam_request, slave_timer );
    339 
    340 	if ( fail ) {
    341 		/* Terminate connection */
    342 		slam_finished ( slam, -ETIMEDOUT );
    343 	} else {
    344 		/* Try sending a NACK */
    345 		DBGC ( slam, "SLAM %p trying to become master client\n",
    346 		       slam );
    347 		start_timer ( timer );
    348 		slam_tx_nack ( slam );
    349 	}
    350 }
    351 
    352 /****************************************************************************
    353  *
    354  * RX datapath
    355  *
    356  */
    357 
    358 /**
    359  * Read and strip a variable-length value from a SLAM packet
    360  *
    361  * @v slam		SLAM request
    362  * @v iobuf		I/O buffer
    363  * @v value		Value to fill in, or NULL to ignore value
    364  * @ret rc		Return status code
    365  *
    366  * Reads a variable-length value from the start of the I/O buffer.
    367  */
    368 static int slam_pull_value ( struct slam_request *slam,
    369 			     struct io_buffer *iobuf,
    370 			     unsigned long *value ) {
    371 	uint8_t *data;
    372 	size_t len;
    373 
    374 	/* Sanity check */
    375 	if ( iob_len ( iobuf ) == 0 ) {
    376 		DBGC ( slam, "SLAM %p empty value\n", slam );
    377 		return -EINVAL;
    378 	}
    379 
    380 	/* Read and verify length of value */
    381 	data = iobuf->data;
    382 	len = ( *data >> 5 );
    383 	if ( ( len == 0 ) ||
    384 	     ( value && ( len > sizeof ( *value ) ) ) ) {
    385 		DBGC ( slam, "SLAM %p invalid value length %zd bytes\n",
    386 		       slam, len );
    387 		return -EINVAL;
    388 	}
    389 	if ( len > iob_len ( iobuf ) ) {
    390 		DBGC ( slam, "SLAM %p value extends beyond I/O buffer\n",
    391 		       slam );
    392 		return -EINVAL;
    393 	}
    394 
    395 	/* Read value */
    396 	iob_pull ( iobuf, len );
    397 	*value = ( *data & 0x1f );
    398 	while ( --len ) {
    399 		*value <<= 8;
    400 		*value |= *(++data);
    401 	}
    402 
    403 	return 0;
    404 }
    405 
    406 /**
    407  * Read and strip SLAM header
    408  *
    409  * @v slam		SLAM request
    410  * @v iobuf		I/O buffer
    411  * @ret rc		Return status code
    412  */
    413 static int slam_pull_header ( struct slam_request *slam,
    414 			      struct io_buffer *iobuf ) {
    415 	void *header = iobuf->data;
    416 	int rc;
    417 
    418 	/* If header matches cached header, just pull it and return */
    419 	if ( ( slam->header_len <= iob_len ( iobuf ) ) &&
    420 	     ( memcmp ( slam->header, iobuf->data, slam->header_len ) == 0 )){
    421 		iob_pull ( iobuf, slam->header_len );
    422 		return 0;
    423 	}
    424 
    425 	DBGC ( slam, "SLAM %p detected changed header; resetting\n", slam );
    426 
    427 	/* Read and strip transaction ID, total number of bytes, and
    428 	 * block size.
    429 	 */
    430 	if ( ( rc = slam_pull_value ( slam, iobuf, NULL ) ) != 0 )
    431 		return rc;
    432 	if ( ( rc = slam_pull_value ( slam, iobuf,
    433 				      &slam->total_bytes ) ) != 0 )
    434 		return rc;
    435 	if ( ( rc = slam_pull_value ( slam, iobuf,
    436 				      &slam->block_size ) ) != 0 )
    437 		return rc;
    438 
    439 	/* Update the cached header */
    440 	slam->header_len = ( iobuf->data - header );
    441 	assert ( slam->header_len <= sizeof ( slam->header ) );
    442 	memcpy ( slam->header, header, slam->header_len );
    443 
    444 	/* Calculate number of blocks */
    445 	slam->num_blocks = ( ( slam->total_bytes + slam->block_size - 1 ) /
    446 			     slam->block_size );
    447 
    448 	DBGC ( slam, "SLAM %p has total bytes %ld, block size %ld, num "
    449 	       "blocks %ld\n", slam, slam->total_bytes, slam->block_size,
    450 	       slam->num_blocks );
    451 
    452 	/* Discard and reset the bitmap */
    453 	bitmap_free ( &slam->bitmap );
    454 	memset ( &slam->bitmap, 0, sizeof ( slam->bitmap ) );
    455 
    456 	/* Allocate a new bitmap */
    457 	if ( ( rc = bitmap_resize ( &slam->bitmap,
    458 				    slam->num_blocks ) ) != 0 ) {
    459 		/* Failure to allocate a bitmap is fatal */
    460 		DBGC ( slam, "SLAM %p could not allocate bitmap for %ld "
    461 		       "blocks: %s\n", slam, slam->num_blocks,
    462 		       strerror ( rc ) );
    463 		slam_finished ( slam, rc );
    464 		return rc;
    465 	}
    466 
    467 	/* Notify recipient of file size */
    468 	xfer_seek ( &slam->xfer, slam->total_bytes, SEEK_SET );
    469 
    470 	return 0;
    471 }
    472 
    473 /**
    474  * Receive SLAM data packet
    475  *
    476  * @v mc_socket		SLAM multicast socket
    477  * @v iobuf		I/O buffer
    478  * @ret rc		Return status code
    479  */
    480 static int slam_mc_socket_deliver ( struct xfer_interface *mc_socket,
    481 				    struct io_buffer *iobuf,
    482 				    struct xfer_metadata *rx_meta __unused ) {
    483 	struct slam_request *slam =
    484 		container_of ( mc_socket, struct slam_request, mc_socket );
    485 	struct xfer_metadata meta;
    486 	unsigned long packet;
    487 	size_t len;
    488 	int rc;
    489 
    490 	/* Stop the master client timer.  Restart the slave client timer. */
    491 	stop_timer ( &slam->master_timer );
    492 	stop_timer ( &slam->slave_timer );
    493 	start_timer_fixed ( &slam->slave_timer, SLAM_SLAVE_TIMEOUT );
    494 
    495 	/* Read and strip packet header */
    496 	if ( ( rc = slam_pull_header ( slam, iobuf ) ) != 0 )
    497 		goto err_discard;
    498 
    499 	/* Read and strip packet number */
    500 	if ( ( rc = slam_pull_value ( slam, iobuf, &packet ) ) != 0 )
    501 		goto err_discard;
    502 
    503 	/* Sanity check packet number */
    504 	if ( packet >= slam->num_blocks ) {
    505 		DBGC ( slam, "SLAM %p received out-of-range packet %ld "
    506 		       "(num_blocks=%ld)\n", slam, packet, slam->num_blocks );
    507 		rc = -EINVAL;
    508 		goto err_discard;
    509 	}
    510 
    511 	/* Sanity check length */
    512 	len = iob_len ( iobuf );
    513 	if ( len > slam->block_size ) {
    514 		DBGC ( slam, "SLAM %p received oversize packet of %zd bytes "
    515 		       "(block_size=%ld)\n", slam, len, slam->block_size );
    516 		rc = -EINVAL;
    517 		goto err_discard;
    518 	}
    519 	if ( ( packet != ( slam->num_blocks - 1 ) ) &&
    520 	     ( len < slam->block_size ) ) {
    521 		DBGC ( slam, "SLAM %p received short packet of %zd bytes "
    522 		       "(block_size=%ld)\n", slam, len, slam->block_size );
    523 		rc = -EINVAL;
    524 		goto err_discard;
    525 	}
    526 
    527 	/* If we have already seen this packet, discard it */
    528 	if ( bitmap_test ( &slam->bitmap, packet ) ) {
    529 		goto discard;
    530 	}
    531 
    532 	/* Pass to recipient */
    533 	memset ( &meta, 0, sizeof ( meta ) );
    534 	meta.whence = SEEK_SET;
    535 	meta.offset = ( packet * slam->block_size );
    536 	if ( ( rc = xfer_deliver_iob_meta ( &slam->xfer, iobuf,
    537 					    &meta ) ) != 0 )
    538 		goto err;
    539 
    540 	/* Mark block as received */
    541 	bitmap_set ( &slam->bitmap, packet );
    542 
    543 	/* If we have received all blocks, terminate */
    544 	if ( bitmap_full ( &slam->bitmap ) )
    545 		slam_finished ( slam, 0 );
    546 
    547 	return 0;
    548 
    549  err_discard:
    550  discard:
    551 	free_iob ( iobuf );
    552  err:
    553 	return rc;
    554 }
    555 
    556 /**
    557  * Receive SLAM non-data packet
    558  *
    559  * @v socket		SLAM unicast socket
    560  * @v iobuf		I/O buffer
    561  * @ret rc		Return status code
    562  */
    563 static int slam_socket_deliver ( struct xfer_interface *socket,
    564 				 struct io_buffer *iobuf,
    565 				 struct xfer_metadata *rx_meta __unused ) {
    566 	struct slam_request *slam =
    567 		container_of ( socket, struct slam_request, socket );
    568 	int rc;
    569 
    570 	/* Restart the master client timer */
    571 	stop_timer ( &slam->master_timer );
    572 	start_timer ( &slam->master_timer );
    573 
    574 	/* Read and strip packet header */
    575 	if ( ( rc = slam_pull_header ( slam, iobuf ) ) != 0 )
    576 		goto discard;
    577 
    578 	/* Sanity check */
    579 	if ( iob_len ( iobuf ) != 0 ) {
    580 		DBGC ( slam, "SLAM %p received trailing garbage:\n", slam );
    581 		DBGC_HD ( slam, iobuf->data, iob_len ( iobuf ) );
    582 		rc = -EINVAL;
    583 		goto discard;
    584 	}
    585 
    586 	/* Discard packet */
    587 	free_iob ( iobuf );
    588 
    589 	/* Send NACK in reply */
    590 	slam_tx_nack ( slam );
    591 
    592 	return 0;
    593 
    594  discard:
    595 	free_iob ( iobuf );
    596 	return rc;
    597 
    598 }
    599 
    600 /**
    601  * Close SLAM unicast socket
    602  *
    603  * @v socket		SLAM unicast socket
    604  * @v rc		Reason for close
    605  */
    606 static void slam_socket_close ( struct xfer_interface *socket, int rc ) {
    607 	struct slam_request *slam =
    608 		container_of ( socket, struct slam_request, socket );
    609 
    610 	DBGC ( slam, "SLAM %p unicast socket closed: %s\n",
    611 	       slam, strerror ( rc ) );
    612 
    613 	slam_finished ( slam, rc );
    614 }
    615 
    616 /** SLAM unicast socket data transfer operations */
    617 static struct xfer_interface_operations slam_socket_operations = {
    618 	.close		= slam_socket_close,
    619 	.vredirect	= xfer_vreopen,
    620 	.window		= unlimited_xfer_window,
    621 	.alloc_iob	= default_xfer_alloc_iob,
    622 	.deliver_iob	= slam_socket_deliver,
    623 	.deliver_raw	= xfer_deliver_as_iob,
    624 };
    625 
    626 /**
    627  * Close SLAM multicast socket
    628  *
    629  * @v mc_socket		SLAM multicast socket
    630  * @v rc		Reason for close
    631  */
    632 static void slam_mc_socket_close ( struct xfer_interface *mc_socket, int rc ){
    633 	struct slam_request *slam =
    634 		container_of ( mc_socket, struct slam_request, mc_socket );
    635 
    636 	DBGC ( slam, "SLAM %p multicast socket closed: %s\n",
    637 	       slam, strerror ( rc ) );
    638 
    639 	slam_finished ( slam, rc );
    640 }
    641 
    642 /** SLAM multicast socket data transfer operations */
    643 static struct xfer_interface_operations slam_mc_socket_operations = {
    644 	.close		= slam_mc_socket_close,
    645 	.vredirect	= xfer_vreopen,
    646 	.window		= unlimited_xfer_window,
    647 	.alloc_iob	= default_xfer_alloc_iob,
    648 	.deliver_iob	= slam_mc_socket_deliver,
    649 	.deliver_raw	= xfer_deliver_as_iob,
    650 };
    651 
    652 /****************************************************************************
    653  *
    654  * Data transfer interface
    655  *
    656  */
    657 
    658 /**
    659  * Close SLAM data transfer interface
    660  *
    661  * @v xfer		SLAM data transfer interface
    662  * @v rc		Reason for close
    663  */
    664 static void slam_xfer_close ( struct xfer_interface *xfer, int rc ) {
    665 	struct slam_request *slam =
    666 		container_of ( xfer, struct slam_request, xfer );
    667 
    668 	DBGC ( slam, "SLAM %p data transfer interface closed: %s\n",
    669 	       slam, strerror ( rc ) );
    670 
    671 	slam_finished ( slam, rc );
    672 }
    673 
    674 /** SLAM data transfer operations */
    675 static struct xfer_interface_operations slam_xfer_operations = {
    676 	.close		= slam_xfer_close,
    677 	.vredirect	= ignore_xfer_vredirect,
    678 	.window		= unlimited_xfer_window,
    679 	.alloc_iob	= default_xfer_alloc_iob,
    680 	.deliver_iob	= xfer_deliver_as_raw,
    681 	.deliver_raw	= ignore_xfer_deliver_raw,
    682 };
    683 
    684 /**
    685  * Parse SLAM URI multicast address
    686  *
    687  * @v slam		SLAM request
    688  * @v path		Path portion of x-slam:// URI
    689  * @v address		Socket address to fill in
    690  * @ret rc		Return status code
    691  */
    692 static int slam_parse_multicast_address ( struct slam_request *slam,
    693 					  const char *path,
    694 					  struct sockaddr_in *address ) {
    695 	char path_dup[ strlen ( path ) /* no +1 */ ];
    696 	char *sep;
    697 	char *end;
    698 
    699 	/* Create temporary copy of path, minus the leading '/' */
    700 	assert ( *path == '/' );
    701 	memcpy ( path_dup, ( path + 1 ) , sizeof ( path_dup ) );
    702 
    703 	/* Parse port, if present */
    704 	sep = strchr ( path_dup, ':' );
    705 	if ( sep ) {
    706 		*(sep++) = '\0';
    707 		address->sin_port = htons ( strtoul ( sep, &end, 0 ) );
    708 		if ( *end != '\0' ) {
    709 			DBGC ( slam, "SLAM %p invalid multicast port "
    710 			       "\"%s\"\n", slam, sep );
    711 			return -EINVAL;
    712 		}
    713 	}
    714 
    715 	/* Parse address */
    716 	if ( inet_aton ( path_dup, &address->sin_addr ) == 0 ) {
    717 		DBGC ( slam, "SLAM %p invalid multicast address \"%s\"\n",
    718 		       slam, path_dup );
    719 		return -EINVAL;
    720 	}
    721 
    722 	return 0;
    723 }
    724 
    725 /**
    726  * Initiate a SLAM request
    727  *
    728  * @v xfer		Data transfer interface
    729  * @v uri		Uniform Resource Identifier
    730  * @ret rc		Return status code
    731  */
    732 static int slam_open ( struct xfer_interface *xfer, struct uri *uri ) {
    733 	static const struct sockaddr_in default_multicast = {
    734 		.sin_family = AF_INET,
    735 		.sin_port = htons ( SLAM_DEFAULT_MULTICAST_PORT ),
    736 		.sin_addr = { htonl ( SLAM_DEFAULT_MULTICAST_IP ) },
    737 	};
    738 	struct slam_request *slam;
    739 	struct sockaddr_tcpip server;
    740 	struct sockaddr_in multicast;
    741 	int rc;
    742 
    743 	/* Sanity checks */
    744 	if ( ! uri->host )
    745 		return -EINVAL;
    746 
    747 	/* Allocate and populate structure */
    748 	slam = zalloc ( sizeof ( *slam ) );
    749 	if ( ! slam )
    750 		return -ENOMEM;
    751 	slam->refcnt.free = slam_free;
    752 	xfer_init ( &slam->xfer, &slam_xfer_operations, &slam->refcnt );
    753 	xfer_init ( &slam->socket, &slam_socket_operations, &slam->refcnt );
    754 	xfer_init ( &slam->mc_socket, &slam_mc_socket_operations,
    755 		    &slam->refcnt );
    756 	slam->master_timer.expired = slam_master_timer_expired;
    757 	slam->slave_timer.expired = slam_slave_timer_expired;
    758 	/* Fake an invalid cached header of { 0x00, ... } */
    759 	slam->header_len = 1;
    760 	/* Fake parameters for initial NACK */
    761 	slam->num_blocks = 1;
    762 	if ( ( rc = bitmap_resize ( &slam->bitmap, 1 ) ) != 0 ) {
    763 		DBGC ( slam, "SLAM %p could not allocate initial bitmap: "
    764 		       "%s\n", slam, strerror ( rc ) );
    765 		goto err;
    766 	}
    767 
    768 	/* Open unicast socket */
    769 	memset ( &server, 0, sizeof ( server ) );
    770 	server.st_port = htons ( uri_port ( uri, SLAM_DEFAULT_PORT ) );
    771 	if ( ( rc = xfer_open_named_socket ( &slam->socket, SOCK_DGRAM,
    772 					     ( struct sockaddr * ) &server,
    773 					     uri->host, NULL ) ) != 0 ) {
    774 		DBGC ( slam, "SLAM %p could not open unicast socket: %s\n",
    775 		       slam, strerror ( rc ) );
    776 		goto err;
    777 	}
    778 
    779 	/* Open multicast socket */
    780 	memcpy ( &multicast, &default_multicast, sizeof ( multicast ) );
    781 	if ( uri->path &&
    782 	     ( ( rc = slam_parse_multicast_address ( slam, uri->path,
    783 						     &multicast ) ) != 0 ) ) {
    784 		goto err;
    785 	}
    786 	if ( ( rc = xfer_open_socket ( &slam->mc_socket, SOCK_DGRAM,
    787 				 ( struct sockaddr * ) &multicast,
    788 				 ( struct sockaddr * ) &multicast ) ) != 0 ) {
    789 		DBGC ( slam, "SLAM %p could not open multicast socket: %s\n",
    790 		       slam, strerror ( rc ) );
    791 		goto err;
    792 	}
    793 
    794 	/* Start slave retry timer */
    795 	start_timer_fixed ( &slam->slave_timer, SLAM_SLAVE_TIMEOUT );
    796 
    797 	/* Attach to parent interface, mortalise self, and return */
    798 	xfer_plug_plug ( &slam->xfer, xfer );
    799 	ref_put ( &slam->refcnt );
    800 	return 0;
    801 
    802  err:
    803 	slam_finished ( slam, rc );
    804 	ref_put ( &slam->refcnt );
    805 	return rc;
    806 }
    807 
    808 /** SLAM URI opener */
    809 struct uri_opener slam_uri_opener __uri_opener = {
    810 	.scheme	= "x-slam",
    811 	.open	= slam_open,
    812 };
    813