#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <assert.h>
#include <byteswap.h>
#include <gpxe/features.h>
#include <gpxe/iobuf.h>
#include <gpxe/bitmap.h>
#include <gpxe/xfer.h>
#include <gpxe/open.h>
#include <gpxe/uri.h>
#include <gpxe/tcpip.h>
#include <gpxe/timer.h>
#include <gpxe/retry.h>
Go to the source code of this file.
Data Structures | |
| struct | slam_request |
| A SLAM request. More... | |
Defines | |
| #define | SLAM_DEFAULT_PORT 10000 |
| Default SLAM server port. | |
| #define | SLAM_DEFAULT_MULTICAST_IP ( ( 239 << 24 ) | ( 255 << 16 ) | ( 1 << 8 ) | ( 1 << 0 ) ) |
| Default SLAM multicast IP address. | |
| #define | SLAM_DEFAULT_MULTICAST_PORT 10000 |
| Default SLAM multicast port. | |
| #define | SLAM_MAX_HEADER_LEN |
| Maximum SLAM header length. | |
| #define | SLAM_MAX_BLOCKS_PER_NACK 4 |
| Maximum number of blocks to request per NACK. | |
| #define | SLAM_MAX_NACK_LEN ( 7 /* block */ + 7 /* #blocks */ + 1 /* NUL */ ) |
| Maximum SLAM NACK length. | |
| #define | SLAM_SLAVE_TIMEOUT ( 1 * TICKS_PER_SEC ) |
| SLAM slave timeout. | |
Functions | |
| FILE_LICENCE (GPL2_OR_LATER) | |
| FEATURE (FEATURE_PROTOCOL,"SLAM", DHCP_EB_FEATURE_SLAM, 1) | |
| static void | slam_free (struct refcnt *refcnt) |
| Free a SLAM request. | |
| static void | slam_finished (struct slam_request *slam, int rc) |
| Mark SLAM request as complete. | |
| static int | slam_put_value (struct slam_request *slam, struct io_buffer *iobuf, unsigned long value) |
| Add a variable-length value to a SLAM packet. | |
| static int | slam_tx_nack (struct slam_request *slam) |
| Send SLAM NACK packet. | |
| static void | slam_master_timer_expired (struct retry_timer *timer, int fail) |
| Handle SLAM master client retry timer expiry. | |
| static void | slam_slave_timer_expired (struct retry_timer *timer, int fail) |
| Handle SLAM slave client retry timer expiry. | |
| static int | slam_pull_value (struct slam_request *slam, struct io_buffer *iobuf, unsigned long *value) |
| Read and strip a variable-length value from a SLAM packet. | |
| static int | slam_pull_header (struct slam_request *slam, struct io_buffer *iobuf) |
| Read and strip SLAM header. | |
| static int | slam_mc_socket_deliver (struct xfer_interface *mc_socket, struct io_buffer *iobuf, struct xfer_metadata *rx_meta __unused) |
| Receive SLAM data packet. | |
| static int | slam_socket_deliver (struct xfer_interface *socket, struct io_buffer *iobuf, struct xfer_metadata *rx_meta __unused) |
| Receive SLAM non-data packet. | |
| static void | slam_socket_close (struct xfer_interface *socket, int rc) |
| Close SLAM unicast socket. | |
| static void | slam_mc_socket_close (struct xfer_interface *mc_socket, int rc) |
| Close SLAM multicast socket. | |
| static void | slam_xfer_close (struct xfer_interface *xfer, int rc) |
| Close SLAM data transfer interface. | |
| static int | slam_parse_multicast_address (struct slam_request *slam, const char *path, struct sockaddr_in *address) |
| Parse SLAM URI multicast address. | |
| static int | slam_open (struct xfer_interface *xfer, struct uri *uri) |
| Initiate a SLAM request. | |
Variables | |
| static struct xfer_interface_operations | slam_socket_operations |
| SLAM unicast socket data transfer operations. | |
| static struct xfer_interface_operations | slam_mc_socket_operations |
| SLAM multicast socket data transfer operations. | |
| static struct xfer_interface_operations | slam_xfer_operations |
| SLAM data transfer operations. | |
| struct uri_opener slam_uri_opener | __uri_opener |
| SLAM URI opener. | |
The SLAM protocol is supported only by Etherboot; it was designed and implemented by Eric Biederman. A server implementation is available in contrib/mini-slamd. There does not appear to be any documentation beyond a few sparse comments in Etherboot's proto_slam.c.
SLAM packets use three types of data field:
Nul : A single NUL (0) byte, used as a list terminator
Raw : A block of raw data
Int : A variable-length integer, in big-endian order. The length of the integer is encoded in the most significant three bits.
Packets received by the client have the following layout:
Int : Transaction identifier. This is an opaque value.
Int : Total number of bytes in the transfer.
Int : Block size, in bytes.
Int : Packet sequence number within the transfer (if this packet contains data).
Raw : Packet data (if this packet contains data).
Packets transmitted by the client consist of a run-length-encoded representation of the received-blocks bitmap, looking something like:
Int : Number of consecutive successfully-received packets Int : Number of consecutive missing packets Int : Number of consecutive successfully-received packets Int : Number of consecutive missing packets .... Nul
Definition in file slam.c.
| #define SLAM_DEFAULT_PORT 10000 |
| #define SLAM_DEFAULT_MULTICAST_IP ( ( 239 << 24 ) | ( 255 << 16 ) | ( 1 << 8 ) | ( 1 << 0 ) ) |
| #define SLAM_DEFAULT_MULTICAST_PORT 10000 |
| #define SLAM_MAX_HEADER_LEN |
| #define SLAM_MAX_BLOCKS_PER_NACK 4 |
Maximum number of blocks to request per NACK.
This is a policy decision equivalent to selecting a TCP window size.
Definition at line 104 of file slam.c.
Referenced by slam_tx_nack().
| #define SLAM_MAX_NACK_LEN ( 7 /* block */ + 7 /* #blocks */ + 1 /* NUL */ ) |
Maximum SLAM NACK length.
We only ever send a NACK for a single range of up to SLAM_MAX_BLOCKS_PER_NACK blocks.
Definition at line 111 of file slam.c.
Referenced by slam_tx_nack().
| #define SLAM_SLAVE_TIMEOUT ( 1 * TICKS_PER_SEC ) |
SLAM slave timeout.
Definition at line 114 of file slam.c.
Referenced by slam_mc_socket_deliver(), and slam_open().
| FILE_LICENCE | ( | GPL2_OR_LATER | ) |
| FEATURE | ( | FEATURE_PROTOCOL | , | |
| "SLAM" | , | |||
| DHCP_EB_FEATURE_SLAM | , | |||
| 1 | ||||
| ) |
| static void slam_free | ( | struct refcnt * | refcnt | ) | [static] |
Free a SLAM request.
| refcnt | Reference counter |
Definition at line 154 of file slam.c.
References slam_request::bitmap, bitmap_free(), container_of, and free().
Referenced by slam_open().
00154 { 00155 struct slam_request *slam = 00156 container_of ( refcnt, struct slam_request, refcnt ); 00157 00158 bitmap_free ( &slam->bitmap ); 00159 free ( slam ); 00160 }
| static void slam_finished | ( | struct slam_request * | slam, | |
| int | rc | |||
| ) | [static] |
Mark SLAM request as complete.
| slam | SLAM request | |
| rc | Return status code |
Definition at line 168 of file slam.c.
References DBGC, slam_request::master_timer, slam_request::mc_socket, slam_request::nack_sent, slam_request::slave_timer, slam_request::socket, stop_timer(), strerror(), slam_request::xfer, xfer_close(), and xfer_deliver_raw().
Referenced by slam_mc_socket_close(), slam_mc_socket_deliver(), slam_open(), slam_pull_header(), slam_slave_timer_expired(), slam_socket_close(), and slam_xfer_close().
00168 { 00169 static const uint8_t slam_disconnect[] = { 0 }; 00170 00171 DBGC ( slam, "SLAM %p finished with status code %d (%s)\n", 00172 slam, rc, strerror ( rc ) ); 00173 00174 /* Send a disconnect message if we ever sent anything to the 00175 * server. 00176 */ 00177 if ( slam->nack_sent ) { 00178 xfer_deliver_raw ( &slam->socket, slam_disconnect, 00179 sizeof ( slam_disconnect ) ); 00180 } 00181 00182 /* Stop the retry timers */ 00183 stop_timer ( &slam->master_timer ); 00184 stop_timer ( &slam->slave_timer ); 00185 00186 /* Close all data transfer interfaces */ 00187 xfer_nullify ( &slam->socket ); 00188 xfer_close ( &slam->socket, rc ); 00189 xfer_nullify ( &slam->mc_socket ); 00190 xfer_close ( &slam->mc_socket, rc ); 00191 xfer_nullify ( &slam->xfer ); 00192 xfer_close ( &slam->xfer, rc ); 00193 }
| static int slam_put_value | ( | struct slam_request * | slam, | |
| struct io_buffer * | iobuf, | |||
| unsigned long | value | |||
| ) | [static] |
Add a variable-length value to a SLAM packet.
| slam | SLAM request | |
| iobuf | I/O buffer | |
| value | Value to add |
| rc | Return status code |
Definition at line 213 of file slam.c.
References assert, DBGC2, ENOBUFS, flsl, iob_put, and iob_tailroom().
Referenced by slam_tx_nack().
00214 { 00215 uint8_t *data; 00216 size_t len; 00217 unsigned int i; 00218 00219 /* Calculate variable length required to store value. Always 00220 * leave at least one byte in the I/O buffer. 00221 */ 00222 len = ( ( flsl ( value ) + 10 ) / 8 ); 00223 if ( len >= iob_tailroom ( iobuf ) ) { 00224 DBGC2 ( slam, "SLAM %p cannot add %zd-byte value\n", 00225 slam, len ); 00226 return -ENOBUFS; 00227 } 00228 /* There is no valid way within the protocol that we can end 00229 * up trying to push a full-sized long (i.e. without space for 00230 * the length encoding). 00231 */ 00232 assert ( len <= sizeof ( value ) ); 00233 00234 /* Add value */ 00235 data = iob_put ( iobuf, len ); 00236 for ( i = len ; i-- ; ) { 00237 data[i] = value; 00238 value >>= 8; 00239 } 00240 *data |= ( len << 5 ); 00241 assert ( value == 0 ); 00242 00243 return 0; 00244 }
| static int slam_tx_nack | ( | struct slam_request * | slam | ) | [static] |
Send SLAM NACK packet.
| slam | SLAM request |
| rc | Return status code |
Definition at line 252 of file slam.c.
References slam_request::bitmap, bitmap_first_gap(), bitmap_test(), DBGC, DBGCP, ENOMEM, iob_put, slam_request::nack_sent, slam_request::num_blocks, SLAM_MAX_BLOCKS_PER_NACK, SLAM_MAX_NACK_LEN, slam_put_value(), slam_request::socket, xfer_alloc_iob(), and xfer_deliver_iob().
Referenced by slam_master_timer_expired(), slam_slave_timer_expired(), and slam_socket_deliver().
00252 { 00253 struct io_buffer *iobuf; 00254 unsigned long first_block; 00255 unsigned long num_blocks; 00256 uint8_t *nul; 00257 int rc; 00258 00259 /* Mark NACK as sent, so that we know we have to disconnect later */ 00260 slam->nack_sent = 1; 00261 00262 /* Allocate I/O buffer */ 00263 iobuf = xfer_alloc_iob ( &slam->socket, SLAM_MAX_NACK_LEN ); 00264 if ( ! iobuf ) { 00265 DBGC ( slam, "SLAM %p could not allocate I/O buffer\n", 00266 slam ); 00267 return -ENOMEM; 00268 } 00269 00270 /* Construct NACK. We always request only a single packet; 00271 * this allows us to force multicast-TFTP-style flow control 00272 * on the SLAM server, which will otherwise just blast the 00273 * data out as fast as it can. On a gigabit network, without 00274 * RX checksumming, this would inevitably cause packet drops. 00275 */ 00276 first_block = bitmap_first_gap ( &slam->bitmap ); 00277 for ( num_blocks = 1 ; ; num_blocks++ ) { 00278 if ( num_blocks >= SLAM_MAX_BLOCKS_PER_NACK ) 00279 break; 00280 if ( ( first_block + num_blocks ) >= slam->num_blocks ) 00281 break; 00282 if ( bitmap_test ( &slam->bitmap, 00283 ( first_block + num_blocks ) ) ) 00284 break; 00285 } 00286 if ( first_block ) { 00287 DBGCP ( slam, "SLAM %p transmitting NACK for blocks " 00288 "%ld-%ld\n", slam, first_block, 00289 ( first_block + num_blocks - 1 ) ); 00290 } else { 00291 DBGC ( slam, "SLAM %p transmitting initial NACK for blocks " 00292 "0-%ld\n", slam, ( num_blocks - 1 ) ); 00293 } 00294 if ( ( rc = slam_put_value ( slam, iobuf, first_block ) ) != 0 ) 00295 return rc; 00296 if ( ( rc = slam_put_value ( slam, iobuf, num_blocks ) ) != 0 ) 00297 return rc; 00298 nul = iob_put ( iobuf, 1 ); 00299 *nul = 0; 00300 00301 /* Transmit packet */ 00302 return xfer_deliver_iob ( &slam->socket, iobuf ); 00303 }
| static void slam_master_timer_expired | ( | struct retry_timer * | timer, | |
| int | fail | |||
| ) | [static] |
Handle SLAM master client retry timer expiry.
| timer | Master retry timer | |
| fail | Failure indicator |
Definition at line 311 of file slam.c.
References container_of, DBGC, slam_request::master_timer, slam_tx_nack(), and start_timer().
Referenced by slam_open().
00312 { 00313 struct slam_request *slam = 00314 container_of ( timer, struct slam_request, master_timer ); 00315 00316 if ( fail ) { 00317 /* Allow timer to stop running. We will terminate the 00318 * connection only if the slave timer times out. 00319 */ 00320 DBGC ( slam, "SLAM %p giving up acting as master client\n", 00321 slam ); 00322 } else { 00323 /* Retransmit NACK */ 00324 start_timer ( timer ); 00325 slam_tx_nack ( slam ); 00326 } 00327 }
| static void slam_slave_timer_expired | ( | struct retry_timer * | timer, | |
| int | fail | |||
| ) | [static] |
Handle SLAM slave client retry timer expiry.
| timer | Master retry timer | |
| fail | Failure indicator |
Definition at line 335 of file slam.c.
References container_of, DBGC, ETIMEDOUT, slam_finished(), slam_tx_nack(), slam_request::slave_timer, and start_timer().
Referenced by slam_open().
00336 { 00337 struct slam_request *slam = 00338 container_of ( timer, struct slam_request, slave_timer ); 00339 00340 if ( fail ) { 00341 /* Terminate connection */ 00342 slam_finished ( slam, -ETIMEDOUT ); 00343 } else { 00344 /* Try sending a NACK */ 00345 DBGC ( slam, "SLAM %p trying to become master client\n", 00346 slam ); 00347 start_timer ( timer ); 00348 slam_tx_nack ( slam ); 00349 } 00350 }
| static int slam_pull_value | ( | struct slam_request * | slam, | |
| struct io_buffer * | iobuf, | |||
| unsigned long * | value | |||
| ) | [static] |
Read and strip a variable-length value from a SLAM packet.
| slam | SLAM request | |
| iobuf | I/O buffer | |
| value | Value to fill in, or NULL to ignore value |
| rc | Return status code |
Definition at line 368 of file slam.c.
References io_buffer::data, DBGC, EINVAL, iob_len(), and iob_pull.
Referenced by slam_mc_socket_deliver(), and slam_pull_header().
00370 { 00371 uint8_t *data; 00372 size_t len; 00373 00374 /* Sanity check */ 00375 if ( iob_len ( iobuf ) == 0 ) { 00376 DBGC ( slam, "SLAM %p empty value\n", slam ); 00377 return -EINVAL; 00378 } 00379 00380 /* Read and verify length of value */ 00381 data = iobuf->data; 00382 len = ( *data >> 5 ); 00383 if ( ( len == 0 ) || 00384 ( value && ( len > sizeof ( *value ) ) ) ) { 00385 DBGC ( slam, "SLAM %p invalid value length %zd bytes\n", 00386 slam, len ); 00387 return -EINVAL; 00388 } 00389 if ( len > iob_len ( iobuf ) ) { 00390 DBGC ( slam, "SLAM %p value extends beyond I/O buffer\n", 00391 slam ); 00392 return -EINVAL; 00393 } 00394 00395 /* Read value */ 00396 iob_pull ( iobuf, len ); 00397 *value = ( *data & 0x1f ); 00398 while ( --len ) { 00399 *value <<= 8; 00400 *value |= *(++data); 00401 } 00402 00403 return 0; 00404 }
| static int slam_pull_header | ( | struct slam_request * | slam, | |
| struct io_buffer * | iobuf | |||
| ) | [static] |
Read and strip SLAM header.
| slam | SLAM request | |
| iobuf | I/O buffer |
| rc | Return status code |
Definition at line 413 of file slam.c.
References assert, slam_request::bitmap, bitmap_free(), bitmap_resize(), slam_request::block_size, io_buffer::data, DBGC, slam_request::header, slam_request::header_len, iob_len(), iob_pull, memcmp(), memcpy, memset(), NULL, slam_request::num_blocks, SEEK_SET, slam_finished(), slam_pull_value(), strerror(), slam_request::total_bytes, slam_request::xfer, and xfer_seek().
Referenced by slam_mc_socket_deliver(), and slam_socket_deliver().
00414 { 00415 void *header = iobuf->data; 00416 int rc; 00417 00418 /* If header matches cached header, just pull it and return */ 00419 if ( ( slam->header_len <= iob_len ( iobuf ) ) && 00420 ( memcmp ( slam->header, iobuf->data, slam->header_len ) == 0 )){ 00421 iob_pull ( iobuf, slam->header_len ); 00422 return 0; 00423 } 00424 00425 DBGC ( slam, "SLAM %p detected changed header; resetting\n", slam ); 00426 00427 /* Read and strip transaction ID, total number of bytes, and 00428 * block size. 00429 */ 00430 if ( ( rc = slam_pull_value ( slam, iobuf, NULL ) ) != 0 ) 00431 return rc; 00432 if ( ( rc = slam_pull_value ( slam, iobuf, 00433 &slam->total_bytes ) ) != 0 ) 00434 return rc; 00435 if ( ( rc = slam_pull_value ( slam, iobuf, 00436 &slam->block_size ) ) != 0 ) 00437 return rc; 00438 00439 /* Update the cached header */ 00440 slam->header_len = ( iobuf->data - header ); 00441 assert ( slam->header_len <= sizeof ( slam->header ) ); 00442 memcpy ( slam->header, header, slam->header_len ); 00443 00444 /* Calculate number of blocks */ 00445 slam->num_blocks = ( ( slam->total_bytes + slam->block_size - 1 ) / 00446 slam->block_size ); 00447 00448 DBGC ( slam, "SLAM %p has total bytes %ld, block size %ld, num " 00449 "blocks %ld\n", slam, slam->total_bytes, slam->block_size, 00450 slam->num_blocks ); 00451 00452 /* Discard and reset the bitmap */ 00453 bitmap_free ( &slam->bitmap ); 00454 memset ( &slam->bitmap, 0, sizeof ( slam->bitmap ) ); 00455 00456 /* Allocate a new bitmap */ 00457 if ( ( rc = bitmap_resize ( &slam->bitmap, 00458 slam->num_blocks ) ) != 0 ) { 00459 /* Failure to allocate a bitmap is fatal */ 00460 DBGC ( slam, "SLAM %p could not allocate bitmap for %ld " 00461 "blocks: %s\n", slam, slam->num_blocks, 00462 strerror ( rc ) ); 00463 slam_finished ( slam, rc ); 00464 return rc; 00465 } 00466 00467 /* Notify recipient of file size */ 00468 xfer_seek ( &slam->xfer, slam->total_bytes, SEEK_SET ); 00469 00470 return 0; 00471 }
| static int slam_mc_socket_deliver | ( | struct xfer_interface * | mc_socket, | |
| struct io_buffer * | iobuf, | |||
| struct xfer_metadata *rx_meta | __unused | |||
| ) | [static] |
Receive SLAM data packet.
| mc_socket | SLAM multicast socket | |
| iobuf | I/O buffer |
| rc | Return status code |
Definition at line 480 of file slam.c.
References slam_request::bitmap, bitmap_full(), bitmap_set(), bitmap_test(), slam_request::block_size, container_of, DBGC, EINVAL, free_iob(), iob_len(), slam_request::master_timer, memset(), slam_request::num_blocks, xfer_metadata::offset, SEEK_SET, slam_finished(), slam_pull_header(), slam_pull_value(), SLAM_SLAVE_TIMEOUT, slam_request::slave_timer, start_timer_fixed(), stop_timer(), xfer_metadata::whence, slam_request::xfer, and xfer_deliver_iob_meta().
00482 { 00483 struct slam_request *slam = 00484 container_of ( mc_socket, struct slam_request, mc_socket ); 00485 struct xfer_metadata meta; 00486 unsigned long packet; 00487 size_t len; 00488 int rc; 00489 00490 /* Stop the master client timer. Restart the slave client timer. */ 00491 stop_timer ( &slam->master_timer ); 00492 stop_timer ( &slam->slave_timer ); 00493 start_timer_fixed ( &slam->slave_timer, SLAM_SLAVE_TIMEOUT ); 00494 00495 /* Read and strip packet header */ 00496 if ( ( rc = slam_pull_header ( slam, iobuf ) ) != 0 ) 00497 goto err_discard; 00498 00499 /* Read and strip packet number */ 00500 if ( ( rc = slam_pull_value ( slam, iobuf, &packet ) ) != 0 ) 00501 goto err_discard; 00502 00503 /* Sanity check packet number */ 00504 if ( packet >= slam->num_blocks ) { 00505 DBGC ( slam, "SLAM %p received out-of-range packet %ld " 00506 "(num_blocks=%ld)\n", slam, packet, slam->num_blocks ); 00507 rc = -EINVAL; 00508 goto err_discard; 00509 } 00510 00511 /* Sanity check length */ 00512 len = iob_len ( iobuf ); 00513 if ( len > slam->block_size ) { 00514 DBGC ( slam, "SLAM %p received oversize packet of %zd bytes " 00515 "(block_size=%ld)\n", slam, len, slam->block_size ); 00516 rc = -EINVAL; 00517 goto err_discard; 00518 } 00519 if ( ( packet != ( slam->num_blocks - 1 ) ) && 00520 ( len < slam->block_size ) ) { 00521 DBGC ( slam, "SLAM %p received short packet of %zd bytes " 00522 "(block_size=%ld)\n", slam, len, slam->block_size ); 00523 rc = -EINVAL; 00524 goto err_discard; 00525 } 00526 00527 /* If we have already seen this packet, discard it */ 00528 if ( bitmap_test ( &slam->bitmap, packet ) ) { 00529 goto discard; 00530 } 00531 00532 /* Pass to recipient */ 00533 memset ( &meta, 0, sizeof ( meta ) ); 00534 meta.whence = SEEK_SET; 00535 meta.offset = ( packet * slam->block_size ); 00536 if ( ( rc = xfer_deliver_iob_meta ( &slam->xfer, iobuf, 00537 &meta ) ) != 0 ) 00538 goto err; 00539 00540 /* Mark block as received */ 00541 bitmap_set ( &slam->bitmap, packet ); 00542 00543 /* If we have received all blocks, terminate */ 00544 if ( bitmap_full ( &slam->bitmap ) ) 00545 slam_finished ( slam, 0 ); 00546 00547 return 0; 00548 00549 err_discard: 00550 discard: 00551 free_iob ( iobuf ); 00552 err: 00553 return rc; 00554 }
| static int slam_socket_deliver | ( | struct xfer_interface * | socket, | |
| struct io_buffer * | iobuf, | |||
| struct xfer_metadata *rx_meta | __unused | |||
| ) | [static] |
Receive SLAM non-data packet.
| socket | SLAM unicast socket | |
| iobuf | I/O buffer |
| rc | Return status code |
Definition at line 563 of file slam.c.
References container_of, io_buffer::data, DBGC, DBGC_HD, EINVAL, free_iob(), iob_len(), slam_request::master_timer, slam_pull_header(), slam_tx_nack(), start_timer(), and stop_timer().
00565 { 00566 struct slam_request *slam = 00567 container_of ( socket, struct slam_request, socket ); 00568 int rc; 00569 00570 /* Restart the master client timer */ 00571 stop_timer ( &slam->master_timer ); 00572 start_timer ( &slam->master_timer ); 00573 00574 /* Read and strip packet header */ 00575 if ( ( rc = slam_pull_header ( slam, iobuf ) ) != 0 ) 00576 goto discard; 00577 00578 /* Sanity check */ 00579 if ( iob_len ( iobuf ) != 0 ) { 00580 DBGC ( slam, "SLAM %p received trailing garbage:\n", slam ); 00581 DBGC_HD ( slam, iobuf->data, iob_len ( iobuf ) ); 00582 rc = -EINVAL; 00583 goto discard; 00584 } 00585 00586 /* Discard packet */ 00587 free_iob ( iobuf ); 00588 00589 /* Send NACK in reply */ 00590 slam_tx_nack ( slam ); 00591 00592 return 0; 00593 00594 discard: 00595 free_iob ( iobuf ); 00596 return rc; 00597 00598 }
| static void slam_socket_close | ( | struct xfer_interface * | socket, | |
| int | rc | |||
| ) | [static] |
Close SLAM unicast socket.
| socket | SLAM unicast socket | |
| rc | Reason for close |
Definition at line 606 of file slam.c.
References container_of, DBGC, slam_finished(), and strerror().
00606 { 00607 struct slam_request *slam = 00608 container_of ( socket, struct slam_request, socket ); 00609 00610 DBGC ( slam, "SLAM %p unicast socket closed: %s\n", 00611 slam, strerror ( rc ) ); 00612 00613 slam_finished ( slam, rc ); 00614 }
| static void slam_mc_socket_close | ( | struct xfer_interface * | mc_socket, | |
| int | rc | |||
| ) | [static] |
Close SLAM multicast socket.
| mc_socket | SLAM multicast socket | |
| rc | Reason for close |
Definition at line 632 of file slam.c.
References container_of, DBGC, slam_finished(), and strerror().
00632 { 00633 struct slam_request *slam = 00634 container_of ( mc_socket, struct slam_request, mc_socket ); 00635 00636 DBGC ( slam, "SLAM %p multicast socket closed: %s\n", 00637 slam, strerror ( rc ) ); 00638 00639 slam_finished ( slam, rc ); 00640 }
| static void slam_xfer_close | ( | struct xfer_interface * | xfer, | |
| int | rc | |||
| ) | [static] |
Close SLAM data transfer interface.
| xfer | SLAM data transfer interface | |
| rc | Reason for close |
Definition at line 664 of file slam.c.
References container_of, DBGC, slam_finished(), and strerror().
00664 { 00665 struct slam_request *slam = 00666 container_of ( xfer, struct slam_request, xfer ); 00667 00668 DBGC ( slam, "SLAM %p data transfer interface closed: %s\n", 00669 slam, strerror ( rc ) ); 00670 00671 slam_finished ( slam, rc ); 00672 }
| static int slam_parse_multicast_address | ( | struct slam_request * | slam, | |
| const char * | path, | |||
| struct sockaddr_in * | address | |||
| ) | [static] |
Parse SLAM URI multicast address.
| slam | SLAM request | |
| path | Path portion of x-slam:// URI | |
| address | Socket address to fill in |
| rc | Return status code |
Definition at line 692 of file slam.c.
References assert, DBGC, EINVAL, htons, inet_aton(), memcpy, sockaddr_in::sin_addr, sockaddr_in::sin_port, strchr(), strlen(), and strtoul().
Referenced by slam_open().
00694 { 00695 char path_dup[ strlen ( path ) /* no +1 */ ]; 00696 char *sep; 00697 char *end; 00698 00699 /* Create temporary copy of path, minus the leading '/' */ 00700 assert ( *path == '/' ); 00701 memcpy ( path_dup, ( path + 1 ) , sizeof ( path_dup ) ); 00702 00703 /* Parse port, if present */ 00704 sep = strchr ( path_dup, ':' ); 00705 if ( sep ) { 00706 *(sep++) = '\0'; 00707 address->sin_port = htons ( strtoul ( sep, &end, 0 ) ); 00708 if ( *end != '\0' ) { 00709 DBGC ( slam, "SLAM %p invalid multicast port " 00710 "\"%s\"\n", slam, sep ); 00711 return -EINVAL; 00712 } 00713 } 00714 00715 /* Parse address */ 00716 if ( inet_aton ( path_dup, &address->sin_addr ) == 0 ) { 00717 DBGC ( slam, "SLAM %p invalid multicast address \"%s\"\n", 00718 slam, path_dup ); 00719 return -EINVAL; 00720 } 00721 00722 return 0; 00723 }
| static int slam_open | ( | struct xfer_interface * | xfer, | |
| struct uri * | uri | |||
| ) | [static] |
Initiate a SLAM request.
| rc | Return status code |
Definition at line 732 of file slam.c.
References AF_INET, slam_request::bitmap, bitmap_resize(), DBGC, EINVAL, ENOMEM, retry_timer::expired, refcnt::free, slam_request::header_len, uri::host, htonl, htons, slam_request::master_timer, slam_request::mc_socket, memcpy, memset(), NULL, slam_request::num_blocks, uri::path, ref_put(), slam_request::refcnt, sockaddr_in::sin_family, SLAM_DEFAULT_MULTICAST_IP, SLAM_DEFAULT_MULTICAST_PORT, SLAM_DEFAULT_PORT, slam_finished(), slam_free(), slam_master_timer_expired(), slam_parse_multicast_address(), SLAM_SLAVE_TIMEOUT, slam_slave_timer_expired(), slam_request::slave_timer, SOCK_DGRAM, slam_request::socket, sockaddr_tcpip::st_port, start_timer_fixed(), strerror(), uri_port(), slam_request::xfer, xfer_init(), xfer_open_named_socket(), xfer_open_socket(), and zalloc().
00732 { 00733 static const struct sockaddr_in default_multicast = { 00734 .sin_family = AF_INET, 00735 .sin_port = htons ( SLAM_DEFAULT_MULTICAST_PORT ), 00736 .sin_addr = { htonl ( SLAM_DEFAULT_MULTICAST_IP ) }, 00737 }; 00738 struct slam_request *slam; 00739 struct sockaddr_tcpip server; 00740 struct sockaddr_in multicast; 00741 int rc; 00742 00743 /* Sanity checks */ 00744 if ( ! uri->host ) 00745 return -EINVAL; 00746 00747 /* Allocate and populate structure */ 00748 slam = zalloc ( sizeof ( *slam ) ); 00749 if ( ! slam ) 00750 return -ENOMEM; 00751 slam->refcnt.free = slam_free; 00752 xfer_init ( &slam->xfer, &slam_xfer_operations, &slam->refcnt ); 00753 xfer_init ( &slam->socket, &slam_socket_operations, &slam->refcnt ); 00754 xfer_init ( &slam->mc_socket, &slam_mc_socket_operations, 00755 &slam->refcnt ); 00756 slam->master_timer.expired = slam_master_timer_expired; 00757 slam->slave_timer.expired = slam_slave_timer_expired; 00758 /* Fake an invalid cached header of { 0x00, ... } */ 00759 slam->header_len = 1; 00760 /* Fake parameters for initial NACK */ 00761 slam->num_blocks = 1; 00762 if ( ( rc = bitmap_resize ( &slam->bitmap, 1 ) ) != 0 ) { 00763 DBGC ( slam, "SLAM %p could not allocate initial bitmap: " 00764 "%s\n", slam, strerror ( rc ) ); 00765 goto err; 00766 } 00767 00768 /* Open unicast socket */ 00769 memset ( &server, 0, sizeof ( server ) ); 00770 server.st_port = htons ( uri_port ( uri, SLAM_DEFAULT_PORT ) ); 00771 if ( ( rc = xfer_open_named_socket ( &slam->socket, SOCK_DGRAM, 00772 ( struct sockaddr * ) &server, 00773 uri->host, NULL ) ) != 0 ) { 00774 DBGC ( slam, "SLAM %p could not open unicast socket: %s\n", 00775 slam, strerror ( rc ) ); 00776 goto err; 00777 } 00778 00779 /* Open multicast socket */ 00780 memcpy ( &multicast, &default_multicast, sizeof ( multicast ) ); 00781 if ( uri->path && 00782 ( ( rc = slam_parse_multicast_address ( slam, uri->path, 00783 &multicast ) ) != 0 ) ) { 00784 goto err; 00785 } 00786 if ( ( rc = xfer_open_socket ( &slam->mc_socket, SOCK_DGRAM, 00787 ( struct sockaddr * ) &multicast, 00788 ( struct sockaddr * ) &multicast ) ) != 0 ) { 00789 DBGC ( slam, "SLAM %p could not open multicast socket: %s\n", 00790 slam, strerror ( rc ) ); 00791 goto err; 00792 } 00793 00794 /* Start slave retry timer */ 00795 start_timer_fixed ( &slam->slave_timer, SLAM_SLAVE_TIMEOUT ); 00796 00797 /* Attach to parent interface, mortalise self, and return */ 00798 xfer_plug_plug ( &slam->xfer, xfer ); 00799 ref_put ( &slam->refcnt ); 00800 return 0; 00801 00802 err: 00803 slam_finished ( slam, rc ); 00804 ref_put ( &slam->refcnt ); 00805 return rc; 00806 }
struct xfer_interface_operations slam_socket_operations [static] |
Initial value:
{
.close = slam_socket_close,
.vredirect = xfer_vreopen,
.window = unlimited_xfer_window,
.alloc_iob = default_xfer_alloc_iob,
.deliver_iob = slam_socket_deliver,
.deliver_raw = xfer_deliver_as_iob,
}
struct xfer_interface_operations slam_mc_socket_operations [static] |
Initial value:
{
.close = slam_mc_socket_close,
.vredirect = xfer_vreopen,
.window = unlimited_xfer_window,
.alloc_iob = default_xfer_alloc_iob,
.deliver_iob = slam_mc_socket_deliver,
.deliver_raw = xfer_deliver_as_iob,
}
struct xfer_interface_operations slam_xfer_operations [static] |
Initial value:
{
.close = slam_xfer_close,
.vredirect = ignore_xfer_vredirect,
.window = unlimited_xfer_window,
.alloc_iob = default_xfer_alloc_iob,
.deliver_iob = xfer_deliver_as_raw,
.deliver_raw = ignore_xfer_deliver_raw,
}
| struct uri_opener slam_uri_opener __uri_opener |
1.5.7.1