2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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.
27 #include <gpxe/refcnt.h>
28 #include <gpxe/xfer.h>
29 #include <gpxe/open.h>
31 #include <gpxe/tcpip.h>
32 #include <gpxe/retry.h>
33 #include <gpxe/features.h>
34 #include <gpxe/bitmap.h>
35 #include <gpxe/tftp.h>
43 FEATURE ( FEATURE_PROTOCOL, "TFTP", DHCP_EB_FEATURE_TFTP, 1 );
48 * This data structure holds the state for an ongoing TFTP transfer.
51 /** Reference count */
53 /** Data transfer interface */
54 struct xfer_interface xfer;
56 /** URI being fetched */
58 /** Transport layer interface */
59 struct xfer_interface socket;
60 /** Multicast transport layer interface */
61 struct xfer_interface mc_socket;
65 * This is the "blksize" option negotiated with the TFTP
66 * server. (If the TFTP server does not support TFTP options,
67 * this will default to 512).
72 * This is the value returned in the "tsize" option from the
73 * TFTP server. If the TFTP server does not support the
74 * "tsize" option, this value will be zero.
80 * This is the port to which RRQ packets are sent.
85 * The peer address is determined by the first response
86 * received to the TFTP RRQ.
88 struct sockaddr_tcpip peer;
91 /** MTFTP timeout count */
92 unsigned int mtftp_timeouts;
96 /** Maximum known length
98 * We don't always know the file length in advance. In
99 * particular, if the TFTP server doesn't support the tsize
100 * option, or we are using MTFTP, then we don't know the file
101 * length until we see the end-of-file block (which, in the
102 * case of MTFTP, may not be the last block we see).
104 * This value is updated whenever we obtain information about
108 /** Retransmission timer */
109 struct retry_timer timer;
112 /** TFTP request flags */
114 /** Send ACK packets */
115 TFTP_FL_SEND_ACK = 0x0001,
116 /** Request blksize and tsize options */
117 TFTP_FL_RRQ_SIZES = 0x0002,
118 /** Request multicast option */
119 TFTP_FL_RRQ_MULTICAST = 0x0004,
120 /** Perform MTFTP recovery on timeout */
121 TFTP_FL_MTFTP_RECOVERY = 0x0008,
124 /** Maximum number of MTFTP open requests before falling back to TFTP */
125 #define MTFTP_MAX_TIMEOUTS 3
130 * @v refcnt Reference counter
132 static void tftp_free ( struct refcnt *refcnt ) {
133 struct tftp_request *tftp =
134 container_of ( refcnt, struct tftp_request, refcnt );
136 uri_put ( tftp->uri );
137 bitmap_free ( &tftp->bitmap );
142 * Mark TFTP request as complete
144 * @v tftp TFTP connection
145 * @v rc Return status code
147 static void tftp_done ( struct tftp_request *tftp, int rc ) {
149 DBGC ( tftp, "TFTP %p finished with status %d (%s)\n",
150 tftp, rc, strerror ( rc ) );
152 /* Stop the retry timer */
153 stop_timer ( &tftp->timer );
155 /* Close all data transfer interfaces */
156 xfer_nullify ( &tftp->socket );
157 xfer_close ( &tftp->socket, rc );
158 xfer_nullify ( &tftp->mc_socket );
159 xfer_close ( &tftp->mc_socket, rc );
160 xfer_nullify ( &tftp->xfer );
161 xfer_close ( &tftp->xfer, rc );
167 * @v tftp TFTP connection
168 * @ret rc Return status code
170 static int tftp_reopen ( struct tftp_request *tftp ) {
171 struct sockaddr_tcpip server;
175 xfer_close ( &tftp->socket, 0 );
177 /* Disable ACK sending. */
178 tftp->flags &= ~TFTP_FL_SEND_ACK;
180 /* Reset peer address */
181 memset ( &tftp->peer, 0, sizeof ( tftp->peer ) );
184 memset ( &server, 0, sizeof ( server ) );
185 server.st_port = htons ( tftp->port );
186 if ( ( rc = xfer_open_named_socket ( &tftp->socket, SOCK_DGRAM,
187 ( struct sockaddr * ) &server,
188 tftp->uri->host, NULL ) ) != 0 ) {
189 DBGC ( tftp, "TFTP %p could not open socket: %s\n",
190 tftp, strerror ( rc ) );
198 * Reopen TFTP multicast socket
200 * @v tftp TFTP connection
201 * @v local Local socket address
202 * @ret rc Return status code
204 static int tftp_reopen_mc ( struct tftp_request *tftp,
205 struct sockaddr *local ) {
208 /* Close multicast socket */
209 xfer_close ( &tftp->mc_socket, 0 );
211 /* Open multicast socket. We never send via this socket, so
212 * use the local address as the peer address (since the peer
213 * address cannot be NULL).
215 if ( ( rc = xfer_open_socket ( &tftp->mc_socket, SOCK_DGRAM,
216 local, local ) ) != 0 ) {
217 DBGC ( tftp, "TFTP %p could not open multicast "
218 "socket: %s\n", tftp, strerror ( rc ) );
226 * Presize TFTP receive buffers and block bitmap
228 * @v tftp TFTP connection
229 * @v filesize Known minimum file size
230 * @ret rc Return status code
232 static int tftp_presize ( struct tftp_request *tftp, size_t filesize ) {
233 unsigned int num_blocks;
236 /* Do nothing if we are already large enough */
237 if ( filesize <= tftp->filesize )
240 /* Record filesize */
241 tftp->filesize = filesize;
243 /* Notify recipient of file size */
244 xfer_seek ( &tftp->xfer, filesize, SEEK_SET );
245 xfer_seek ( &tftp->xfer, 0, SEEK_SET );
247 /* Calculate expected number of blocks. Note that files whose
248 * length is an exact multiple of the blocksize will have a
249 * trailing zero-length block, which must be included.
251 num_blocks = ( ( filesize / tftp->blksize ) + 1 );
252 if ( ( rc = bitmap_resize ( &tftp->bitmap, num_blocks ) ) != 0 ) {
253 DBGC ( tftp, "TFTP %p could not resize bitmap to %d blocks: "
254 "%s\n", tftp, num_blocks, strerror ( rc ) );
262 * TFTP requested blocksize
264 * This is treated as a global configuration parameter.
266 static unsigned int tftp_request_blksize = TFTP_MAX_BLKSIZE;
269 * Set TFTP request blocksize
271 * @v blksize Requested block size
273 void tftp_set_request_blksize ( unsigned int blksize ) {
274 if ( blksize < TFTP_DEFAULT_BLKSIZE )
275 blksize = TFTP_DEFAULT_BLKSIZE;
276 tftp_request_blksize = blksize;
280 * MTFTP multicast receive address
282 * This is treated as a global configuration parameter.
284 static struct sockaddr_in tftp_mtftp_socket = {
285 .sin_family = AF_INET,
286 .sin_addr.s_addr = htonl ( 0xefff0101 ),
287 .sin_port = htons ( 3001 ),
291 * Set MTFTP multicast address
293 * @v address Multicast IPv4 address
295 void tftp_set_mtftp_address ( struct in_addr address ) {
296 tftp_mtftp_socket.sin_addr = address;
300 * Set MTFTP multicast port
302 * @v port Multicast port
304 void tftp_set_mtftp_port ( unsigned int port ) {
305 tftp_mtftp_socket.sin_port = htons ( port );
311 * @v tftp TFTP connection
312 * @ret rc Return status code
314 static int tftp_send_rrq ( struct tftp_request *tftp ) {
315 struct tftp_rrq *rrq;
316 const char *path = tftp->uri->path;
317 size_t len = ( sizeof ( *rrq ) + strlen ( path ) + 1 /* NUL */
318 + 5 + 1 /* "octet" + NUL */
319 + 7 + 1 + 5 + 1 /* "blksize" + NUL + ddddd + NUL */
320 + 5 + 1 + 1 + 1 /* "tsize" + NUL + "0" + NUL */
321 + 9 + 1 + 1 /* "multicast" + NUL + NUL */ );
322 struct io_buffer *iobuf;
324 DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, path );
326 /* Allocate buffer */
327 iobuf = xfer_alloc_iob ( &tftp->socket, len );
332 rrq = iob_put ( iobuf, sizeof ( *rrq ) );
333 rrq->opcode = htons ( TFTP_RRQ );
334 iob_put ( iobuf, snprintf ( iobuf->tail, iob_tailroom ( iobuf ),
335 "%s%coctet", path, 0 ) + 1 );
336 if ( tftp->flags & TFTP_FL_RRQ_SIZES ) {
337 iob_put ( iobuf, snprintf ( iobuf->tail,
338 iob_tailroom ( iobuf ),
339 "blksize%c%d%ctsize%c0", 0,
340 tftp_request_blksize, 0, 0 ) + 1 );
342 if ( tftp->flags & TFTP_FL_RRQ_MULTICAST ) {
343 iob_put ( iobuf, snprintf ( iobuf->tail,
344 iob_tailroom ( iobuf ),
345 "multicast%c", 0 ) + 1 );
348 /* RRQ always goes to the address specified in the initial
351 return xfer_deliver_iob ( &tftp->socket, iobuf );
357 * @v tftp TFTP connection
358 * @ret rc Return status code
360 static int tftp_send_ack ( struct tftp_request *tftp ) {
361 struct tftp_ack *ack;
362 struct io_buffer *iobuf;
363 struct xfer_metadata meta = {
364 .dest = ( struct sockaddr * ) &tftp->peer,
368 /* Determine next required block number */
369 block = bitmap_first_gap ( &tftp->bitmap );
370 DBGC2 ( tftp, "TFTP %p sending ACK for block %d\n", tftp, block );
372 /* Allocate buffer */
373 iobuf = xfer_alloc_iob ( &tftp->socket, sizeof ( *ack ) );
378 ack = iob_put ( iobuf, sizeof ( *ack ) );
379 ack->opcode = htons ( TFTP_ACK );
380 ack->block = htons ( block );
382 /* ACK always goes to the peer recorded from the RRQ response */
383 return xfer_deliver_iob_meta ( &tftp->socket, iobuf, &meta );
387 * Transmit next relevant packet
389 * @v tftp TFTP connection
390 * @ret rc Return status code
392 static int tftp_send_packet ( struct tftp_request *tftp ) {
394 /* Update retransmission timer */
395 stop_timer ( &tftp->timer );
396 start_timer ( &tftp->timer );
398 /* Send RRQ or ACK as appropriate */
399 if ( ! tftp->peer.st_family ) {
400 return tftp_send_rrq ( tftp );
402 if ( tftp->flags & TFTP_FL_SEND_ACK ) {
403 return tftp_send_ack ( tftp );
411 * Handle TFTP retransmission timer expiry
413 * @v timer Retry timer
414 * @v fail Failure indicator
416 static void tftp_timer_expired ( struct retry_timer *timer, int fail ) {
417 struct tftp_request *tftp =
418 container_of ( timer, struct tftp_request, timer );
421 /* If we are doing MTFTP, attempt the various recovery strategies */
422 if ( tftp->flags & TFTP_FL_MTFTP_RECOVERY ) {
423 if ( tftp->peer.st_family ) {
424 /* If we have received any response from the server,
425 * try resending the RRQ to restart the download.
427 DBGC ( tftp, "TFTP %p attempting reopen\n", tftp );
428 if ( ( rc = tftp_reopen ( tftp ) ) != 0 )
431 /* Fall back to plain TFTP after several attempts */
432 tftp->mtftp_timeouts++;
433 DBGC ( tftp, "TFTP %p timeout %d waiting for MTFTP "
434 "open\n", tftp, tftp->mtftp_timeouts );
436 if ( tftp->mtftp_timeouts > MTFTP_MAX_TIMEOUTS ) {
437 DBGC ( tftp, "TFTP %p falling back to plain "
439 tftp->flags = TFTP_FL_RRQ_SIZES;
441 /* Close multicast socket */
442 xfer_close ( &tftp->mc_socket, 0 );
444 /* Reset retry timer */
445 start_timer_nodelay ( &tftp->timer );
447 /* The blocksize may change: discard
450 bitmap_free ( &tftp->bitmap );
451 memset ( &tftp->bitmap, 0,
452 sizeof ( tftp->bitmap ) );
454 /* Reopen on standard TFTP port */
455 tftp->port = TFTP_PORT;
456 if ( ( rc = tftp_reopen ( tftp ) ) != 0 )
461 /* Not doing MTFTP (or have fallen back to plain
462 * TFTP); fail as per normal.
469 tftp_send_packet ( tftp );
473 tftp_done ( tftp, rc );
477 * Process TFTP "blksize" option
479 * @v tftp TFTP connection
480 * @v value Option value
481 * @ret rc Return status code
483 static int tftp_process_blksize ( struct tftp_request *tftp,
484 const char *value ) {
487 tftp->blksize = strtoul ( value, &end, 10 );
489 DBGC ( tftp, "TFTP %p got invalid blksize \"%s\"\n",
493 DBGC ( tftp, "TFTP %p blksize=%d\n", tftp, tftp->blksize );
499 * Process TFTP "tsize" option
501 * @v tftp TFTP connection
502 * @v value Option value
503 * @ret rc Return status code
505 static int tftp_process_tsize ( struct tftp_request *tftp,
506 const char *value ) {
509 tftp->tsize = strtoul ( value, &end, 10 );
511 DBGC ( tftp, "TFTP %p got invalid tsize \"%s\"\n",
515 DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
521 * Process TFTP "multicast" option
523 * @v tftp TFTP connection
524 * @v value Option value
525 * @ret rc Return status code
527 static int tftp_process_multicast ( struct tftp_request *tftp,
528 const char *value ) {
531 struct sockaddr_in sin;
533 char buf[ strlen ( value ) + 1 ];
541 /* Split value into "addr,port,mc" fields */
542 memcpy ( buf, value, sizeof ( buf ) );
544 port = strchr ( addr, ',' );
546 DBGC ( tftp, "TFTP %p multicast missing port,mc\n", tftp );
550 mc = strchr ( port, ',' );
552 DBGC ( tftp, "TFTP %p multicast missing mc\n", tftp );
557 /* Parse parameters */
558 if ( strtoul ( mc, &mc_end, 0 ) == 0 )
559 tftp->flags &= ~TFTP_FL_SEND_ACK;
561 DBGC ( tftp, "TFTP %p multicast invalid mc %s\n", tftp, mc );
564 DBGC ( tftp, "TFTP %p is%s the master client\n",
565 tftp, ( ( tftp->flags & TFTP_FL_SEND_ACK ) ? "" : " not" ) );
566 if ( *addr && *port ) {
567 socket.sin.sin_family = AF_INET;
568 if ( inet_aton ( addr, &socket.sin.sin_addr ) == 0 ) {
569 DBGC ( tftp, "TFTP %p multicast invalid IP address "
570 "%s\n", tftp, addr );
573 DBGC ( tftp, "TFTP %p multicast IP address %s\n",
574 tftp, inet_ntoa ( socket.sin.sin_addr ) );
575 socket.sin.sin_port = htons ( strtoul ( port, &port_end, 0 ) );
577 DBGC ( tftp, "TFTP %p multicast invalid port %s\n",
581 DBGC ( tftp, "TFTP %p multicast port %d\n",
582 tftp, ntohs ( socket.sin.sin_port ) );
583 if ( ( rc = tftp_reopen_mc ( tftp, &socket.sa ) ) != 0 )
596 * @v tftp TFTP connection
597 * @v value Option value
598 * @ret rc Return status code
600 int ( * process ) ( struct tftp_request *tftp, const char *value );
603 /** Recognised TFTP options */
604 static struct tftp_option tftp_options[] = {
605 { "blksize", tftp_process_blksize },
606 { "tsize", tftp_process_tsize },
607 { "multicast", tftp_process_multicast },
612 * Process TFTP option
614 * @v tftp TFTP connection
615 * @v name Option name
616 * @v value Option value
617 * @ret rc Return status code
619 static int tftp_process_option ( struct tftp_request *tftp,
620 const char *name, const char *value ) {
621 struct tftp_option *option;
623 for ( option = tftp_options ; option->name ; option++ ) {
624 if ( strcasecmp ( name, option->name ) == 0 )
625 return option->process ( tftp, value );
628 DBGC ( tftp, "TFTP %p received unknown option \"%s\" = \"%s\"\n",
631 /* Unknown options should be silently ignored */
638 * @v tftp TFTP connection
639 * @v buf Temporary data buffer
640 * @v len Length of temporary data buffer
641 * @ret rc Return status code
643 static int tftp_rx_oack ( struct tftp_request *tftp, void *buf, size_t len ) {
644 struct tftp_oack *oack = buf;
645 char *end = buf + len;
651 if ( len < sizeof ( *oack ) ) {
652 DBGC ( tftp, "TFTP %p received underlength OACK packet "
653 "length %zd\n", tftp, len );
657 if ( end[-1] != '\0' ) {
658 DBGC ( tftp, "TFTP %p received OACK missing final NUL\n",
664 /* Process each option in turn */
666 while ( name < end ) {
667 value = ( name + strlen ( name ) + 1 );
668 if ( value == end ) {
669 DBGC ( tftp, "TFTP %p received OACK missing value "
670 "for option \"%s\"\n", tftp, name );
674 if ( ( rc = tftp_process_option ( tftp, name, value ) ) != 0 )
676 name = ( value + strlen ( value ) + 1 );
679 /* Process tsize information, if available */
681 if ( ( rc = tftp_presize ( tftp, tftp->tsize ) ) != 0 )
685 /* Request next data block */
686 tftp_send_packet ( tftp );
690 tftp_done ( tftp, rc );
697 * @v tftp TFTP connection
698 * @v iobuf I/O buffer
699 * @ret rc Return status code
701 * Takes ownership of I/O buffer.
703 static int tftp_rx_data ( struct tftp_request *tftp,
704 struct io_buffer *iobuf ) {
705 struct tftp_data *data = iobuf->data;
706 struct xfer_metadata meta;
713 if ( iob_len ( iobuf ) < sizeof ( *data ) ) {
714 DBGC ( tftp, "TFTP %p received underlength DATA packet "
715 "length %zd\n", tftp, iob_len ( iobuf ) );
721 block = ( ntohs ( data->block ) - 1 );
722 offset = ( block * tftp->blksize );
723 iob_pull ( iobuf, sizeof ( *data ) );
724 data_len = iob_len ( iobuf );
725 if ( data_len > tftp->blksize ) {
726 DBGC ( tftp, "TFTP %p received overlength DATA packet "
727 "length %zd\n", tftp, data_len );
733 memset ( &meta, 0, sizeof ( meta ) );
734 meta.whence = SEEK_SET;
735 meta.offset = offset;
736 rc = xfer_deliver_iob_meta ( &tftp->xfer, iobuf, &meta );
739 DBGC ( tftp, "TFTP %p could not deliver data: %s\n",
740 tftp, strerror ( rc ) );
744 /* Ensure block bitmap is ready */
745 if ( ( rc = tftp_presize ( tftp, ( offset + data_len ) ) ) != 0 )
748 /* Mark block as received */
749 bitmap_set ( &tftp->bitmap, block );
751 /* Acknowledge block */
752 tftp_send_packet ( tftp );
754 /* If all blocks have been received, finish. */
755 if ( bitmap_full ( &tftp->bitmap ) )
756 tftp_done ( tftp, 0 );
761 tftp_done ( tftp, rc );
765 /** Translation between TFTP errors and internal error numbers */
766 static const int tftp_errors[] = {
767 [TFTP_ERR_FILE_NOT_FOUND] = ENOENT,
768 [TFTP_ERR_ACCESS_DENIED] = EACCES,
769 [TFTP_ERR_ILLEGAL_OP] = ENOTSUP,
775 * @v tftp TFTP connection
776 * @v buf Temporary data buffer
777 * @v len Length of temporary data buffer
778 * @ret rc Return status code
780 static int tftp_rx_error ( struct tftp_request *tftp, void *buf, size_t len ) {
781 struct tftp_error *error = buf;
786 if ( len < sizeof ( *error ) ) {
787 DBGC ( tftp, "TFTP %p received underlength ERROR packet "
788 "length %zd\n", tftp, len );
792 DBGC ( tftp, "TFTP %p received ERROR packet with code %d, message "
793 "\"%s\"\n", tftp, ntohs ( error->errcode ), error->errmsg );
795 /* Determine final operation result */
796 err = ntohs ( error->errcode );
797 if ( err < ( sizeof ( tftp_errors ) / sizeof ( tftp_errors[0] ) ) )
798 rc = -tftp_errors[err];
802 /* Close TFTP request */
803 tftp_done ( tftp, rc );
811 * @v tftp TFTP connection
812 * @v iobuf I/O buffer
813 * @v meta Transfer metadata, or NULL
814 * @ret rc Return status code
816 static int tftp_rx ( struct tftp_request *tftp,
817 struct io_buffer *iobuf,
818 struct xfer_metadata *meta ) {
819 struct sockaddr_tcpip *st_src;
820 struct tftp_common *common = iobuf->data;
821 size_t len = iob_len ( iobuf );
825 if ( len < sizeof ( *common ) ) {
826 DBGC ( tftp, "TFTP %p received underlength packet length "
827 "%zd\n", tftp, len );
831 DBGC ( tftp, "TFTP %p received packet without metadata\n",
836 DBGC ( tftp, "TFTP %p received packet without source port\n",
841 /* Filter by TID. Set TID on first response received */
842 st_src = ( struct sockaddr_tcpip * ) meta->src;
843 if ( ! tftp->peer.st_family ) {
844 memcpy ( &tftp->peer, st_src, sizeof ( tftp->peer ) );
845 DBGC ( tftp, "TFTP %p using remote port %d\n", tftp,
846 ntohs ( tftp->peer.st_port ) );
847 } else if ( memcmp ( &tftp->peer, st_src,
848 sizeof ( tftp->peer ) ) != 0 ) {
849 DBGC ( tftp, "TFTP %p received packet from wrong source (got "
850 "%d, wanted %d)\n", tftp, ntohs ( st_src->st_port ),
851 ntohs ( tftp->peer.st_port ) );
855 switch ( common->opcode ) {
856 case htons ( TFTP_OACK ):
857 rc = tftp_rx_oack ( tftp, iobuf->data, len );
859 case htons ( TFTP_DATA ):
860 rc = tftp_rx_data ( tftp, iobuf );
863 case htons ( TFTP_ERROR ):
864 rc = tftp_rx_error ( tftp, iobuf->data, len );
867 DBGC ( tftp, "TFTP %p received strange packet type %d\n",
868 tftp, ntohs ( common->opcode ) );
878 * Receive new data via socket
880 * @v socket Transport layer interface
881 * @v iobuf I/O buffer
882 * @v meta Transfer metadata, or NULL
883 * @ret rc Return status code
885 static int tftp_socket_deliver_iob ( struct xfer_interface *socket,
886 struct io_buffer *iobuf,
887 struct xfer_metadata *meta ) {
888 struct tftp_request *tftp =
889 container_of ( socket, struct tftp_request, socket );
891 /* Enable sending ACKs when we receive a unicast packet. This
892 * covers three cases:
894 * 1. Standard TFTP; we should always send ACKs, and will
895 * always receive a unicast packet before we need to send the
898 * 2. RFC2090 multicast TFTP; the only unicast packets we will
899 * receive are the OACKs; enable sending ACKs here (before
900 * processing the OACK) and disable it when processing the
901 * multicast option if we are not the master client.
903 * 3. MTFTP; receiving a unicast datagram indicates that we
904 * are the "master client" and should send ACKs.
906 tftp->flags |= TFTP_FL_SEND_ACK;
908 return tftp_rx ( tftp, iobuf, meta );
911 /** TFTP socket operations */
912 static struct xfer_interface_operations tftp_socket_operations = {
913 .close = ignore_xfer_close,
914 .vredirect = xfer_vopen,
915 .window = unlimited_xfer_window,
916 .alloc_iob = default_xfer_alloc_iob,
917 .deliver_iob = tftp_socket_deliver_iob,
918 .deliver_raw = xfer_deliver_as_iob,
922 * Receive new data via multicast socket
924 * @v mc_socket Multicast transport layer interface
925 * @v iobuf I/O buffer
926 * @v meta Transfer metadata, or NULL
927 * @ret rc Return status code
929 static int tftp_mc_socket_deliver_iob ( struct xfer_interface *mc_socket,
930 struct io_buffer *iobuf,
931 struct xfer_metadata *meta ) {
932 struct tftp_request *tftp =
933 container_of ( mc_socket, struct tftp_request, mc_socket );
935 return tftp_rx ( tftp, iobuf, meta );
938 /** TFTP multicast socket operations */
939 static struct xfer_interface_operations tftp_mc_socket_operations = {
940 .close = ignore_xfer_close,
941 .vredirect = xfer_vopen,
942 .window = unlimited_xfer_window,
943 .alloc_iob = default_xfer_alloc_iob,
944 .deliver_iob = tftp_mc_socket_deliver_iob,
945 .deliver_raw = xfer_deliver_as_iob,
949 * Close TFTP data transfer interface
951 * @v xfer Data transfer interface
952 * @v rc Reason for close
954 static void tftp_xfer_close ( struct xfer_interface *xfer, int rc ) {
955 struct tftp_request *tftp =
956 container_of ( xfer, struct tftp_request, xfer );
958 DBGC ( tftp, "TFTP %p interface closed: %s\n",
959 tftp, strerror ( rc ) );
961 tftp_done ( tftp, rc );
964 /** TFTP data transfer interface operations */
965 static struct xfer_interface_operations tftp_xfer_operations = {
966 .close = tftp_xfer_close,
967 .vredirect = ignore_xfer_vredirect,
968 .window = unlimited_xfer_window,
969 .alloc_iob = default_xfer_alloc_iob,
970 .deliver_iob = xfer_deliver_as_raw,
971 .deliver_raw = ignore_xfer_deliver_raw,
975 * Initiate TFTP/TFTM/MTFTP download
977 * @v xfer Data transfer interface
978 * @v uri Uniform Resource Identifier
979 * @ret rc Return status code
981 static int tftp_core_open ( struct xfer_interface *xfer, struct uri *uri,
982 unsigned int default_port,
983 struct sockaddr *multicast,
984 unsigned int flags ) {
985 struct tftp_request *tftp;
994 /* Allocate and populate TFTP structure */
995 tftp = zalloc ( sizeof ( *tftp ) );
998 tftp->refcnt.free = tftp_free;
999 xfer_init ( &tftp->xfer, &tftp_xfer_operations, &tftp->refcnt );
1000 tftp->uri = uri_get ( uri );
1001 xfer_init ( &tftp->socket, &tftp_socket_operations, &tftp->refcnt );
1002 xfer_init ( &tftp->mc_socket, &tftp_mc_socket_operations,
1004 tftp->blksize = TFTP_DEFAULT_BLKSIZE;
1005 tftp->flags = flags;
1006 tftp->timer.expired = tftp_timer_expired;
1009 tftp->port = uri_port ( tftp->uri, default_port );
1010 if ( ( rc = tftp_reopen ( tftp ) ) != 0 )
1013 /* Open multicast socket */
1015 if ( ( rc = tftp_reopen_mc ( tftp, multicast ) ) != 0 )
1019 /* Start timer to initiate RRQ */
1020 start_timer_nodelay ( &tftp->timer );
1022 /* Attach to parent interface, mortalise self, and return */
1023 xfer_plug_plug ( &tftp->xfer, xfer );
1024 ref_put ( &tftp->refcnt );
1028 DBGC ( tftp, "TFTP %p could not create request: %s\n",
1029 tftp, strerror ( rc ) );
1030 tftp_done ( tftp, rc );
1031 ref_put ( &tftp->refcnt );
1036 * Initiate TFTP download
1038 * @v xfer Data transfer interface
1039 * @v uri Uniform Resource Identifier
1040 * @ret rc Return status code
1042 static int tftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
1043 return tftp_core_open ( xfer, uri, TFTP_PORT, NULL,
1044 TFTP_FL_RRQ_SIZES );
1048 /** TFTP URI opener */
1049 struct uri_opener tftp_uri_opener __uri_opener = {
1055 * Initiate TFTM download
1057 * @v xfer Data transfer interface
1058 * @v uri Uniform Resource Identifier
1059 * @ret rc Return status code
1061 static int tftm_open ( struct xfer_interface *xfer, struct uri *uri ) {
1062 return tftp_core_open ( xfer, uri, TFTP_PORT, NULL,
1063 ( TFTP_FL_RRQ_SIZES |
1064 TFTP_FL_RRQ_MULTICAST ) );
1068 /** TFTM URI opener */
1069 struct uri_opener tftm_uri_opener __uri_opener = {
1075 * Initiate MTFTP download
1077 * @v xfer Data transfer interface
1078 * @v uri Uniform Resource Identifier
1079 * @ret rc Return status code
1081 static int mtftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
1082 return tftp_core_open ( xfer, uri, MTFTP_PORT,
1083 ( struct sockaddr * ) &tftp_mtftp_socket,
1084 TFTP_FL_MTFTP_RECOVERY );
1087 /** MTFTP URI opener */
1088 struct uri_opener mtftp_uri_opener __uri_opener = {