Add RFC2090 TFTP multicast support.
[people/sha0/gpxe.git] / src / net / udp / tftp.c
1 /*
2  * Copyright (C) 2006 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 <stdio.h>
22 #include <string.h>
23 #include <strings.h>
24 #include <byteswap.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include <gpxe/refcnt.h>
28 #include <gpxe/xfer.h>
29 #include <gpxe/open.h>
30 #include <gpxe/uri.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>
36
37 /** @file
38  *
39  * TFTP protocol
40  *
41  */
42
43 FEATURE ( FEATURE_PROTOCOL, "TFTP", DHCP_EB_FEATURE_TFTP, 1 );
44
45 /**
46  * A TFTP request
47  *
48  * This data structure holds the state for an ongoing TFTP transfer.
49  */
50 struct tftp_request {
51         /** Reference count */
52         struct refcnt refcnt;
53         /** Data transfer interface */
54         struct xfer_interface xfer;
55
56         /** URI being fetched */
57         struct uri *uri;
58         /** Transport layer interface */
59         struct xfer_interface socket;
60         /** Multicast transport layer interface */
61         struct xfer_interface mc_socket;
62
63         /** Data block size
64          *
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).
68          */
69         unsigned int blksize;
70         /** File size
71          *
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.
75          */
76         unsigned long tsize;
77         /** Multicast address
78          *
79          * This is the destination address for multicast data
80          * transmissions.
81          */
82         struct sockaddr_tcpip multicast;
83         /** Master client
84          *
85          * True if this is the client responsible for sending ACKs.
86          */
87         int master;
88         
89         /** Peer address
90          *
91          * The peer address is determined by the first response
92          * received to the TFTP RRQ.
93          */
94         struct sockaddr_tcpip peer;
95         /** Block bitmap */
96         struct bitmap bitmap;
97         /** Maximum known length
98          *
99          * We don't always know the file length in advance.  In
100          * particular, if the TFTP server doesn't support the tsize
101          * option, or we are using MTFTP, then we don't know the file
102          * length until we see the end-of-file block (which, in the
103          * case of MTFTP, may not be the last block we see).
104          *
105          * This value is updated whenever we obtain information about
106          * the file length.
107          */
108         size_t filesize;
109         /** Retransmission timer */
110         struct retry_timer timer;
111 };
112
113 /**
114  * Free TFTP request
115  *
116  * @v refcnt            Reference counter
117  */
118 static void tftp_free ( struct refcnt *refcnt ) {
119         struct tftp_request *tftp =
120                 container_of ( refcnt, struct tftp_request, refcnt );
121
122         uri_put ( tftp->uri );
123         bitmap_free ( &tftp->bitmap );
124         free ( tftp );
125 }
126
127 /**
128  * Mark TFTP request as complete
129  *
130  * @v tftp              TFTP connection
131  * @v rc                Return status code
132  */
133 static void tftp_done ( struct tftp_request *tftp, int rc ) {
134
135         DBGC ( tftp, "TFTP %p finished with status %d (%s)\n",
136                tftp, rc, strerror ( rc ) );
137
138         /* Stop the retry timer */
139         stop_timer ( &tftp->timer );
140
141         /* Close all data transfer interfaces */
142         xfer_nullify ( &tftp->socket );
143         xfer_close ( &tftp->socket, rc );
144         xfer_nullify ( &tftp->mc_socket );
145         xfer_close ( &tftp->mc_socket, rc );
146         xfer_nullify ( &tftp->xfer );
147         xfer_close ( &tftp->xfer, rc );
148 }
149
150 /**
151  * Presize TFTP receive buffers and block bitmap
152  *
153  * @v tftp              TFTP connection
154  * @v filesize          Known minimum file size
155  * @ret rc              Return status code
156  */
157 static int tftp_presize ( struct tftp_request *tftp, size_t filesize ) {
158         unsigned int num_blocks;
159         int rc;
160
161         /* Do nothing if we are already large enough */
162         if ( filesize <= tftp->filesize )
163                 return 0;
164
165         /* Record filesize */
166         tftp->filesize = filesize;
167
168         /* Notify recipient of file size */
169         xfer_seek ( &tftp->xfer, filesize, SEEK_SET );
170         xfer_seek ( &tftp->xfer, 0, SEEK_SET );
171
172         /* Calculate expected number of blocks.  Note that files whose
173          * length is an exact multiple of the blocksize will have a
174          * trailing zero-length block, which must be included.
175          */
176         num_blocks = ( ( filesize / tftp->blksize ) + 1 );
177         if ( ( rc = bitmap_resize ( &tftp->bitmap, num_blocks ) ) != 0 ) {
178                 DBGC ( tftp, "TFTP %p could not resize bitmap to %d blocks: "
179                        "%s\n", tftp, num_blocks, strerror ( rc ) );
180                 return rc;
181         }
182
183         return 0;
184 }
185
186 /**
187  * TFTP requested blocksize
188  *
189  * This is treated as a global configuration parameter.
190  */
191 static unsigned int tftp_request_blksize = TFTP_MAX_BLKSIZE;
192
193 /**
194  * Set TFTP request blocksize
195  *
196  * @v blksize           Requested block size
197  */
198 void tftp_set_request_blksize ( unsigned int blksize ) {
199         if ( blksize < TFTP_DEFAULT_BLKSIZE )
200                 blksize = TFTP_DEFAULT_BLKSIZE;
201         tftp_request_blksize = blksize;
202 }
203
204 /**
205  * Transmit RRQ
206  *
207  * @v tftp              TFTP connection
208  * @ret rc              Return status code
209  */
210 static int tftp_send_rrq ( struct tftp_request *tftp ) {
211         struct tftp_rrq *rrq;
212         const char *path = tftp->uri->path;
213         size_t len = ( sizeof ( *rrq ) + strlen ( path ) + 1 /* NUL */
214                        + 5 + 1 /* "octet" + NUL */
215                        + 7 + 1 + 5 + 1 /* "blksize" + NUL + ddddd + NUL */
216                        + 5 + 1 + 1 + 1 /* "tsize" + NUL + "0" + NUL */ 
217                        + 9 + 1 + 1 /* "multicast" + NUL + NUL */ );
218         struct io_buffer *iobuf;
219
220         DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, path );
221
222         /* Allocate buffer */
223         iobuf = xfer_alloc_iob ( &tftp->socket, len );
224         if ( ! iobuf )
225                 return -ENOMEM;
226
227         /* Build request */
228         rrq = iob_put ( iobuf, sizeof ( *rrq ) );
229         rrq->opcode = htons ( TFTP_RRQ );
230         iob_put ( iobuf,
231                   snprintf ( rrq->data, iob_tailroom ( iobuf ),
232                              "%s%coctet%cblksize%c%d%ctsize%c0%cmulticast%c",
233                              path, 0, 0, 0, tftp_request_blksize, 0,
234                              0, 0, 0 ) + 1 );
235
236         /* RRQ always goes to the address specified in the initial
237          * xfer_open() call
238          */
239         return xfer_deliver_iob ( &tftp->socket, iobuf );
240 }
241
242 /**
243  * Transmit ACK
244  *
245  * @v tftp              TFTP connection
246  * @ret rc              Return status code
247  */
248 static int tftp_send_ack ( struct tftp_request *tftp ) {
249         struct tftp_ack *ack;
250         struct io_buffer *iobuf;
251         struct xfer_metadata meta = {
252                 .dest = ( struct sockaddr * ) &tftp->peer,
253         };
254         unsigned int block;
255
256         /* Determine next required block number */
257         block = bitmap_first_gap ( &tftp->bitmap );
258         DBGC2 ( tftp, "TFTP %p sending ACK for block %d\n", tftp, block );
259
260         /* Allocate buffer */
261         iobuf = xfer_alloc_iob ( &tftp->socket, sizeof ( *ack ) );
262         if ( ! iobuf )
263                 return -ENOMEM;
264
265         /* Build ACK */
266         ack = iob_put ( iobuf, sizeof ( *ack ) );
267         ack->opcode = htons ( TFTP_ACK );
268         ack->block = htons ( block );
269
270         /* ACK always goes to the peer recorded from the RRQ response */
271         return xfer_deliver_iob_meta ( &tftp->socket, iobuf, &meta );
272 }
273
274 /**
275  * Transmit next relevant packet
276  *
277  * @v tftp              TFTP connection
278  * @ret rc              Return status code
279  */
280 static int tftp_send_packet ( struct tftp_request *tftp ) {
281
282         /* Update retransmission timer */
283         stop_timer ( &tftp->timer );
284         start_timer ( &tftp->timer );
285
286         /* If we are the master client, send RRQ or ACK as appropriate */
287         if ( tftp->master ) {
288                 if ( ! tftp->peer.st_family ) {
289                         return tftp_send_rrq ( tftp );
290                 } else {
291                         return tftp_send_ack ( tftp );
292                 }
293         } else {
294                 /* Do nothing when not the master client */
295                 return 0;
296         }
297 }
298
299 /**
300  * Handle TFTP retransmission timer expiry
301  *
302  * @v timer             Retry timer
303  * @v fail              Failure indicator
304  */
305 static void tftp_timer_expired ( struct retry_timer *timer, int fail ) {
306         struct tftp_request *tftp =
307                 container_of ( timer, struct tftp_request, timer );
308
309         if ( fail ) {
310                 tftp_done ( tftp, -ETIMEDOUT );
311         } else {
312                 tftp_send_packet ( tftp );
313         }
314 }
315
316 /**
317  * Process TFTP "blksize" option
318  *
319  * @v tftp              TFTP connection
320  * @v value             Option value
321  * @ret rc              Return status code
322  */
323 static int tftp_process_blksize ( struct tftp_request *tftp,
324                                   const char *value ) {
325         char *end;
326
327         tftp->blksize = strtoul ( value, &end, 10 );
328         if ( *end ) {
329                 DBGC ( tftp, "TFTP %p got invalid blksize \"%s\"\n",
330                        tftp, value );
331                 return -EINVAL;
332         }
333         DBGC ( tftp, "TFTP %p blksize=%d\n", tftp, tftp->blksize );
334
335         return 0;
336 }
337
338 /**
339  * Process TFTP "tsize" option
340  *
341  * @v tftp              TFTP connection
342  * @v value             Option value
343  * @ret rc              Return status code
344  */
345 static int tftp_process_tsize ( struct tftp_request *tftp,
346                                 const char *value ) {
347         char *end;
348
349         tftp->tsize = strtoul ( value, &end, 10 );
350         if ( *end ) {
351                 DBGC ( tftp, "TFTP %p got invalid tsize \"%s\"\n",
352                        tftp, value );
353                 return -EINVAL;
354         }
355         DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
356
357         return 0;
358 }
359
360 /**
361  * Process TFTP "multicast" option
362  *
363  * @v tftp              TFTP connection
364  * @v value             Option value
365  * @ret rc              Return status code
366  */
367 static int tftp_process_multicast ( struct tftp_request *tftp,
368                                     const char *value ) {
369         struct sockaddr_in *sin = ( struct sockaddr_in * ) &tftp->multicast;
370         char buf[ strlen ( value ) + 1 ];
371         char *addr;
372         char *port;
373         char *port_end;
374         char *mc;
375         char *mc_end;
376         struct sockaddr *mc_peer;
377         struct sockaddr *mc_local;
378         int rc;
379
380         /* Split value into "addr,port,mc" fields */
381         memcpy ( buf, value, sizeof ( buf ) );
382         addr = buf;
383         port = strchr ( addr, ',' );
384         if ( ! port ) {
385                 DBGC ( tftp, "TFTP %p multicast missing port,mc\n", tftp );
386                 return -EINVAL;
387         }
388         *(port++) = '\0';
389         mc = strchr ( port, ',' );
390         if ( ! mc ) {
391                 DBGC ( tftp, "TFTP %p multicast missing mc\n", tftp );
392                 return -EINVAL;
393         }
394         *(mc++) = '\0';
395
396         /* Parse parameters */
397         if ( *addr ) {
398                 if ( inet_aton ( addr, &sin->sin_addr ) == 0 ) {
399                         DBGC ( tftp, "TFTP %p multicast invalid IP address "
400                                "%s\n", tftp, addr );
401                         return -EINVAL;
402                 }
403                 DBGC ( tftp, "TFTP %p multicast IP address %s\n",
404                        tftp, inet_ntoa ( sin->sin_addr ) );
405         }
406         if ( *port ) {
407                 sin->sin_port = htons ( strtoul ( port, &port_end, 0 ) );
408                 if ( *port_end ) {
409                         DBGC ( tftp, "TFTP %p multicast invalid port %s\n",
410                                tftp, port );
411                         return -EINVAL;
412                 }
413                 DBGC ( tftp, "TFTP %p multicast port %d\n",
414                        tftp, ntohs ( sin->sin_port ) );
415         }
416         tftp->master = strtoul ( mc, &mc_end, 0 );
417         if ( *mc_end ) {
418                 DBGC ( tftp, "TFTP %p multicast invalid mc %s\n", tftp, mc );
419                 return -EINVAL;
420         }
421         DBGC ( tftp, "TFTP %p is%s the master client\n",
422                tftp, ( tftp->master ? "" : " not" ) );
423
424         /* Open multicast socket, if new address specified */
425         if ( *addr || *port ) {
426                 xfer_close ( &tftp->mc_socket, 0 );
427                 mc_peer = ( ( struct sockaddr * ) &tftp->peer );
428                 mc_local = ( ( struct sockaddr * ) &tftp->multicast );
429                 mc_local->sa_family = mc_peer->sa_family;
430                 if ( ( rc = xfer_open_socket ( &tftp->mc_socket, SOCK_DGRAM,
431                                                mc_peer, mc_local ) ) != 0 ) {
432                         DBGC ( tftp, "TFTP %p could not open multicast "
433                                "socket: %s\n", tftp, strerror ( rc ) );
434                         return rc;
435                 }
436         }
437
438         return 0;
439 }
440
441 /** A TFTP option */
442 struct tftp_option {
443         /** Option name */
444         const char *name;
445         /** Option processor
446          *
447          * @v tftp      TFTP connection
448          * @v value     Option value
449          * @ret rc      Return status code
450          */
451         int ( * process ) ( struct tftp_request *tftp, const char *value );
452 };
453
454 /** Recognised TFTP options */
455 static struct tftp_option tftp_options[] = {
456         { "blksize", tftp_process_blksize },
457         { "tsize", tftp_process_tsize },
458         { "multicast", tftp_process_multicast },
459         { NULL, NULL }
460 };
461
462 /**
463  * Process TFTP option
464  *
465  * @v tftp              TFTP connection
466  * @v name              Option name
467  * @v value             Option value
468  * @ret rc              Return status code
469  */
470 static int tftp_process_option ( struct tftp_request *tftp,
471                                  const char *name, const char *value ) {
472         struct tftp_option *option;
473
474         for ( option = tftp_options ; option->name ; option++ ) {
475                 if ( strcasecmp ( name, option->name ) == 0 )
476                         return option->process ( tftp, value );
477         }
478
479         DBGC ( tftp, "TFTP %p received unknown option \"%s\" = \"%s\"\n",
480                tftp, name, value );
481
482         /* Unknown options should be silently ignored */
483         return 0;
484 }
485
486 /**
487  * Receive OACK
488  *
489  * @v tftp              TFTP connection
490  * @v buf               Temporary data buffer
491  * @v len               Length of temporary data buffer
492  * @ret rc              Return status code
493  */
494 static int tftp_rx_oack ( struct tftp_request *tftp, void *buf, size_t len ) {
495         struct tftp_oack *oack = buf;
496         char *end = buf + len;
497         char *name;
498         char *value;
499         int rc;
500
501         /* Sanity check */
502         if ( len < sizeof ( *oack ) ) {
503                 DBGC ( tftp, "TFTP %p received underlength OACK packet "
504                        "length %d\n", tftp, len );
505                 rc = -EINVAL;
506                 goto done;
507         }
508         if ( end[-1] != '\0' ) {
509                 DBGC ( tftp, "TFTP %p received OACK missing final NUL\n",
510                        tftp );
511                 rc = -EINVAL;
512                 goto done;
513         }
514
515         /* Process each option in turn */
516         name = oack->data;
517         while ( name < end ) {
518                 value = ( name + strlen ( name ) + 1 );
519                 if ( value == end ) {
520                         DBGC ( tftp, "TFTP %p received OACK missing value "
521                                "for option \"%s\"\n", tftp, name );
522                         rc = -EINVAL;
523                         goto done;
524                 }
525                 if ( ( rc = tftp_process_option ( tftp, name, value ) ) != 0 )
526                         goto done;
527                 name = ( value + strlen ( value ) + 1 );
528         }
529
530         /* Process tsize information, if available */
531         if ( tftp->tsize ) {
532                 if ( ( rc = tftp_presize ( tftp, tftp->tsize ) ) != 0 )
533                         goto done;
534         }
535
536         /* Request next data block */
537         tftp_send_packet ( tftp );
538
539  done:
540         if ( rc )
541                 tftp_done ( tftp, rc );
542         return rc;
543 }
544
545 /**
546  * Receive DATA
547  *
548  * @v tftp              TFTP connection
549  * @v iobuf             I/O buffer
550  * @ret rc              Return status code
551  *
552  * Takes ownership of I/O buffer.
553  */
554 static int tftp_rx_data ( struct tftp_request *tftp,
555                           struct io_buffer *iobuf ) {
556         struct tftp_data *data = iobuf->data;
557         int block;
558         off_t offset;
559         size_t data_len;
560         int rc;
561
562         /* Sanity check */
563         if ( iob_len ( iobuf ) < sizeof ( *data ) ) {
564                 DBGC ( tftp, "TFTP %p received underlength DATA packet "
565                        "length %d\n", tftp, iob_len ( iobuf ) );
566                 rc = -EINVAL;
567                 goto done;
568         }
569
570         /* Extract data */
571         block = ( ntohs ( data->block ) - 1 );
572         offset = ( block * tftp->blksize );
573         iob_pull ( iobuf, sizeof ( *data ) );
574         data_len = iob_len ( iobuf );
575         if ( data_len > tftp->blksize ) {
576                 DBGC ( tftp, "TFTP %p received overlength DATA packet "
577                        "length %d\n", tftp, data_len );
578                 rc = -EINVAL;
579                 goto done;
580         }
581
582         /* Deliver data */
583         xfer_seek ( &tftp->xfer, offset, SEEK_SET );
584         rc = xfer_deliver_iob ( &tftp->xfer, iobuf );
585         iobuf = NULL;
586         if ( rc != 0 ) {
587                 DBGC ( tftp, "TFTP %p could not deliver data: %s\n",
588                        tftp, strerror ( rc ) );
589                 goto done;
590         }
591
592         /* Ensure block bitmap is ready */
593         if ( ( rc = tftp_presize ( tftp, ( offset + data_len ) ) ) != 0 )
594                 goto done;
595
596         /* Mark block as received */
597         bitmap_set ( &tftp->bitmap, block );
598
599         /* Acknowledge block */
600         tftp_send_packet ( tftp );
601
602         /* If all blocks have been received, finish. */
603         if ( bitmap_full ( &tftp->bitmap ) )
604                 tftp_done ( tftp, 0 );
605
606  done:
607         free_iob ( iobuf );
608         if ( rc )
609                 tftp_done ( tftp, rc );
610         return rc;
611 }
612
613 /** Translation between TFTP errors and internal error numbers */
614 static const uint8_t tftp_errors[] = {
615         [TFTP_ERR_FILE_NOT_FOUND]       = PXENV_STATUS_TFTP_FILE_NOT_FOUND,
616         [TFTP_ERR_ACCESS_DENIED]        = PXENV_STATUS_TFTP_ACCESS_VIOLATION,
617         [TFTP_ERR_ILLEGAL_OP]           = PXENV_STATUS_TFTP_UNKNOWN_OPCODE,
618 };
619
620 /**
621  * Receive ERROR
622  *
623  * @v tftp              TFTP connection
624  * @v buf               Temporary data buffer
625  * @v len               Length of temporary data buffer
626  * @ret rc              Return status code
627  */
628 static int tftp_rx_error ( struct tftp_request *tftp, void *buf, size_t len ) {
629         struct tftp_error *error = buf;
630         unsigned int err;
631         int rc = 0;
632
633         /* Sanity check */
634         if ( len < sizeof ( *error ) ) {
635                 DBGC ( tftp, "TFTP %p received underlength ERROR packet "
636                        "length %d\n", tftp, len );
637                 return -EINVAL;
638         }
639
640         DBGC ( tftp, "TFTP %p received ERROR packet with code %d, message "
641                "\"%s\"\n", tftp, ntohs ( error->errcode ), error->errmsg );
642         
643         /* Determine final operation result */
644         err = ntohs ( error->errcode );
645         if ( err < ( sizeof ( tftp_errors ) / sizeof ( tftp_errors[0] ) ) )
646                 rc = -tftp_errors[err];
647         if ( ! rc )
648                 rc = -PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION;
649
650         /* Close TFTP request */
651         tftp_done ( tftp, rc );
652
653         return 0;
654 }
655
656 /**
657  * Receive new data
658  *
659  * @v tftp              TFTP connection
660  * @v iobuf             I/O buffer
661  * @v meta              Transfer metadata, or NULL
662  * @ret rc              Return status code
663  */
664 static int tftp_rx ( struct tftp_request *tftp,
665                      struct io_buffer *iobuf,
666                      struct xfer_metadata *meta ) {
667         struct sockaddr_tcpip *st_src;
668         struct tftp_common *common = iobuf->data;
669         size_t len = iob_len ( iobuf );
670         int rc = -EINVAL;
671         
672         /* Sanity checks */
673         if ( len < sizeof ( *common ) ) {
674                 DBGC ( tftp, "TFTP %p received underlength packet length %d\n",
675                        tftp, len );
676                 goto done;
677         }
678         if ( ! meta ) {
679                 DBGC ( tftp, "TFTP %p received packet without metadata\n",
680                        tftp );
681                 goto done;
682         }
683         if ( ! meta->src ) {
684                 DBGC ( tftp, "TFTP %p received packet without source port\n",
685                        tftp );
686                 goto done;
687         }
688
689         /* Filter by TID.  Set TID on first response received */
690         st_src = ( struct sockaddr_tcpip * ) meta->src;
691         if ( ! tftp->peer.st_family ) {
692                 memcpy ( &tftp->peer, st_src, sizeof ( tftp->peer ) );
693                 DBGC ( tftp, "TFTP %p using remote port %d\n", tftp,
694                        ntohs ( tftp->peer.st_port ) );
695         } else if ( memcmp ( &tftp->peer, st_src,
696                              sizeof ( tftp->peer ) ) != 0 ) {
697                 DBGC ( tftp, "TFTP %p received packet from wrong source (got "
698                        "%d, wanted %d)\n", tftp, ntohs ( st_src->st_port ),
699                        ntohs ( tftp->peer.st_port ) );
700                 goto done;
701         }
702
703         switch ( common->opcode ) {
704         case htons ( TFTP_OACK ):
705                 rc = tftp_rx_oack ( tftp, iobuf->data, len );
706                 break;
707         case htons ( TFTP_DATA ):
708                 rc = tftp_rx_data ( tftp, iobuf );
709                 iobuf = NULL;
710                 break;
711         case htons ( TFTP_ERROR ):
712                 rc = tftp_rx_error ( tftp, iobuf->data, len );
713                 break;
714         default:
715                 DBGC ( tftp, "TFTP %p received strange packet type %d\n",
716                        tftp, ntohs ( common->opcode ) );
717                 break;
718         };
719
720  done:
721         free_iob ( iobuf );
722         return rc;
723 }
724
725 /**
726  * Receive new data via socket
727  *
728  * @v socket            Transport layer interface
729  * @v iobuf             I/O buffer
730  * @v meta              Transfer metadata, or NULL
731  * @ret rc              Return status code
732  */
733 static int tftp_socket_deliver_iob ( struct xfer_interface *socket,
734                                      struct io_buffer *iobuf,
735                                      struct xfer_metadata *meta ) {
736         struct tftp_request *tftp =
737                 container_of ( socket, struct tftp_request, socket );
738
739         return tftp_rx ( tftp, iobuf, meta );
740 }
741
742 /**
743  * TFTP connection closed by network stack
744  *
745  * @v socket            Transport layer interface
746  * @v rc                Reason for close
747  */
748 static void tftp_socket_close ( struct xfer_interface *socket, int rc ) {
749         struct tftp_request *tftp =
750                 container_of ( socket, struct tftp_request, socket );
751
752         DBGC ( tftp, "TFTP %p socket closed: %s\n",
753                tftp, strerror ( rc ) );
754
755         /* Any close counts as an error */
756         if ( ! rc )
757                 rc = -ECONNRESET;
758
759         tftp_done ( tftp, rc );
760 }
761
762 /** TFTP socket operations */
763 static struct xfer_interface_operations tftp_socket_operations = {
764         .close          = tftp_socket_close,
765         .vredirect      = xfer_vopen,
766         .seek           = ignore_xfer_seek,
767         .window         = unlimited_xfer_window,
768         .alloc_iob      = default_xfer_alloc_iob,
769         .deliver_iob    = tftp_socket_deliver_iob,
770         .deliver_raw    = xfer_deliver_as_iob,
771 };
772
773 /**
774  * Receive new data via multicast socket
775  *
776  * @v mc_socket         Multicast transport layer interface
777  * @v iobuf             I/O buffer
778  * @v meta              Transfer metadata, or NULL
779  * @ret rc              Return status code
780  */
781 static int tftp_mc_socket_deliver_iob ( struct xfer_interface *mc_socket,
782                                         struct io_buffer *iobuf,
783                                         struct xfer_metadata *meta ) {
784         struct tftp_request *tftp =
785                 container_of ( mc_socket, struct tftp_request, mc_socket );
786
787         return tftp_rx ( tftp, iobuf, meta );
788 }
789
790 /**
791  * TFTP multicast connection closed by network stack
792  *
793  * @v socket            Multicast transport layer interface
794  * @v rc                Reason for close
795  */
796 static void tftp_mc_socket_close ( struct xfer_interface *mc_socket,
797                                    int rc ) {
798         struct tftp_request *tftp =
799                 container_of ( mc_socket, struct tftp_request, mc_socket );
800
801         DBGC ( tftp, "TFTP %p multicast socket closed: %s\n",
802                tftp, strerror ( rc ) );
803
804         /* The multicast socket may be closed when we receive a new
805          * OACK and open/reopen the socket; we should not call
806          * tftp_done() at this point.
807          */
808 }
809  
810 /** TFTP multicast socket operations */
811 static struct xfer_interface_operations tftp_mc_socket_operations = {
812         .close          = tftp_mc_socket_close,
813         .vredirect      = xfer_vopen,
814         .seek           = ignore_xfer_seek,
815         .window         = unlimited_xfer_window,
816         .alloc_iob      = default_xfer_alloc_iob,
817         .deliver_iob    = tftp_mc_socket_deliver_iob,
818         .deliver_raw    = xfer_deliver_as_iob,
819 };
820
821 /**
822  * Close TFTP data transfer interface
823  *
824  * @v xfer              Data transfer interface
825  * @v rc                Reason for close
826  */
827 static void tftp_xfer_close ( struct xfer_interface *xfer, int rc ) {
828         struct tftp_request *tftp =
829                 container_of ( xfer, struct tftp_request, xfer );
830
831         DBGC ( tftp, "TFTP %p interface closed: %s\n",
832                tftp, strerror ( rc ) );
833
834         tftp_done ( tftp, rc );
835 }
836
837 /** TFTP data transfer interface operations */
838 static struct xfer_interface_operations tftp_xfer_operations = {
839         .close          = tftp_xfer_close,
840         .vredirect      = ignore_xfer_vredirect,
841         .seek           = ignore_xfer_seek,
842         .window         = unlimited_xfer_window,
843         .alloc_iob      = default_xfer_alloc_iob,
844         .deliver_iob    = xfer_deliver_as_raw,
845         .deliver_raw    = ignore_xfer_deliver_raw,
846 };
847
848 /**
849  * Initiate TFTP download
850  *
851  * @v xfer              Data transfer interface
852  * @v uri               Uniform Resource Identifier
853  * @ret rc              Return status code
854  */
855 int tftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
856         struct tftp_request *tftp;
857         struct sockaddr_tcpip server;
858         int rc;
859
860         /* Sanity checks */
861         if ( ! uri->host )
862                 return -EINVAL;
863         if ( ! uri->path )
864                 return -EINVAL;
865
866         /* Allocate and populate TFTP structure */
867         tftp = zalloc ( sizeof ( *tftp ) );
868         if ( ! tftp )
869                 return -ENOMEM;
870         tftp->refcnt.free = tftp_free;
871         xfer_init ( &tftp->xfer, &tftp_xfer_operations, &tftp->refcnt );
872         tftp->uri = uri_get ( uri );
873         xfer_init ( &tftp->socket, &tftp_socket_operations, &tftp->refcnt );
874         xfer_init ( &tftp->mc_socket, &tftp_mc_socket_operations,
875                     &tftp->refcnt );
876         tftp->blksize = TFTP_DEFAULT_BLKSIZE;
877         tftp->master = 1;
878         tftp->timer.expired = tftp_timer_expired;
879
880         /* Open socket */
881         memset ( &server, 0, sizeof ( server ) );
882         server.st_port = htons ( uri_port ( tftp->uri, TFTP_PORT ) );
883         if ( ( rc = xfer_open_named_socket ( &tftp->socket, SOCK_DGRAM,
884                                              ( struct sockaddr * ) &server,
885                                              uri->host, NULL ) ) != 0 )
886                 goto err;
887
888         /* Start timer to initiate RRQ */
889         start_timer_nodelay ( &tftp->timer );
890
891         /* Attach to parent interface, mortalise self, and return */
892         xfer_plug_plug ( &tftp->xfer, xfer );
893         ref_put ( &tftp->refcnt );
894         return 0;
895
896  err:
897         DBGC ( tftp, "TFTP %p could not create request: %s\n",
898                tftp, strerror ( rc ) );
899         tftp_done ( tftp, rc );
900         ref_put ( &tftp->refcnt );
901         return rc;
902 }
903
904 /** TFTP URI opener */
905 struct uri_opener tftp_uri_opener __uri_opener = {
906         .scheme = "tftp",
907         .open   = tftp_open,
908 };