Bugfix: iobuf->data always points to the start of the allocated
[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         /* Stop the retry timer */
115         stop_timer ( &tftp->timer );
116
117         /* Close all data transfer interfaces */
118         xfer_nullify ( &tftp->socket );
119         xfer_close ( &tftp->socket, rc );
120         xfer_nullify ( &tftp->xfer );
121         xfer_close ( &tftp->xfer, rc );
122 }
123
124 /**
125  * TFTP requested blocksize
126  *
127  * This is treated as a global configuration parameter.
128  */
129 static unsigned int tftp_request_blksize = TFTP_MAX_BLKSIZE;
130
131 /**
132  * Set TFTP request blocksize
133  *
134  * @v blksize           Requested block size
135  */
136 void tftp_set_request_blksize ( unsigned int blksize ) {
137         if ( blksize < TFTP_DEFAULT_BLKSIZE )
138                 blksize = TFTP_DEFAULT_BLKSIZE;
139         tftp_request_blksize = blksize;
140 }
141
142 /**
143  * Transmit RRQ
144  *
145  * @v tftp              TFTP connection
146  * @ret rc              Return status code
147  */
148 static int tftp_send_rrq ( struct tftp_request *tftp ) {
149         struct tftp_rrq *rrq;
150         const char *path = tftp->uri->path;
151         size_t len = ( sizeof ( *rrq ) + strlen ( path ) + 1 /* NUL */
152                        + 5 + 1 /* "octet" + NUL */
153                        + 7 + 1 + 5 + 1 /* "blksize" + NUL + ddddd + NUL */
154                        + 5 + 1 + 1 + 1 /* "tsize" + NUL + "0" + NUL */ );
155         struct io_buffer *iobuf;
156
157         DBGC ( tftp, "TFTP %p requesting \"%s\"\n", tftp, path );
158
159         /* Allocate buffer */
160         iobuf = xfer_alloc_iob ( &tftp->socket, len );
161         if ( ! iobuf )
162                 return -ENOMEM;
163
164         /* Build request */
165         rrq = iob_put ( iobuf, sizeof ( *rrq ) );
166         rrq->opcode = htons ( TFTP_RRQ );
167         iob_put ( iobuf,
168                   snprintf ( rrq->data, iob_tailroom ( iobuf ),
169                              "%s%coctet%cblksize%c%d%ctsize%c0", path, 0,
170                              0, 0, tftp_request_blksize, 0, 0 ) + 1 );
171
172         /* RRQ always goes to the address specified in the initial
173          * xfer_open() call
174          */
175         return xfer_deliver_iob ( &tftp->socket, iobuf );
176 }
177
178 /**
179  * Transmit ACK
180  *
181  * @v tftp              TFTP connection
182  * @ret rc              Return status code
183  */
184 static int tftp_send_ack ( struct tftp_request *tftp ) {
185         struct tftp_ack *ack;
186         struct io_buffer *iobuf;
187         struct xfer_metadata meta = {
188                 .dest = ( struct sockaddr * ) &tftp->peer,
189         };
190
191         /* Allocate buffer */
192         iobuf = xfer_alloc_iob ( &tftp->socket, sizeof ( *ack ) );
193         if ( ! iobuf )
194                 return -ENOMEM;
195
196         /* Build ACK */
197         ack = iob_put ( iobuf, sizeof ( *ack ) );
198         ack->opcode = htons ( TFTP_ACK );
199         ack->block = htons ( tftp->state );
200
201         /* ACK always goes to the peer recorded from the RRQ response */
202         return xfer_deliver_iob_meta ( &tftp->socket, iobuf, &meta );
203 }
204
205 /**
206  * Transmit data
207  *
208  * @v tftp              TFTP connection
209  * @ret rc              Return status code
210  */
211 static int tftp_send_packet ( struct tftp_request *tftp ) {
212
213         /* Start retransmission timer */
214         start_timer ( &tftp->timer );
215
216         /* Send RRQ or ACK as appropriate */
217         if ( tftp->state < 0 ) {
218                 return tftp_send_rrq ( tftp );
219         } else {
220                 return tftp_send_ack ( tftp );
221         }
222 }
223
224 /**
225  * Handle TFTP retransmission timer expiry
226  *
227  * @v timer             Retry timer
228  * @v fail              Failure indicator
229  */
230 static void tftp_timer_expired ( struct retry_timer *timer, int fail ) {
231         struct tftp_request *tftp =
232                 container_of ( timer, struct tftp_request, timer );
233
234         if ( fail ) {
235                 tftp_done ( tftp, -ETIMEDOUT );
236         } else {
237                 tftp_send_packet ( tftp );
238         }
239 }
240
241 /**
242  * Mark TFTP block as received
243  *
244  * @v tftp              TFTP connection
245  * @v block             Block number
246  */
247 static void tftp_received ( struct tftp_request *tftp, unsigned int block ) {
248
249         /* Stop the retry timer */
250         stop_timer ( &tftp->timer );
251
252         /* Update state to indicate which block we're now waiting for */
253         tftp->state = block;
254
255         /* Send next packet */
256         tftp_send_packet ( tftp );
257 }
258
259 /**
260  * Process TFTP "blksize" option
261  *
262  * @v tftp              TFTP connection
263  * @v value             Option value
264  * @ret rc              Return status code
265  */
266 static int tftp_process_blksize ( struct tftp_request *tftp,
267                                   const char *value ) {
268         char *end;
269
270         tftp->blksize = strtoul ( value, &end, 10 );
271         if ( *end ) {
272                 DBGC ( tftp, "TFTP %p got invalid blksize \"%s\"\n",
273                        tftp, value );
274                 return -EINVAL;
275         }
276         DBGC ( tftp, "TFTP %p blksize=%d\n", tftp, tftp->blksize );
277
278         return 0;
279 }
280
281 /**
282  * Process TFTP "tsize" option
283  *
284  * @v tftp              TFTP connection
285  * @v value             Option value
286  * @ret rc              Return status code
287  */
288 static int tftp_process_tsize ( struct tftp_request *tftp,
289                                 const char *value ) {
290         char *end;
291
292         tftp->tsize = strtoul ( value, &end, 10 );
293         if ( *end ) {
294                 DBGC ( tftp, "TFTP %p got invalid tsize \"%s\"\n",
295                        tftp, value );
296                 return -EINVAL;
297         }
298         DBGC ( tftp, "TFTP %p tsize=%ld\n", tftp, tftp->tsize );
299
300         /* Notify recipient of file size */
301         xfer_seek ( &tftp->xfer, tftp->tsize, SEEK_SET );
302         xfer_seek ( &tftp->xfer, 0, SEEK_SET );
303
304         return 0;
305 }
306
307 /** A TFTP option */
308 struct tftp_option {
309         /** Option name */
310         const char *name;
311         /** Option processor
312          *
313          * @v tftp      TFTP connection
314          * @v value     Option value
315          * @ret rc      Return status code
316          */
317         int ( * process ) ( struct tftp_request *tftp, const char *value );
318 };
319
320 /** Recognised TFTP options */
321 static struct tftp_option tftp_options[] = {
322         { "blksize", tftp_process_blksize },
323         { "tsize", tftp_process_tsize },
324         { NULL, NULL }
325 };
326
327 /**
328  * Process TFTP option
329  *
330  * @v tftp              TFTP connection
331  * @v name              Option name
332  * @v value             Option value
333  * @ret rc              Return status code
334  */
335 static int tftp_process_option ( struct tftp_request *tftp,
336                                  const char *name, const char *value ) {
337         struct tftp_option *option;
338
339         for ( option = tftp_options ; option->name ; option++ ) {
340                 if ( strcasecmp ( name, option->name ) == 0 )
341                         return option->process ( tftp, value );
342         }
343
344         DBGC ( tftp, "TFTP %p received unknown option \"%s\" = \"%s\"\n",
345                tftp, name, value );
346
347         return -EINVAL;
348 }
349
350 /**
351  * Receive OACK
352  *
353  * @v tftp              TFTP connection
354  * @v buf               Temporary data buffer
355  * @v len               Length of temporary data buffer
356  * @ret rc              Return status code
357  */
358 static int tftp_rx_oack ( struct tftp_request *tftp, void *buf, size_t len ) {
359         struct tftp_oack *oack = buf;
360         char *end = buf + len;
361         char *name;
362         char *value;
363         int rc;
364
365         /* Sanity check */
366         if ( len < sizeof ( *oack ) ) {
367                 DBGC ( tftp, "TFTP %p received underlength OACK packet "
368                        "length %d\n", tftp, len );
369                 return -EINVAL;
370         }
371         if ( end[-1] != '\0' ) {
372                 DBGC ( tftp, "TFTP %p received OACK missing final NUL\n",
373                        tftp );
374                 return -EINVAL;
375         }
376
377         /* Process each option in turn */
378         name = oack->data;
379         while ( name < end ) {
380                 value = ( name + strlen ( name ) + 1 );
381                 if ( value == end ) {
382                         DBGC ( tftp, "TFTP %p received OACK missing value "
383                                "for option \"%s\"\n", tftp, name );
384                         return -EINVAL;
385                 }
386                 if ( ( rc = tftp_process_option ( tftp, name, value ) ) != 0 )
387                         return rc;
388                 name = ( value + strlen ( value ) + 1 );
389         }
390
391         /* Mark as received block 0 (the OACK) */
392         tftp_received ( tftp, 0 );
393
394         return 0;
395 }
396
397 /**
398  * Receive DATA
399  *
400  * @v tftp              TFTP connection
401  * @v iobuf             I/O buffer
402  * @ret rc              Return status code
403  *
404  * Takes ownership of I/O buffer.
405  */
406 static int tftp_rx_data ( struct tftp_request *tftp,
407                           struct io_buffer *iobuf ) {
408         struct tftp_data *data = iobuf->data;
409         unsigned int block;
410         size_t data_len;
411         int rc;
412
413         /* Sanity check */
414         if ( iob_len ( iobuf ) < sizeof ( *data ) ) {
415                 DBGC ( tftp, "TFTP %p received underlength DATA packet "
416                        "length %d\n", tftp, iob_len ( iobuf ) );
417                 free_iob ( iobuf );
418                 return -EINVAL;
419         }
420
421         /* Extract data */
422         block = ntohs ( data->block );
423         iob_pull ( iobuf, sizeof ( *data ) );
424         data_len = iob_len ( iobuf );
425
426         /* Deliver data */
427         if ( ( rc = xfer_deliver_iob ( &tftp->xfer, iobuf ) ) != 0 ) {
428                 DBGC ( tftp, "TFTP %p could not deliver data: %s\n",
429                        tftp, strerror ( rc ) );
430                 tftp_done ( tftp, rc );
431                 return rc;
432         }
433
434         /* Mark block as received */
435         tftp_received ( tftp, block );
436
437         /* Finish when final block received */
438         if ( data_len < tftp->blksize )
439                 tftp_done ( tftp, 0 );
440
441         return 0;
442 }
443
444 /** Translation between TFTP errors and internal error numbers */
445 static const uint8_t tftp_errors[] = {
446         [TFTP_ERR_FILE_NOT_FOUND]       = PXENV_STATUS_TFTP_FILE_NOT_FOUND,
447         [TFTP_ERR_ACCESS_DENIED]        = PXENV_STATUS_TFTP_ACCESS_VIOLATION,
448         [TFTP_ERR_ILLEGAL_OP]           = PXENV_STATUS_TFTP_UNKNOWN_OPCODE,
449 };
450
451 /**
452  * Receive ERROR
453  *
454  * @v tftp              TFTP connection
455  * @v buf               Temporary data buffer
456  * @v len               Length of temporary data buffer
457  * @ret rc              Return status code
458  */
459 static int tftp_rx_error ( struct tftp_request *tftp, void *buf, size_t len ) {
460         struct tftp_error *error = buf;
461         unsigned int err;
462         int rc = 0;
463
464         /* Sanity check */
465         if ( len < sizeof ( *error ) ) {
466                 DBGC ( tftp, "TFTP %p received underlength ERROR packet "
467                        "length %d\n", tftp, len );
468                 return -EINVAL;
469         }
470
471         DBGC ( tftp, "TFTP %p received ERROR packet with code %d, message "
472                "\"%s\"\n", tftp, ntohs ( error->errcode ), error->errmsg );
473         
474         /* Determine final operation result */
475         err = ntohs ( error->errcode );
476         if ( err < ( sizeof ( tftp_errors ) / sizeof ( tftp_errors[0] ) ) )
477                 rc = -tftp_errors[err];
478         if ( ! rc )
479                 rc = -PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION;
480
481         /* Close TFTP request */
482         tftp_done ( tftp, rc );
483
484         return 0;
485 }
486
487 /**
488  * Receive new data
489  *
490  * @v udp               UDP connection
491  * @v data              Received data
492  * @v len               Length of received data
493  * @v st_src            Partially-filled source address
494  * @v st_dest           Partially-filled destination address
495  */
496 static int tftp_socket_deliver_iob ( struct xfer_interface *socket,
497                                      struct io_buffer *iobuf,
498                                      struct xfer_metadata *meta ) {
499         struct tftp_request *tftp =
500                 container_of ( socket, struct tftp_request, socket );
501         struct sockaddr_tcpip *st_src;
502         struct tftp_common *common = iobuf->data;
503         size_t len = iob_len ( iobuf );
504         int rc = -EINVAL;
505         
506         /* Sanity checks */
507         if ( len < sizeof ( *common ) ) {
508                 DBGC ( tftp, "TFTP %p received underlength packet length %d\n",
509                        tftp, len );
510                 goto done;
511         }
512         if ( ! meta ) {
513                 DBGC ( tftp, "TFTP %p received packet without metadata\n",
514                        tftp );
515                 goto done;
516         }
517         if ( ! meta->src ) {
518                 DBGC ( tftp, "TFTP %p received packet without source port\n",
519                        tftp );
520                 goto done;
521         }
522
523         /* Filter by TID.  Set TID on first response received */
524         st_src = ( struct sockaddr_tcpip * ) meta->src;
525         if ( tftp->state < 0 ) {
526                 memcpy ( &tftp->peer, st_src, sizeof ( tftp->peer ) );
527                 DBGC ( tftp, "TFTP %p using remote port %d\n", tftp,
528                        ntohs ( tftp->peer.st_port ) );
529         } else if ( memcmp ( &tftp->peer, st_src,
530                              sizeof ( tftp->peer ) ) != 0 ) {
531                 DBGC ( tftp, "TFTP %p received packet from wrong source (got "
532                        "%d, wanted %d)\n", tftp, ntohs ( st_src->st_port ),
533                        ntohs ( tftp->peer.st_port ) );
534                 goto done;
535         }
536
537         switch ( common->opcode ) {
538         case htons ( TFTP_OACK ):
539                 rc = tftp_rx_oack ( tftp, iobuf->data, len );
540                 break;
541         case htons ( TFTP_DATA ):
542                 rc = tftp_rx_data ( tftp, iobuf );
543                 iobuf = NULL;
544                 break;
545         case htons ( TFTP_ERROR ):
546                 rc = tftp_rx_error ( tftp, iobuf->data, len );
547                 break;
548         default:
549                 DBGC ( tftp, "TFTP %p received strange packet type %d\n",
550                        tftp, ntohs ( common->opcode ) );
551                 break;
552         };
553
554  done:
555         free_iob ( iobuf );
556         return rc;
557 }
558
559 /**
560  * TFTP connection closed by network stack
561  *
562  * @v socket            Transport layer interface
563  * @v rc                Reason for close
564  */
565 static void tftp_socket_close ( struct xfer_interface *socket, int rc ) {
566         struct tftp_request *tftp =
567                 container_of ( socket, struct tftp_request, socket );
568
569         DBGC ( tftp, "TFTP %p socket closed: %s\n",
570                tftp, strerror ( rc ) );
571
572         tftp_done ( tftp, rc );
573 }
574
575 /** TFTP socket operations */
576 static struct xfer_interface_operations tftp_socket_operations = {
577         .close          = tftp_socket_close,
578         .vredirect      = xfer_vopen,
579         .request        = ignore_xfer_request,
580         .seek           = ignore_xfer_seek,
581         .alloc_iob      = default_xfer_alloc_iob,
582         .deliver_iob    = tftp_socket_deliver_iob,
583         .deliver_raw    = xfer_deliver_as_iob,
584 };
585  
586 /**
587  * Close TFTP data transfer interface
588  *
589  * @v xfer              Data transfer interface
590  * @v rc                Reason for close
591  */
592 static void tftp_xfer_close ( struct xfer_interface *xfer, int rc ) {
593         struct tftp_request *tftp =
594                 container_of ( xfer, struct tftp_request, xfer );
595
596         DBGC ( tftp, "TFTP %p interface closed: %s\n",
597                tftp, strerror ( rc ) );
598
599         tftp_done ( tftp, rc );
600 }
601
602 /** TFTP data transfer interface operations */
603 static struct xfer_interface_operations tftp_xfer_operations = {
604         .close          = tftp_xfer_close,
605         .vredirect      = ignore_xfer_vredirect,
606         .request        = ignore_xfer_request,
607         .seek           = ignore_xfer_seek,
608         .alloc_iob      = default_xfer_alloc_iob,
609         .deliver_iob    = xfer_deliver_as_raw,
610         .deliver_raw    = ignore_xfer_deliver_raw,
611 };
612
613 /**
614  * Initiate TFTP download
615  *
616  * @v xfer              Data transfer interface
617  * @v uri               Uniform Resource Identifier
618  * @ret rc              Return status code
619  */
620 int tftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
621         struct tftp_request *tftp;
622         struct sockaddr_tcpip server;
623         int rc;
624
625         /* Sanity checks */
626         if ( ! uri->host )
627                 return -EINVAL;
628         if ( ! uri->path )
629                 return -EINVAL;
630
631         /* Allocate and populate TFTP structure */
632         tftp = malloc ( sizeof ( *tftp ) );
633         if ( ! tftp )
634                 return -ENOMEM;
635         memset ( tftp, 0, sizeof ( *tftp ) );
636         tftp->refcnt.free = tftp_free;
637         xfer_init ( &tftp->xfer, &tftp_xfer_operations, &tftp->refcnt );
638         tftp->uri = uri_get ( uri );
639         xfer_init ( &tftp->socket, &tftp_socket_operations, &tftp->refcnt );
640         tftp->state = -1;
641         tftp->timer.expired = tftp_timer_expired;
642
643         /* Open socket */
644         memset ( &server, 0, sizeof ( server ) );
645         server.st_port = htons ( uri_port ( tftp->uri, TFTP_PORT ) );
646         if ( ( rc = xfer_open_named_socket ( &tftp->socket, SOCK_DGRAM,
647                                              ( struct sockaddr * ) &server,
648                                              uri->host, NULL ) ) != 0 )
649                 goto err;
650
651         /* Start timer to initiate RRQ */
652         start_timer ( &tftp->timer );
653
654         /* Attach to parent interface, mortalise self, and return */
655         xfer_plug_plug ( &tftp->xfer, xfer );
656         ref_put ( &tftp->refcnt );
657         return 0;
658
659  err:
660         DBGC ( tftp, "TFTP %p could not create request: %s\n",
661                tftp, strerror ( rc ) );
662         tftp_done ( tftp, rc );
663         ref_put ( &tftp->refcnt );
664         return rc;
665 }
666
667 /** TFTP URI opener */
668 struct uri_opener tftp_uri_opener __uri_opener = {
669         .scheme = "tftp",
670         .open   = tftp_open,
671 };