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