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/tftp.h>
44 * This data structure holds the state for an ongoing TFTP transfer.
47 /** Reference count */
49 /** Data transfer interface */
50 struct xfer_interface xfer;
52 /** URI being fetched */
54 /** Transport layer interface */
55 struct xfer_interface socket;
59 * This is the "blksize" option negotiated with the TFTP
60 * server. (If the TFTP server does not support TFTP options,
61 * this will default to 512).
66 * This is the value returned in the "tsize" option from the
67 * TFTP server. If the TFTP server does not support the
68 * "tsize" option, this value will be zero.
74 * This is the block number to be used in the next ACK sent
75 * back to the server, i.e. the number of the last received
76 * data block. The value zero indicates that the last
77 * received block was an OACK (i.e. that the next ACK will
78 * contain a block number of zero), and any value less than
79 * zero indicates that the connection has not yet been opened
80 * (i.e. that no blocks have yet been received).
85 * The peer address is determined by the first response
86 * received to the TFTP RRQ.
88 struct sockaddr_tcpip peer;
89 /** Retransmission timer */
90 struct retry_timer timer;
96 * @v refcnt Reference counter
98 static void tftp_free ( struct refcnt *refcnt ) {
99 struct tftp_request *tftp =
100 container_of ( refcnt, struct tftp_request, refcnt );
102 uri_put ( tftp->uri );
107 * Mark TFTP request as complete
109 * @v tftp TFTP connection
110 * @v rc Return status code
112 static void tftp_done ( struct tftp_request *tftp, int rc ) {
114 DBGC ( tftp, "TFTP %p finished with status %d (%s)\n",
115 tftp, rc, strerror ( rc ) );
117 /* Stop the retry timer */
118 stop_timer ( &tftp->timer );
120 /* Close all data transfer interfaces */
121 xfer_nullify ( &tftp->socket );
122 xfer_close ( &tftp->socket, rc );
123 xfer_nullify ( &tftp->xfer );
124 xfer_close ( &tftp->xfer, rc );
128 * TFTP requested blocksize
130 * This is treated as a global configuration parameter.
132 static unsigned int tftp_request_blksize = TFTP_MAX_BLKSIZE;
135 * Set TFTP request blocksize
137 * @v blksize Requested block size
139 void tftp_set_request_blksize ( unsigned int blksize ) {
140 if ( blksize < TFTP_DEFAULT_BLKSIZE )
141 blksize = TFTP_DEFAULT_BLKSIZE;
142 tftp_request_blksize = blksize;
148 * @v tftp TFTP connection
149 * @ret rc Return status code
151 static int tftp_send_rrq ( struct tftp_request *tftp ) {
152 struct tftp_rrq *rrq;
153 const char *path = tftp->uri->path;
154 size_t len = ( sizeof ( *rrq ) + strlen ( path ) + 1 /* NUL */
155 + 5 + 1 /* "octet" + NUL */
156 + 7 + 1 + 5 + 1 /* "blksize" + NUL + ddddd + NUL */
157 + 5 + 1 + 1 + 1 /* "tsize" + NUL + "0" + NUL */ );
158 struct io_buffer *iobuf;
160 DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, path );
162 /* Allocate buffer */
163 iobuf = xfer_alloc_iob ( &tftp->socket, len );
168 rrq = iob_put ( iobuf, sizeof ( *rrq ) );
169 rrq->opcode = htons ( TFTP_RRQ );
171 snprintf ( rrq->data, iob_tailroom ( iobuf ),
172 "%s%coctet%cblksize%c%d%ctsize%c0", path, 0,
173 0, 0, tftp_request_blksize, 0, 0 ) + 1 );
175 /* RRQ always goes to the address specified in the initial
178 return xfer_deliver_iob ( &tftp->socket, iobuf );
184 * @v tftp TFTP connection
185 * @ret rc Return status code
187 static int tftp_send_ack ( struct tftp_request *tftp ) {
188 struct tftp_ack *ack;
189 struct io_buffer *iobuf;
190 struct xfer_metadata meta = {
191 .dest = ( struct sockaddr * ) &tftp->peer,
194 DBGC2 ( tftp, "TFTP %p sending ACK for block %d\n",
197 /* Allocate buffer */
198 iobuf = xfer_alloc_iob ( &tftp->socket, sizeof ( *ack ) );
203 ack = iob_put ( iobuf, sizeof ( *ack ) );
204 ack->opcode = htons ( TFTP_ACK );
205 ack->block = htons ( tftp->state );
207 /* ACK always goes to the peer recorded from the RRQ response */
208 return xfer_deliver_iob_meta ( &tftp->socket, iobuf, &meta );
214 * @v tftp TFTP connection
215 * @ret rc Return status code
217 static int tftp_send_packet ( struct tftp_request *tftp ) {
219 /* Start retransmission timer */
220 start_timer ( &tftp->timer );
222 /* Send RRQ or ACK as appropriate */
223 if ( tftp->state < 0 ) {
224 return tftp_send_rrq ( tftp );
226 return tftp_send_ack ( tftp );
231 * Handle TFTP retransmission timer expiry
233 * @v timer Retry timer
234 * @v fail Failure indicator
236 static void tftp_timer_expired ( struct retry_timer *timer, int fail ) {
237 struct tftp_request *tftp =
238 container_of ( timer, struct tftp_request, timer );
241 tftp_done ( tftp, -ETIMEDOUT );
243 tftp_send_packet ( tftp );
248 * Mark TFTP block as received
250 * @v tftp TFTP connection
251 * @v block Block number
253 static void tftp_received ( struct tftp_request *tftp, unsigned int block ) {
255 /* Stop the retry timer */
256 stop_timer ( &tftp->timer );
258 /* Update state to indicate which block we're now waiting for */
261 /* Send next packet */
262 tftp_send_packet ( tftp );
266 * Process TFTP "blksize" option
268 * @v tftp TFTP connection
269 * @v value Option value
270 * @ret rc Return status code
272 static int tftp_process_blksize ( struct tftp_request *tftp,
273 const char *value ) {
276 tftp->blksize = strtoul ( value, &end, 10 );
278 DBGC ( tftp, "TFTP %p got invalid blksize \"%s\"\n",
282 DBGC ( tftp, "TFTP %p blksize=%d\n", tftp, tftp->blksize );
288 * Process TFTP "tsize" option
290 * @v tftp TFTP connection
291 * @v value Option value
292 * @ret rc Return status code
294 static int tftp_process_tsize ( struct tftp_request *tftp,
295 const char *value ) {
298 tftp->tsize = strtoul ( value, &end, 10 );
300 DBGC ( tftp, "TFTP %p got invalid tsize \"%s\"\n",
304 DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
306 /* Notify recipient of file size */
307 xfer_seek ( &tftp->xfer, tftp->tsize, SEEK_SET );
308 xfer_seek ( &tftp->xfer, 0, SEEK_SET );
319 * @v tftp TFTP connection
320 * @v value Option value
321 * @ret rc Return status code
323 int ( * process ) ( struct tftp_request *tftp, const char *value );
326 /** Recognised TFTP options */
327 static struct tftp_option tftp_options[] = {
328 { "blksize", tftp_process_blksize },
329 { "tsize", tftp_process_tsize },
334 * Process TFTP option
336 * @v tftp TFTP connection
337 * @v name Option name
338 * @v value Option value
339 * @ret rc Return status code
341 static int tftp_process_option ( struct tftp_request *tftp,
342 const char *name, const char *value ) {
343 struct tftp_option *option;
345 for ( option = tftp_options ; option->name ; option++ ) {
346 if ( strcasecmp ( name, option->name ) == 0 )
347 return option->process ( tftp, value );
350 DBGC ( tftp, "TFTP %p received unknown option \"%s\" = \"%s\"\n",
359 * @v tftp TFTP connection
360 * @v buf Temporary data buffer
361 * @v len Length of temporary data buffer
362 * @ret rc Return status code
364 static int tftp_rx_oack ( struct tftp_request *tftp, void *buf, size_t len ) {
365 struct tftp_oack *oack = buf;
366 char *end = buf + len;
372 if ( len < sizeof ( *oack ) ) {
373 DBGC ( tftp, "TFTP %p received underlength OACK packet "
374 "length %d\n", tftp, len );
377 if ( end[-1] != '\0' ) {
378 DBGC ( tftp, "TFTP %p received OACK missing final NUL\n",
383 /* Process each option in turn */
385 while ( name < end ) {
386 value = ( name + strlen ( name ) + 1 );
387 if ( value == end ) {
388 DBGC ( tftp, "TFTP %p received OACK missing value "
389 "for option \"%s\"\n", tftp, name );
392 if ( ( rc = tftp_process_option ( tftp, name, value ) ) != 0 )
394 name = ( value + strlen ( value ) + 1 );
397 /* Mark as received block 0 (the OACK) */
398 tftp_received ( tftp, 0 );
406 * @v tftp TFTP connection
407 * @v iobuf I/O buffer
408 * @ret rc Return status code
410 * Takes ownership of I/O buffer.
412 static int tftp_rx_data ( struct tftp_request *tftp,
413 struct io_buffer *iobuf ) {
414 struct tftp_data *data = iobuf->data;
420 if ( iob_len ( iobuf ) < sizeof ( *data ) ) {
421 DBGC ( tftp, "TFTP %p received underlength DATA packet "
422 "length %d\n", tftp, iob_len ( iobuf ) );
428 block = ntohs ( data->block );
429 iob_pull ( iobuf, sizeof ( *data ) );
430 data_len = iob_len ( iobuf );
433 if ( ( rc = xfer_deliver_iob ( &tftp->xfer, iobuf ) ) != 0 ) {
434 DBGC ( tftp, "TFTP %p could not deliver data: %s\n",
435 tftp, strerror ( rc ) );
436 tftp_done ( tftp, rc );
440 /* Mark block as received */
441 tftp_received ( tftp, block );
443 /* Finish when final block received */
444 if ( data_len < tftp->blksize )
445 tftp_done ( tftp, 0 );
450 /** Translation between TFTP errors and internal error numbers */
451 static const uint8_t tftp_errors[] = {
452 [TFTP_ERR_FILE_NOT_FOUND] = PXENV_STATUS_TFTP_FILE_NOT_FOUND,
453 [TFTP_ERR_ACCESS_DENIED] = PXENV_STATUS_TFTP_ACCESS_VIOLATION,
454 [TFTP_ERR_ILLEGAL_OP] = PXENV_STATUS_TFTP_UNKNOWN_OPCODE,
460 * @v tftp TFTP connection
461 * @v buf Temporary data buffer
462 * @v len Length of temporary data buffer
463 * @ret rc Return status code
465 static int tftp_rx_error ( struct tftp_request *tftp, void *buf, size_t len ) {
466 struct tftp_error *error = buf;
471 if ( len < sizeof ( *error ) ) {
472 DBGC ( tftp, "TFTP %p received underlength ERROR packet "
473 "length %d\n", tftp, len );
477 DBGC ( tftp, "TFTP %p received ERROR packet with code %d, message "
478 "\"%s\"\n", tftp, ntohs ( error->errcode ), error->errmsg );
480 /* Determine final operation result */
481 err = ntohs ( error->errcode );
482 if ( err < ( sizeof ( tftp_errors ) / sizeof ( tftp_errors[0] ) ) )
483 rc = -tftp_errors[err];
485 rc = -PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION;
487 /* Close TFTP request */
488 tftp_done ( tftp, rc );
496 * @v udp UDP connection
497 * @v data Received data
498 * @v len Length of received data
499 * @v st_src Partially-filled source address
500 * @v st_dest Partially-filled destination address
502 static int tftp_socket_deliver_iob ( struct xfer_interface *socket,
503 struct io_buffer *iobuf,
504 struct xfer_metadata *meta ) {
505 struct tftp_request *tftp =
506 container_of ( socket, struct tftp_request, socket );
507 struct sockaddr_tcpip *st_src;
508 struct tftp_common *common = iobuf->data;
509 size_t len = iob_len ( iobuf );
513 if ( len < sizeof ( *common ) ) {
514 DBGC ( tftp, "TFTP %p received underlength packet length %d\n",
519 DBGC ( tftp, "TFTP %p received packet without metadata\n",
524 DBGC ( tftp, "TFTP %p received packet without source port\n",
529 /* Filter by TID. Set TID on first response received */
530 st_src = ( struct sockaddr_tcpip * ) meta->src;
531 if ( tftp->state < 0 ) {
532 memcpy ( &tftp->peer, st_src, sizeof ( tftp->peer ) );
533 DBGC ( tftp, "TFTP %p using remote port %d\n", tftp,
534 ntohs ( tftp->peer.st_port ) );
535 } else if ( memcmp ( &tftp->peer, st_src,
536 sizeof ( tftp->peer ) ) != 0 ) {
537 DBGC ( tftp, "TFTP %p received packet from wrong source (got "
538 "%d, wanted %d)\n", tftp, ntohs ( st_src->st_port ),
539 ntohs ( tftp->peer.st_port ) );
543 switch ( common->opcode ) {
544 case htons ( TFTP_OACK ):
545 rc = tftp_rx_oack ( tftp, iobuf->data, len );
547 case htons ( TFTP_DATA ):
548 rc = tftp_rx_data ( tftp, iobuf );
551 case htons ( TFTP_ERROR ):
552 rc = tftp_rx_error ( tftp, iobuf->data, len );
555 DBGC ( tftp, "TFTP %p received strange packet type %d\n",
556 tftp, ntohs ( common->opcode ) );
566 * TFTP connection closed by network stack
568 * @v socket Transport layer interface
569 * @v rc Reason for close
571 static void tftp_socket_close ( struct xfer_interface *socket, int rc ) {
572 struct tftp_request *tftp =
573 container_of ( socket, struct tftp_request, socket );
575 DBGC ( tftp, "TFTP %p socket closed: %s\n",
576 tftp, strerror ( rc ) );
578 tftp_done ( tftp, rc );
581 /** TFTP socket operations */
582 static struct xfer_interface_operations tftp_socket_operations = {
583 .close = tftp_socket_close,
584 .vredirect = xfer_vopen,
585 .seek = ignore_xfer_seek,
586 .window = unlimited_xfer_window,
587 .alloc_iob = default_xfer_alloc_iob,
588 .deliver_iob = tftp_socket_deliver_iob,
589 .deliver_raw = xfer_deliver_as_iob,
593 * Close TFTP data transfer interface
595 * @v xfer Data transfer interface
596 * @v rc Reason for close
598 static void tftp_xfer_close ( struct xfer_interface *xfer, int rc ) {
599 struct tftp_request *tftp =
600 container_of ( xfer, struct tftp_request, xfer );
602 DBGC ( tftp, "TFTP %p interface closed: %s\n",
603 tftp, strerror ( rc ) );
605 tftp_done ( tftp, rc );
608 /** TFTP data transfer interface operations */
609 static struct xfer_interface_operations tftp_xfer_operations = {
610 .close = tftp_xfer_close,
611 .vredirect = ignore_xfer_vredirect,
612 .seek = ignore_xfer_seek,
613 .window = unlimited_xfer_window,
614 .alloc_iob = default_xfer_alloc_iob,
615 .deliver_iob = xfer_deliver_as_raw,
616 .deliver_raw = ignore_xfer_deliver_raw,
620 * Initiate TFTP download
622 * @v xfer Data transfer interface
623 * @v uri Uniform Resource Identifier
624 * @ret rc Return status code
626 int tftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
627 struct tftp_request *tftp;
628 struct sockaddr_tcpip server;
637 /* Allocate and populate TFTP structure */
638 tftp = zalloc ( sizeof ( *tftp ) );
641 tftp->refcnt.free = tftp_free;
642 xfer_init ( &tftp->xfer, &tftp_xfer_operations, &tftp->refcnt );
643 tftp->uri = uri_get ( uri );
644 xfer_init ( &tftp->socket, &tftp_socket_operations, &tftp->refcnt );
646 tftp->timer.expired = tftp_timer_expired;
649 memset ( &server, 0, sizeof ( server ) );
650 server.st_port = htons ( uri_port ( tftp->uri, TFTP_PORT ) );
651 if ( ( rc = xfer_open_named_socket ( &tftp->socket, SOCK_DGRAM,
652 ( struct sockaddr * ) &server,
653 uri->host, NULL ) ) != 0 )
656 /* Start timer to initiate RRQ */
657 start_timer ( &tftp->timer );
659 /* Attach to parent interface, mortalise self, and return */
660 xfer_plug_plug ( &tftp->xfer, xfer );
661 ref_put ( &tftp->refcnt );
665 DBGC ( tftp, "TFTP %p could not create request: %s\n",
666 tftp, strerror ( rc ) );
667 tftp_done ( tftp, rc );
668 ref_put ( &tftp->refcnt );
672 /** TFTP URI opener */
673 struct uri_opener tftp_uri_opener __uri_opener = {