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/tftp.h>
42 * This data structure holds the state for an ongoing TFTP transfer.
45 /** Reference count */
47 /** Data transfer interface */
48 struct xfer_interface xfer;
50 /** URI being fetched */
52 /** Transport layer interface */
53 struct xfer_interface socket;
57 * This is the "blksize" option negotiated with the TFTP
58 * server. (If the TFTP server does not support TFTP options,
59 * this will default to 512).
64 * This is the value returned in the "tsize" option from the
65 * TFTP server. If the TFTP server does not support the
66 * "tsize" option, this value will be zero.
72 * This is the block number to be used in the next ACK sent
73 * back to the server, i.e. the number of the last received
74 * data block. The value zero indicates that the last
75 * received block was an OACK (i.e. that the next ACK will
76 * contain a block number of zero), and any value less than
77 * zero indicates that the connection has not yet been opened
78 * (i.e. that no blocks have yet been received).
83 * The peer address is determined by the first response
84 * received to the TFTP RRQ.
86 struct sockaddr_tcpip peer;
87 /** Retransmission timer */
88 struct retry_timer timer;
94 * @v refcnt Reference counter
96 static void tftp_free ( struct refcnt *refcnt ) {
97 struct tftp_request *tftp =
98 container_of ( refcnt, struct tftp_request, refcnt );
100 uri_put ( tftp->uri );
105 * Mark TFTP request as complete
107 * @v tftp TFTP connection
108 * @v rc Return status code
110 static void tftp_done ( struct tftp_request *tftp, int rc ) {
112 /* Stop the retry timer */
113 stop_timer ( &tftp->timer );
115 /* Close all data transfer interfaces */
116 xfer_nullify ( &tftp->socket );
117 xfer_close ( &tftp->socket, rc );
118 xfer_nullify ( &tftp->xfer );
119 xfer_close ( &tftp->xfer, rc );
123 * TFTP requested blocksize
125 * This is treated as a global configuration parameter.
127 static unsigned int tftp_request_blksize = TFTP_MAX_BLKSIZE;
130 * Set TFTP request blocksize
132 * @v blksize Requested block size
134 void tftp_set_request_blksize ( unsigned int blksize ) {
135 if ( blksize < TFTP_DEFAULT_BLKSIZE )
136 blksize = TFTP_DEFAULT_BLKSIZE;
137 tftp_request_blksize = blksize;
143 * @v tftp TFTP connection
144 * @ret rc Return status code
146 static int tftp_send_rrq ( struct tftp_request *tftp ) {
147 struct tftp_rrq *rrq;
148 const char *path = tftp->uri->path;
149 size_t len = ( sizeof ( *rrq ) + strlen ( path ) + 1 /* NUL */
150 + 5 + 1 /* "octet" + NUL */
151 + 7 + 1 + 5 + 1 /* "blksize" + NUL + ddddd + NUL */
152 + 5 + 1 + 1 + 1 /* "tsize" + NUL + "0" + NUL */ );
153 struct io_buffer *iobuf;
155 DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, path );
157 /* Allocate buffer */
158 iobuf = xfer_alloc_iob ( &tftp->socket, len );
163 rrq = iob_put ( iobuf, sizeof ( *rrq ) );
164 rrq->opcode = htons ( TFTP_RRQ );
166 snprintf ( iobuf->data, iob_tailroom ( iobuf ),
167 "%s%coctet%cblksize%c%d%ctsize%c0", path, 0,
168 0, 0, tftp_request_blksize, 0, 0 ) + 1 );
170 /* RRQ always goes to the address specified in the initial
173 return xfer_deliver_iob ( &tftp->socket, iobuf );
179 * @v tftp TFTP connection
180 * @ret rc Return status code
182 static int tftp_send_ack ( struct tftp_request *tftp ) {
183 struct tftp_ack *ack;
184 struct io_buffer *iobuf;
185 struct xfer_metadata meta = {
186 .dest = ( struct sockaddr * ) &tftp->peer,
189 /* Allocate buffer */
190 iobuf = xfer_alloc_iob ( &tftp->socket, sizeof ( *ack ) );
195 ack = iob_put ( iobuf, sizeof ( *ack ) );
196 ack->opcode = htons ( TFTP_ACK );
197 ack->block = htons ( tftp->state );
199 /* ACK always goes to the peer recorded from the RRQ response */
200 return xfer_deliver_iob_meta ( &tftp->socket, iobuf, &meta );
206 * @v tftp TFTP connection
207 * @ret rc Return status code
209 static int tftp_send_packet ( struct tftp_request *tftp ) {
211 /* Start retransmission timer */
212 start_timer ( &tftp->timer );
214 /* Send RRQ or ACK as appropriate */
215 if ( tftp->state < 0 ) {
216 return tftp_send_rrq ( tftp );
218 return tftp_send_ack ( tftp );
223 * Handle TFTP retransmission timer expiry
225 * @v timer Retry timer
226 * @v fail Failure indicator
228 static void tftp_timer_expired ( struct retry_timer *timer, int fail ) {
229 struct tftp_request *tftp =
230 container_of ( timer, struct tftp_request, timer );
233 tftp_done ( tftp, -ETIMEDOUT );
235 tftp_send_packet ( tftp );
240 * Mark TFTP block as received
242 * @v tftp TFTP connection
243 * @v block Block number
245 static void tftp_received ( struct tftp_request *tftp, unsigned int block ) {
247 /* Stop the retry timer */
248 stop_timer ( &tftp->timer );
250 /* Update state to indicate which block we're now waiting for */
253 /* Send next packet */
254 tftp_send_packet ( tftp );
258 * Process TFTP "blksize" option
260 * @v tftp TFTP connection
261 * @v value Option value
262 * @ret rc Return status code
264 static int tftp_process_blksize ( struct tftp_request *tftp,
265 const char *value ) {
268 tftp->blksize = strtoul ( value, &end, 10 );
270 DBGC ( tftp, "TFTP %p got invalid blksize \"%s\"\n",
274 DBGC ( tftp, "TFTP %p blksize=%d\n", tftp, tftp->blksize );
280 * Process TFTP "tsize" option
282 * @v tftp TFTP connection
283 * @v value Option value
284 * @ret rc Return status code
286 static int tftp_process_tsize ( struct tftp_request *tftp,
287 const char *value ) {
290 tftp->tsize = strtoul ( value, &end, 10 );
292 DBGC ( tftp, "TFTP %p got invalid tsize \"%s\"\n",
296 DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
298 /* Notify recipient of file size */
299 xfer_seek ( &tftp->xfer, tftp->tsize, SEEK_SET );
300 xfer_seek ( &tftp->xfer, 0, SEEK_SET );
311 * @v tftp TFTP connection
312 * @v value Option value
313 * @ret rc Return status code
315 int ( * process ) ( struct tftp_request *tftp, const char *value );
318 /** Recognised TFTP options */
319 static struct tftp_option tftp_options[] = {
320 { "blksize", tftp_process_blksize },
321 { "tsize", tftp_process_tsize },
326 * Process TFTP option
328 * @v tftp TFTP connection
329 * @v name Option name
330 * @v value Option value
331 * @ret rc Return status code
333 static int tftp_process_option ( struct tftp_request *tftp,
334 const char *name, const char *value ) {
335 struct tftp_option *option;
337 for ( option = tftp_options ; option->name ; option++ ) {
338 if ( strcasecmp ( name, option->name ) == 0 )
339 return option->process ( tftp, value );
342 DBGC ( tftp, "TFTP %p received unknown option \"%s\" = \"%s\"\n",
351 * @v tftp TFTP connection
352 * @v buf Temporary data buffer
353 * @v len Length of temporary data buffer
354 * @ret rc Return status code
356 static int tftp_rx_oack ( struct tftp_request *tftp, void *buf, size_t len ) {
357 struct tftp_oack *oack = buf;
358 char *end = buf + len;
364 if ( len < sizeof ( *oack ) ) {
365 DBGC ( tftp, "TFTP %p received underlength OACK packet "
366 "length %d\n", tftp, len );
369 if ( end[-1] != '\0' ) {
370 DBGC ( tftp, "TFTP %p received OACK missing final NUL\n",
375 /* Process each option in turn */
377 while ( name < end ) {
378 value = ( name + strlen ( name ) + 1 );
379 if ( value == end ) {
380 DBGC ( tftp, "TFTP %p received OACK missing value "
381 "for option \"%s\"\n", tftp, name );
384 if ( ( rc = tftp_process_option ( tftp, name, value ) ) != 0 )
386 name = ( value + strlen ( value ) + 1 );
389 /* Mark as received block 0 (the OACK) */
390 tftp_received ( tftp, 0 );
398 * @v tftp TFTP connection
399 * @v iobuf I/O buffer
400 * @ret rc Return status code
402 * Takes ownership of I/O buffer.
404 static int tftp_rx_data ( struct tftp_request *tftp,
405 struct io_buffer *iobuf ) {
406 struct tftp_data *data = iobuf->data;
412 if ( iob_len ( iobuf ) < sizeof ( *data ) ) {
413 DBGC ( tftp, "TFTP %p received underlength DATA packet "
414 "length %d\n", tftp, iob_len ( iobuf ) );
420 block = ntohs ( data->block );
421 iob_pull ( iobuf, sizeof ( *data ) );
422 data_len = iob_len ( iobuf );
425 if ( ( rc = xfer_deliver_iob ( &tftp->xfer, iobuf ) ) != 0 ) {
426 DBGC ( tftp, "TFTP %p could not deliver data: %s\n",
427 tftp, strerror ( rc ) );
428 tftp_done ( tftp, rc );
432 /* Mark block as received */
433 tftp_received ( tftp, block );
435 /* Finish when final block received */
436 if ( data_len < tftp->blksize )
437 tftp_done ( tftp, 0 );
442 /** Translation between TFTP errors and internal error numbers */
443 static const uint8_t tftp_errors[] = {
444 [TFTP_ERR_FILE_NOT_FOUND] = PXENV_STATUS_TFTP_FILE_NOT_FOUND,
445 [TFTP_ERR_ACCESS_DENIED] = PXENV_STATUS_TFTP_ACCESS_VIOLATION,
446 [TFTP_ERR_ILLEGAL_OP] = PXENV_STATUS_TFTP_UNKNOWN_OPCODE,
452 * @v tftp TFTP connection
453 * @v buf Temporary data buffer
454 * @v len Length of temporary data buffer
455 * @ret rc Return status code
457 static int tftp_rx_error ( struct tftp_request *tftp, void *buf, size_t len ) {
458 struct tftp_error *error = buf;
463 if ( len < sizeof ( *error ) ) {
464 DBGC ( tftp, "TFTP %p received underlength ERROR packet "
465 "length %d\n", tftp, len );
469 DBGC ( tftp, "TFTP %p received ERROR packet with code %d, message "
470 "\"%s\"\n", tftp, ntohs ( error->errcode ), error->errmsg );
472 /* Determine final operation result */
473 err = ntohs ( error->errcode );
474 if ( err < ( sizeof ( tftp_errors ) / sizeof ( tftp_errors[0] ) ) )
475 rc = -tftp_errors[err];
477 rc = -PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION;
479 /* Close TFTP request */
480 tftp_done ( tftp, rc );
488 * @v udp UDP connection
489 * @v data Received data
490 * @v len Length of received data
491 * @v st_src Partially-filled source address
492 * @v st_dest Partially-filled destination address
494 static int tftp_socket_deliver_iob ( struct xfer_interface *socket,
495 struct io_buffer *iobuf,
496 struct xfer_metadata *meta ) {
497 struct tftp_request *tftp =
498 container_of ( socket, struct tftp_request, socket );
499 struct sockaddr_tcpip *st_src;
500 struct tftp_common *common = iobuf->data;
501 size_t len = iob_len ( iobuf );
505 if ( len < sizeof ( *common ) ) {
506 DBGC ( tftp, "TFTP %p received underlength packet length %d\n",
511 DBGC ( tftp, "TFTP %p received packet without metadata\n",
516 DBGC ( tftp, "TFTP %p received packet without source port\n",
521 /* Filter by TID. Set TID on first response received */
522 st_src = ( struct sockaddr_tcpip * ) meta->src;
523 if ( tftp->state < 0 ) {
524 memcpy ( &tftp->peer, st_src, sizeof ( tftp->peer ) );
525 DBGC ( tftp, "TFTP %p using remote port %d\n", tftp,
526 ntohs ( tftp->peer.st_port ) );
527 } else if ( memcmp ( &tftp->peer, st_src,
528 sizeof ( tftp->peer ) ) != 0 ) {
529 DBGC ( tftp, "TFTP %p received packet from wrong source (got "
530 "%d, wanted %d)\n", tftp, ntohs ( st_src->st_port ),
531 ntohs ( tftp->peer.st_port ) );
535 switch ( common->opcode ) {
536 case htons ( TFTP_OACK ):
537 rc = tftp_rx_oack ( tftp, iobuf->data, len );
539 case htons ( TFTP_DATA ):
540 rc = tftp_rx_data ( tftp, iobuf );
543 case htons ( TFTP_ERROR ):
544 rc = tftp_rx_error ( tftp, iobuf->data, len );
547 DBGC ( tftp, "TFTP %p received strange packet type %d\n",
548 tftp, ntohs ( common->opcode ) );
558 * TFTP connection closed by network stack
560 * @v socket Transport layer interface
561 * @v rc Reason for close
563 static void tftp_socket_close ( struct xfer_interface *socket, int rc ) {
564 struct tftp_request *tftp =
565 container_of ( socket, struct tftp_request, socket );
567 DBGC ( tftp, "TFTP %p socket closed: %s\n",
568 tftp, strerror ( rc ) );
570 tftp_done ( tftp, rc );
573 /** TFTP socket operations */
574 static struct xfer_interface_operations tftp_socket_operations = {
575 .close = tftp_socket_close,
576 .vredirect = xfer_vopen,
577 .request = ignore_xfer_request,
578 .seek = ignore_xfer_seek,
579 .alloc_iob = default_xfer_alloc_iob,
580 .deliver_iob = tftp_socket_deliver_iob,
581 .deliver_raw = xfer_deliver_as_iob,
585 * Close TFTP data transfer interface
587 * @v xfer Data transfer interface
588 * @v rc Reason for close
590 static void tftp_xfer_close ( struct xfer_interface *xfer, int rc ) {
591 struct tftp_request *tftp =
592 container_of ( xfer, struct tftp_request, xfer );
594 DBGC ( tftp, "TFTP %p interface closed: %s\n",
595 tftp, strerror ( rc ) );
597 tftp_done ( tftp, rc );
600 /** TFTP data transfer interface operations */
601 static struct xfer_interface_operations tftp_xfer_operations = {
602 .close = tftp_xfer_close,
603 .vredirect = ignore_xfer_vredirect,
604 .request = ignore_xfer_request,
605 .seek = ignore_xfer_seek,
606 .alloc_iob = default_xfer_alloc_iob,
607 .deliver_iob = xfer_deliver_as_raw,
608 .deliver_raw = ignore_xfer_deliver_raw,
612 * Initiate TFTP download
614 * @v xfer Data transfer interface
615 * @v uri Uniform Resource Identifier
616 * @ret rc Return status code
618 int tftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
619 struct tftp_request *tftp;
620 struct sockaddr_tcpip server;
629 /* Allocate and populate TFTP structure */
630 tftp = malloc ( sizeof ( *tftp ) );
633 memset ( tftp, 0, sizeof ( *tftp ) );
634 tftp->refcnt.free = tftp_free;
635 xfer_init ( &tftp->xfer, &tftp_xfer_operations, &tftp->refcnt );
636 tftp->uri = uri_get ( uri );
637 xfer_init ( &tftp->socket, &tftp_socket_operations, &tftp->refcnt );
639 tftp->timer.expired = tftp_timer_expired;
642 memset ( &server, 0, sizeof ( server ) );
643 server.st_port = htons ( uri_port ( tftp->uri, TFTP_PORT ) );
644 if ( ( rc = xfer_open_named_socket ( &tftp->socket, SOCK_DGRAM,
645 ( struct sockaddr * ) &server,
646 uri->host, NULL ) ) != 0 )
649 /* Start timer to initiate RRQ */
650 start_timer ( &tftp->timer );
652 /* Attach to parent interface, mortalise self, and return */
653 xfer_plug_plug ( &tftp->xfer, xfer );
654 ref_put ( &tftp->refcnt );
658 DBGC ( tftp, "TFTP %p could not create request: %s\n",
659 tftp, strerror ( rc ) );
660 tftp_done ( tftp, rc );
661 ref_put ( &tftp->refcnt );
665 /** TFTP URI opener */
666 struct uri_opener tftp_uri_opener __uri_opener = {