Kill off unused request() method in data-xfer interface.
[people/xl0/gpxe-arm.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/tftp.h>
34
35 /** @file
36  *
37  * TFTP protocol
38  *
39  */
40
41 /**
42  * A TFTP request
43  *
44  * This data structure holds the state for an ongoing TFTP transfer.
45  */
46 struct tftp_request {
47         /** Reference count */
48         struct refcnt refcnt;
49         /** Data transfer interface */
50         struct xfer_interface xfer;
51
52         /** URI being fetched */
53         struct uri *uri;
54         /** Transport layer interface */
55         struct xfer_interface socket;
56
57         /** Data block size
58          *
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).
62          */
63         unsigned int blksize;
64         /** File size
65          *
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.
69          */
70         unsigned long tsize;
71
72         /** Request state
73          *
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).
81          */
82         int state;
83         /** Peer address
84          *
85          * The peer address is determined by the first response
86          * received to the TFTP RRQ.
87          */
88         struct sockaddr_tcpip peer;
89         /** Retransmission timer */
90         struct retry_timer timer;
91 };
92
93 /**
94  * Free TFTP request
95  *
96  * @v refcnt            Reference counter
97  */
98 static void tftp_free ( struct refcnt *refcnt ) {
99         struct tftp_request *tftp =
100                 container_of ( refcnt, struct tftp_request, refcnt );
101
102         uri_put ( tftp->uri );
103         free ( tftp );
104 }
105
106 /**
107  * Mark TFTP request as complete
108  *
109  * @v tftp              TFTP connection
110  * @v rc                Return status code
111  */
112 static void tftp_done ( struct tftp_request *tftp, int rc ) {
113
114         DBGC ( tftp, "TFTP %p finished with status %d (%s)\n",
115                tftp, rc, strerror ( rc ) );
116
117         /* Stop the retry timer */
118         stop_timer ( &tftp->timer );
119
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 );
125 }
126
127 /**
128  * TFTP requested blocksize
129  *
130  * This is treated as a global configuration parameter.
131  */
132 static unsigned int tftp_request_blksize = TFTP_MAX_BLKSIZE;
133
134 /**
135  * Set TFTP request blocksize
136  *
137  * @v blksize           Requested block size
138  */
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;
143 }
144
145 /**
146  * Transmit RRQ
147  *
148  * @v tftp              TFTP connection
149  * @ret rc              Return status code
150  */
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;
159
160         DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, path );
161
162         /* Allocate buffer */
163         iobuf = xfer_alloc_iob ( &tftp->socket, len );
164         if ( ! iobuf )
165                 return -ENOMEM;
166
167         /* Build request */
168         rrq = iob_put ( iobuf, sizeof ( *rrq ) );
169         rrq->opcode = htons ( TFTP_RRQ );
170         iob_put ( iobuf,
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 );
174
175         /* RRQ always goes to the address specified in the initial
176          * xfer_open() call
177          */
178         return xfer_deliver_iob ( &tftp->socket, iobuf );
179 }
180
181 /**
182  * Transmit ACK
183  *
184  * @v tftp              TFTP connection
185  * @ret rc              Return status code
186  */
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,
192         };
193
194         DBGC2 ( tftp, "TFTP %p sending ACK for block %d\n",
195                 tftp, tftp->state );
196
197         /* Allocate buffer */
198         iobuf = xfer_alloc_iob ( &tftp->socket, sizeof ( *ack ) );
199         if ( ! iobuf )
200                 return -ENOMEM;
201
202         /* Build ACK */
203         ack = iob_put ( iobuf, sizeof ( *ack ) );
204         ack->opcode = htons ( TFTP_ACK );
205         ack->block = htons ( tftp->state );
206
207         /* ACK always goes to the peer recorded from the RRQ response */
208         return xfer_deliver_iob_meta ( &tftp->socket, iobuf, &meta );
209 }
210
211 /**
212  * Transmit data
213  *
214  * @v tftp              TFTP connection
215  * @ret rc              Return status code
216  */
217 static int tftp_send_packet ( struct tftp_request *tftp ) {
218
219         /* Start retransmission timer */
220         start_timer ( &tftp->timer );
221
222         /* Send RRQ or ACK as appropriate */
223         if ( tftp->state < 0 ) {
224                 return tftp_send_rrq ( tftp );
225         } else {
226                 return tftp_send_ack ( tftp );
227         }
228 }
229
230 /**
231  * Handle TFTP retransmission timer expiry
232  *
233  * @v timer             Retry timer
234  * @v fail              Failure indicator
235  */
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 );
239
240         if ( fail ) {
241                 tftp_done ( tftp, -ETIMEDOUT );
242         } else {
243                 tftp_send_packet ( tftp );
244         }
245 }
246
247 /**
248  * Mark TFTP block as received
249  *
250  * @v tftp              TFTP connection
251  * @v block             Block number
252  */
253 static void tftp_received ( struct tftp_request *tftp, unsigned int block ) {
254
255         /* Stop the retry timer */
256         stop_timer ( &tftp->timer );
257
258         /* Update state to indicate which block we're now waiting for */
259         tftp->state = block;
260
261         /* Send next packet */
262         tftp_send_packet ( tftp );
263 }
264
265 /**
266  * Process TFTP "blksize" option
267  *
268  * @v tftp              TFTP connection
269  * @v value             Option value
270  * @ret rc              Return status code
271  */
272 static int tftp_process_blksize ( struct tftp_request *tftp,
273                                   const char *value ) {
274         char *end;
275
276         tftp->blksize = strtoul ( value, &end, 10 );
277         if ( *end ) {
278                 DBGC ( tftp, "TFTP %p got invalid blksize \"%s\"\n",
279                        tftp, value );
280                 return -EINVAL;
281         }
282         DBGC ( tftp, "TFTP %p blksize=%d\n", tftp, tftp->blksize );
283
284         return 0;
285 }
286
287 /**
288  * Process TFTP "tsize" option
289  *
290  * @v tftp              TFTP connection
291  * @v value             Option value
292  * @ret rc              Return status code
293  */
294 static int tftp_process_tsize ( struct tftp_request *tftp,
295                                 const char *value ) {
296         char *end;
297
298         tftp->tsize = strtoul ( value, &end, 10 );
299         if ( *end ) {
300                 DBGC ( tftp, "TFTP %p got invalid tsize \"%s\"\n",
301                        tftp, value );
302                 return -EINVAL;
303         }
304         DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
305
306         /* Notify recipient of file size */
307         xfer_seek ( &tftp->xfer, tftp->tsize, SEEK_SET );
308         xfer_seek ( &tftp->xfer, 0, SEEK_SET );
309
310         return 0;
311 }
312
313 /** A TFTP option */
314 struct tftp_option {
315         /** Option name */
316         const char *name;
317         /** Option processor
318          *
319          * @v tftp      TFTP connection
320          * @v value     Option value
321          * @ret rc      Return status code
322          */
323         int ( * process ) ( struct tftp_request *tftp, const char *value );
324 };
325
326 /** Recognised TFTP options */
327 static struct tftp_option tftp_options[] = {
328         { "blksize", tftp_process_blksize },
329         { "tsize", tftp_process_tsize },
330         { NULL, NULL }
331 };
332
333 /**
334  * Process TFTP option
335  *
336  * @v tftp              TFTP connection
337  * @v name              Option name
338  * @v value             Option value
339  * @ret rc              Return status code
340  */
341 static int tftp_process_option ( struct tftp_request *tftp,
342                                  const char *name, const char *value ) {
343         struct tftp_option *option;
344
345         for ( option = tftp_options ; option->name ; option++ ) {
346                 if ( strcasecmp ( name, option->name ) == 0 )
347                         return option->process ( tftp, value );
348         }
349
350         DBGC ( tftp, "TFTP %p received unknown option \"%s\" = \"%s\"\n",
351                tftp, name, value );
352
353         return -EINVAL;
354 }
355
356 /**
357  * Receive OACK
358  *
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
363  */
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;
367         char *name;
368         char *value;
369         int rc;
370
371         /* Sanity check */
372         if ( len < sizeof ( *oack ) ) {
373                 DBGC ( tftp, "TFTP %p received underlength OACK packet "
374                        "length %d\n", tftp, len );
375                 return -EINVAL;
376         }
377         if ( end[-1] != '\0' ) {
378                 DBGC ( tftp, "TFTP %p received OACK missing final NUL\n",
379                        tftp );
380                 return -EINVAL;
381         }
382
383         /* Process each option in turn */
384         name = oack->data;
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 );
390                         return -EINVAL;
391                 }
392                 if ( ( rc = tftp_process_option ( tftp, name, value ) ) != 0 )
393                         return rc;
394                 name = ( value + strlen ( value ) + 1 );
395         }
396
397         /* Mark as received block 0 (the OACK) */
398         tftp_received ( tftp, 0 );
399
400         return 0;
401 }
402
403 /**
404  * Receive DATA
405  *
406  * @v tftp              TFTP connection
407  * @v iobuf             I/O buffer
408  * @ret rc              Return status code
409  *
410  * Takes ownership of I/O buffer.
411  */
412 static int tftp_rx_data ( struct tftp_request *tftp,
413                           struct io_buffer *iobuf ) {
414         struct tftp_data *data = iobuf->data;
415         unsigned int block;
416         size_t data_len;
417         int rc;
418
419         /* Sanity check */
420         if ( iob_len ( iobuf ) < sizeof ( *data ) ) {
421                 DBGC ( tftp, "TFTP %p received underlength DATA packet "
422                        "length %d\n", tftp, iob_len ( iobuf ) );
423                 free_iob ( iobuf );
424                 return -EINVAL;
425         }
426
427         /* Extract data */
428         block = ntohs ( data->block );
429         iob_pull ( iobuf, sizeof ( *data ) );
430         data_len = iob_len ( iobuf );
431
432         /* Deliver data */
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 );
437                 return rc;
438         }
439
440         /* Mark block as received */
441         tftp_received ( tftp, block );
442
443         /* Finish when final block received */
444         if ( data_len < tftp->blksize )
445                 tftp_done ( tftp, 0 );
446
447         return 0;
448 }
449
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,
455 };
456
457 /**
458  * Receive ERROR
459  *
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
464  */
465 static int tftp_rx_error ( struct tftp_request *tftp, void *buf, size_t len ) {
466         struct tftp_error *error = buf;
467         unsigned int err;
468         int rc = 0;
469
470         /* Sanity check */
471         if ( len < sizeof ( *error ) ) {
472                 DBGC ( tftp, "TFTP %p received underlength ERROR packet "
473                        "length %d\n", tftp, len );
474                 return -EINVAL;
475         }
476
477         DBGC ( tftp, "TFTP %p received ERROR packet with code %d, message "
478                "\"%s\"\n", tftp, ntohs ( error->errcode ), error->errmsg );
479         
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];
484         if ( ! rc )
485                 rc = -PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION;
486
487         /* Close TFTP request */
488         tftp_done ( tftp, rc );
489
490         return 0;
491 }
492
493 /**
494  * Receive new data
495  *
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
501  */
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 );
510         int rc = -EINVAL;
511         
512         /* Sanity checks */
513         if ( len < sizeof ( *common ) ) {
514                 DBGC ( tftp, "TFTP %p received underlength packet length %d\n",
515                        tftp, len );
516                 goto done;
517         }
518         if ( ! meta ) {
519                 DBGC ( tftp, "TFTP %p received packet without metadata\n",
520                        tftp );
521                 goto done;
522         }
523         if ( ! meta->src ) {
524                 DBGC ( tftp, "TFTP %p received packet without source port\n",
525                        tftp );
526                 goto done;
527         }
528
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 ) );
540                 goto done;
541         }
542
543         switch ( common->opcode ) {
544         case htons ( TFTP_OACK ):
545                 rc = tftp_rx_oack ( tftp, iobuf->data, len );
546                 break;
547         case htons ( TFTP_DATA ):
548                 rc = tftp_rx_data ( tftp, iobuf );
549                 iobuf = NULL;
550                 break;
551         case htons ( TFTP_ERROR ):
552                 rc = tftp_rx_error ( tftp, iobuf->data, len );
553                 break;
554         default:
555                 DBGC ( tftp, "TFTP %p received strange packet type %d\n",
556                        tftp, ntohs ( common->opcode ) );
557                 break;
558         };
559
560  done:
561         free_iob ( iobuf );
562         return rc;
563 }
564
565 /**
566  * TFTP connection closed by network stack
567  *
568  * @v socket            Transport layer interface
569  * @v rc                Reason for close
570  */
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 );
574
575         DBGC ( tftp, "TFTP %p socket closed: %s\n",
576                tftp, strerror ( rc ) );
577
578         tftp_done ( tftp, rc );
579 }
580
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         .alloc_iob      = default_xfer_alloc_iob,
587         .deliver_iob    = tftp_socket_deliver_iob,
588         .deliver_raw    = xfer_deliver_as_iob,
589 };
590  
591 /**
592  * Close TFTP data transfer interface
593  *
594  * @v xfer              Data transfer interface
595  * @v rc                Reason for close
596  */
597 static void tftp_xfer_close ( struct xfer_interface *xfer, int rc ) {
598         struct tftp_request *tftp =
599                 container_of ( xfer, struct tftp_request, xfer );
600
601         DBGC ( tftp, "TFTP %p interface closed: %s\n",
602                tftp, strerror ( rc ) );
603
604         tftp_done ( tftp, rc );
605 }
606
607 /** TFTP data transfer interface operations */
608 static struct xfer_interface_operations tftp_xfer_operations = {
609         .close          = tftp_xfer_close,
610         .vredirect      = ignore_xfer_vredirect,
611         .seek           = ignore_xfer_seek,
612         .alloc_iob      = default_xfer_alloc_iob,
613         .deliver_iob    = xfer_deliver_as_raw,
614         .deliver_raw    = ignore_xfer_deliver_raw,
615 };
616
617 /**
618  * Initiate TFTP download
619  *
620  * @v xfer              Data transfer interface
621  * @v uri               Uniform Resource Identifier
622  * @ret rc              Return status code
623  */
624 int tftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
625         struct tftp_request *tftp;
626         struct sockaddr_tcpip server;
627         int rc;
628
629         /* Sanity checks */
630         if ( ! uri->host )
631                 return -EINVAL;
632         if ( ! uri->path )
633                 return -EINVAL;
634
635         /* Allocate and populate TFTP structure */
636         tftp = zalloc ( sizeof ( *tftp ) );
637         if ( ! tftp )
638                 return -ENOMEM;
639         tftp->refcnt.free = tftp_free;
640         xfer_init ( &tftp->xfer, &tftp_xfer_operations, &tftp->refcnt );
641         tftp->uri = uri_get ( uri );
642         xfer_init ( &tftp->socket, &tftp_socket_operations, &tftp->refcnt );
643         tftp->state = -1;
644         tftp->timer.expired = tftp_timer_expired;
645
646         /* Open socket */
647         memset ( &server, 0, sizeof ( server ) );
648         server.st_port = htons ( uri_port ( tftp->uri, TFTP_PORT ) );
649         if ( ( rc = xfer_open_named_socket ( &tftp->socket, SOCK_DGRAM,
650                                              ( struct sockaddr * ) &server,
651                                              uri->host, NULL ) ) != 0 )
652                 goto err;
653
654         /* Start timer to initiate RRQ */
655         start_timer ( &tftp->timer );
656
657         /* Attach to parent interface, mortalise self, and return */
658         xfer_plug_plug ( &tftp->xfer, xfer );
659         ref_put ( &tftp->refcnt );
660         return 0;
661
662  err:
663         DBGC ( tftp, "TFTP %p could not create request: %s\n",
664                tftp, strerror ( rc ) );
665         tftp_done ( tftp, rc );
666         ref_put ( &tftp->refcnt );
667         return rc;
668 }
669
670 /** TFTP URI opener */
671 struct uri_opener tftp_uri_opener __uri_opener = {
672         .scheme = "tftp",
673         .open   = tftp_open,
674 };