Warnings purge
[people/xl0/gpxe.git] / src / proto / tftpcore.c
1 #include "tftp.h"
2 #include "old_tcp.h" /* for struct tcphdr */
3 #include "errno.h"
4 #include "etherboot.h"
5 #include "tftpcore.h"
6
7 /** @file */
8
9 /**
10  * await_reply() filter for TFTP packets
11  *
12  * @v ptr                               Pointer to a struct tftp_state
13  * @v tftp_state::server::sin_addr      TFTP server IP address
14  * @v tftp_state::lport                 Client UDP port
15  * @v tftp_state::multicast::sin_addr   Multicast IP address, or 0.0.0.0
16  * @v tftp_state::multicast::sin_port   Multicast UDP port, or 0
17  * @v ip                                IP header
18  * @v udp                               UDP header
19  * @ret True                            This is our TFTP packet
20  * @ret False                           This is not one of our TFTP packets
21  *
22  * Wait for a TFTP packet that is part of the current connection
23  * (i.e. comes from the TFTP server, has the correct destination port,
24  * and is addressed either to our IP address and UDP port, or to our
25  * multicast listening address and UDP port).
26  *
27  * Use await_tftp() in code such as
28  *
29  * @code
30  *
31  * if ( await_reply ( await_tftp, 0, &tftp_state, timeout ) ) {
32  *      ...
33  * }
34  *
35  * @endcode
36  */
37 static int await_tftp ( int ival __unused, void *ptr,
38                         unsigned short ptype __unused, struct iphdr *ip,
39                         struct udphdr *udp, struct tcphdr *tcp __unused ) {
40         struct tftp_state *state = ptr;
41
42         /* Must have valid UDP (and, therefore, also IP) headers */
43         if ( ! udp ) {
44                 DBG2 ( "TFTPCORE: not UDP\n" );
45                 return 0;
46         }
47         /* Packet must come from the TFTP server */
48         if ( ip->src.s_addr != state->server.sin_addr.s_addr ) {
49                 DBG2 ( "TFTPCORE: from %@, not from TFTP server %@\n",
50                        ip->src.s_addr, state->server.sin_addr.s_addr );
51                 return 0;
52         }
53         /* Packet may be addressed to our IP address and unicast UDP
54          * port
55          */
56         if ( ( ip->dest.s_addr == arptable[ARP_CLIENT].ipaddr.s_addr ) &&
57              ( ntohs ( udp->dest ) == state->lport ) ) {
58                 return 1;
59         }
60         /* Packet may be addressed to our multicast IP address and UDP
61          * port, if we have one
62          */
63         if ( ( state->multicast.sin_addr.s_addr ) && 
64              ( ip->dest.s_addr == state->multicast.sin_addr.s_addr ) &&
65              ( ntohs ( udp->dest ) == state->multicast.sin_port ) ) {
66                 return 1;
67         }
68         DBG2 ( "TFTPCORE: to %@:%d, not to %@:%d (or %@:%d)\n",
69                ip->dest.s_addr, ntohs ( udp->dest ),
70                arptable[ARP_CLIENT].ipaddr.s_addr, state->lport,
71                state->multicast.sin_addr.s_addr, state->multicast.sin_port );
72         return 0;
73 }
74
75 /**
76  * Retrieve a TFTP packet
77  *
78  * @v state                             TFTP transfer state
79  * @v tftp_state::server::sin_addr      TFTP server IP address
80  * @v tftp_state::lport                 Client UDP port
81  * @v tftp_state::multicast::sin_addr   Multicast IP address, or 0.0.0.0
82  * @v tftp_state::multicast::sin_port   Multicast UDP port, or 0
83  * @v timeout                           Time to wait for a response
84  * @ret True                            Received a non-error response
85  * @ret False                           Received error response / no response
86  * @ret *reply                          The server's response, if any
87  * @err #PXENV_STATUS_TFTP_READ_TIMEOUT No response received in time
88  * @err other                           As set by tftp_set_errno()
89  *
90  * Retrieve the next packet sent by the TFTP server, if any is sent
91  * within the specified timeout period.  The packet is returned via
92  * #reply.  If no packet is received within the timeout period, a NULL
93  * value will be stored in #reply.
94  *
95  * If the response from the server is a TFTP ERROR packet, tftp_get()
96  * will return False and #errno will be set accordingly.
97  *
98  * You can differentiate between "received no response" and "received
99  * an error response" by checking #reply; if #reply is NULL then no
100  * response was received.
101  */
102 int tftp_get ( struct tftp_state *state, long timeout,
103                union tftp_any **reply ) {
104
105         *reply = NULL;
106
107         if ( ! await_reply ( await_tftp, 0, state, timeout ) ) {
108                 errno = PXENV_STATUS_TFTP_READ_TIMEOUT;
109                 return 0;
110         }
111
112         *reply = ( union tftp_any * ) &nic.packet[ETH_HLEN];
113         DBG ( "TFTPCORE: got reply (type %d)\n",
114               ntohs ( (*reply)->common.opcode ) );
115         if ( ntohs ( (*reply)->common.opcode ) == TFTP_ERROR ){
116                 tftp_set_errno ( &(*reply)->error );
117                 return 0;
118         }
119         return 1;
120 }
121
122 /**
123  * Issue a TFTP open request (RRQ)
124  *
125  * @v state                             TFTP transfer state
126  * @v tftp_state::server::sin_addr      TFTP server IP address
127  * @v tftp_state::server::sin_port      TFTP server UDP port, or 0
128  * @v tftp_state::lport                 Client UDP port, or 0
129  * @v tftp_state::multicast::sin_addr   Multicast IP address, or 0.0.0.0
130  * @v tftp_state::multicast::sin_port   Multicast UDP port, or 0
131  * @v tftp_state::blksize               Requested blksize, or 0
132  * @v filename                          File name
133  * @v multicast                         Enable/disable rfc2090 multicast TFTP
134  * @ret True                            Received a non-error response
135  * @ret False                           Received error response / no response
136  * @ret tftp_state::server::sin_port    TFTP server UDP port
137  * @ret tftp_state::lport               Client UDP port
138  * @ret tftp_state::blksize             Always #TFTP_DEFAULT_BLKSIZE
139  * @ret *reply                          The server's response, if any
140  * @err #PXENV_STATUS_TFTP_OPEN_TIMEOUT TFTP open timed out
141  * @err other                           As returned by udp_transmit()
142  * @err other                           As set by tftp_set_errno()
143  *
144  * Send a TFTP/TFTM/MTFTP RRQ (read request) to a TFTP server, and
145  * return the server's reply (which may be an OACK, DATA or ERROR
146  * packet).  The server's reply will not be acknowledged, or processed
147  * in any way.
148  *
149  * If tftp_state::server::sin_port is 0, the standard TFTP server port
150  * (#TFTP_PORT) will be used.
151  *
152  * If tftp_state::lport is 0, the standard mechanism of
153  * using a new, unique port number for each TFTP request will be used.
154  * 
155  * If tftp_state::multicast::sin_addr is not 0.0.0.0, it (and
156  * tftp_state::multicast::sin_port) will be used as a multicast
157  * listening address for replies from the TFTP server.
158  *
159  * For the various different types of TFTP server, you should treat
160  * tftp_state::lport and tftp_state::multicast as follows:
161  *
162  *   - Standard TFTP server: set tftp_state::lport to 0,
163  *     tftp_state::multicast::sin_addr to 0.0.0.0 and
164  *     tftp_state::multicast::sin_port to 0.  tftp_open() will set
165  *     tftp_state::lport to the assigned local UDP port.
166  *
167  *   - TFTM server: set tftp_state::lport to 0,
168  *     tftp_state::multicast::sin_addr to 0.0.0.0 and
169  *     tftp_state::multicast::sin_port to 0.  tftp_open() will set
170  *     tftp_state::lport to the assigned local UDP port.  (Your call
171  *     to tftp_process_opts() will then overwrite both
172  *     tftp_state::multicast::sin_addr and
173  *     tftp_state::multicast::sin_port with the values specified in
174  *     the OACK packet.)
175  *
176  *   - MTFTP server: set tftp_state::multicast::sin_addr to the
177  *     multicast address and both tftp_state::lport and
178  *     tftp_state::multicast::sin_port to the multicast port (both of
179  *     which must be previously known, e.g. provided by a DHCP
180  *     server).  tftp_open() will not alter these values.
181  *
182  * If tftp_state::blksize is 0, the maximum blocksize
183  * (#TFTP_MAX_BLKSIZE) will be requested.
184  *
185  * On exit, tftp_state::blksize will always contain
186  * #TFTP_DEFAULT_BLKSIZE, since this is the blocksize value that must
187  * be assumed until the OACK packet is processed (by a subsequent call
188  * to tftp_process_opts()).
189  *
190  * tftp_state::server::sin_port will be set to the UDP port from which
191  * the server's response originated.  This may or may not be the port
192  * to which the open request was sent.
193  *
194  * The options "blksize" and "tsize" will always be appended to a TFTP
195  * open request.  The option "multicast" will be appended to the
196  * request if #multicast is True.  Servers that do not understand any
197  * of these options should simply ignore them.
198  *
199  * tftp_open() will not automatically join or leave multicast groups;
200  * the caller is responsible for calling join_group() and
201  * leave_group() at appropriate times.
202  *
203  * If the response from the server is a TFTP ERROR packet, tftp_open()
204  * will return False and #errno will be set accordingly.
205  */
206 int tftp_open ( struct tftp_state *state, const char *filename,
207                 union tftp_any **reply, int multicast ) {
208         static unsigned short lport = 2000; /* local port */
209         int fixed_lport;
210         struct tftp_rrq rrq;
211         char *p;
212         unsigned int rrqlen;
213         int retry;
214
215         /* Flush receive queue */
216         rx_qdrain();
217
218         /* Default to blksize of TFTP_MAX_BLKSIZE if none specified */
219         if ( ! state->blksize )
220                 state->blksize = TFTP_MAX_BLKSIZE;
221
222         /* Use default TFTP server port if none specified */
223         if ( ! state->server.sin_port )
224                 state->server.sin_port = TFTP_PORT;
225
226         /* Determine whether or not to use lport */
227         fixed_lport = state->lport;
228
229         /* Set up RRQ */
230         rrq.opcode = htons ( TFTP_RRQ );
231         p = rrq.data;
232         p += sprintf ( p, "%s%coctet%cblksize%c%d%ctsize%c0",
233                        filename, 0, 0, 0, state->blksize, 0, 0 ) + 1;
234         if ( multicast ) {
235                 p += sprintf ( p, "multicast%c", 0 ) + 1;
236         }
237         rrqlen = ( p - ( char * ) &rrq );
238
239         /* Set negotiated blksize to default value */
240         state->blksize = TFTP_DEFAULT_BLKSIZE;
241         
242         /* Nullify received packet pointer */
243         *reply = NULL;
244
245         /* Transmit RRQ until we get a response */
246         for ( retry = 0 ; retry < MAX_TFTP_RETRIES ; retry++ ) {
247                 long timeout = rfc2131_sleep_interval ( TIMEOUT, retry );
248
249                 /* Set client UDP port, if not already fixed */
250                 if ( ! fixed_lport )
251                         state->lport = ++lport;
252                 
253                 /* Send the RRQ */
254                 DBG ( "TFTPCORE: requesting %@:%d/%s from port %d\n",
255                       state->server.sin_addr.s_addr, state->server.sin_port,
256                       rrq.data, state->lport );
257                 if ( ! udp_transmit ( state->server.sin_addr.s_addr,
258                                       state->lport, state->server.sin_port,
259                                       rrqlen, &rrq ) )
260                         return 0;
261                 
262                 /* Wait for response */
263                 if ( tftp_get ( state, timeout, reply ) ) {
264                         /* We got a non-error response */
265                         state->server.sin_port
266                                 = ntohs ( (*reply)->common.udp.src );
267                         DBG ( "TFTP server is at %@:%d\n",
268                               state->server.sin_addr.s_addr,
269                               state->server.sin_port );
270                         return 1;
271                 }
272                 if ( *reply ) {
273                         /* We got an error response; abort */
274                         return 0;
275                 }
276         }
277
278         DBG ( "TFTPCORE: open request timed out\n" );
279         errno = PXENV_STATUS_TFTP_OPEN_TIMEOUT;
280         return 0;
281 }
282
283 /**
284  * Process a TFTP OACK packet
285  *
286  * @v state                             TFTP transfer state
287  * @v oack                              The TFTP OACK packet
288  * @ret True                            Options were processed successfully
289  * @ret False                           Options were not processed successfully
290  * @ret tftp_state::blksize             Negotiated blksize
291  * @ret tftp_state::tsize               File size (if known), or 0
292  * @ret tftp_state::multicast::sin_addr Multicast IP address, or 0.0.0.0
293  * @ret tftp_state::multicast::sin_port Multicast UDP port, or 0
294  * @ret tftp_state::master              Client is master
295  * @err EINVAL                          An invalid option value was encountered
296  *
297  * Process the options returned by the TFTP server in an rfc2347 OACK
298  * packet.  The options "blksize" (rfc2348), "tsize" (rfc2349) and
299  * "multicast" (rfc2090) are recognised and processed; any other
300  * options are silently ignored.
301  *
302  * Where an option is not present in the OACK packet, the
303  * corresponding field(s) in #state will be left unaltered.
304  *
305  * Calling tftp_process_opts() does not send an acknowledgement for
306  * the OACK packet; this is the responsibility of the caller.
307  *
308  * @note If the "blksize" option is not present, tftp_state::blksize
309  * will @b not be implicitly set to #TFTP_DEFAULT_BLKSIZE.  However,
310  * since tftp_open() always sets tftp_state::blksize to
311  * #TFTP_DEFAULT_BLKSIZE before returning, you probably don't need to
312  * worry about this.
313  */
314 int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
315         const char *p;
316         const char *end;
317
318         DBG ( "TFTPCORE: processing OACK\n" );
319
320         /* End of options */
321         end = ( ( char * ) &oack->udp ) + ntohs ( oack->udp.len );
322
323         /* Only possible error */
324         errno = EINVAL;
325
326         for ( p = oack->data ; p < end ; ) {
327                 if ( strcasecmp ( "blksize", p ) == 0 ) {
328                         p += 8;
329                         state->blksize = strtoul ( p, &p, 10 );
330                         if ( *p ) {
331                                 DBG ( "TFTPCORE: garbage \"%s\" "
332                                       "after blksize\n", p );
333                                 return 0;
334                         }
335                         p++;
336                         DBG ( "TFTPCORE: got blksize %d\n", state->blksize );
337                 } else if ( strcasecmp ( "tsize", p ) == 0 ) {
338                         p += 6;
339                         state->tsize = strtoul ( p, &p, 10 );
340                         if ( *p ) {
341                                 DBG ( "TFTPCORE: garbage \"%s\" "
342                                       "after tsize\n", p );
343                                 return 0;
344                         }
345                         p++;
346                         DBG ( "TFTPCORE: got tsize %d\n", state->tsize );
347                 } else if ( strcasecmp ( "multicast", p ) == 0 ) {
348                         p += 10;
349                         char *e = strchr ( p, ',' );
350                         if ( ( ! e ) || ( e >= end ) ) {
351                                 DBG ( "TFTPCORE: malformed multicast field "
352                                       "\"%s\"\n", p );
353                                 return 0;
354                         }
355                         /* IP address may be missing, in which case we
356                          * should leave state->multicast.sin_addr
357                          * unaltered.
358                          */
359                         if ( e != p ) {
360                                 int rc;
361                                 *e = '\0';
362                                 rc = inet_aton ( p,
363                                                  &state->multicast.sin_addr );
364                                 *e = ',';
365                                 if ( ! rc ) {
366                                         DBG ( "TFTPCORE: malformed multicast "
367                                               "IP address \"%s\"\n", p );
368                                         return 0;
369                                 }
370                         }
371                         p = e + 1;
372                         /* UDP port may also be missing */
373                         if ( *p != ',' ) {
374                                 state->multicast.sin_port
375                                         = strtoul ( p, &p, 10 );
376                                 if ( *p != ',' ) {
377                                         DBG ( "TFTPCORE: garbage \"%s\" "
378                                               "after multicast port\n", p );
379                                         return 0;
380                                 }
381                         }
382                         p++;
383                         /* "Master Client" must always be present */
384                         state->master = strtoul ( p, &p, 10 );
385                         if ( *p ) {
386                                 DBG ( "TFTPCORE: garbage \"%s\" "
387                                       "after multicast mc\n", p );
388                                 return 0;
389                         }
390                         p++;
391                         DBG ( "TFTPCORE: got multicast %@:%d (%s)\n",
392                               state->multicast.sin_addr.s_addr,
393                               state->multicast.sin_port,
394                               ( state->master ? "master" : "not master" ) );
395                 } else {
396                         DBG ( "TFTPCORE: unknown option \"%s\"\n", p );
397                         p += strlen ( p ) + 1; /* skip option name */
398                         p += strlen ( p ) + 1; /* skip option value */
399                 }
400         }
401
402         if ( p > end ) {
403                 DBG ( "TFTPCORE: overran options in OACK\n" );
404                 return 0;
405         }
406
407         return 1;
408 }
409
410 /**
411  * Acknowledge a TFTP packet
412  *
413  * @v state                             TFTP transfer state
414  * @v tftp_state::server::sin_addr      TFTP server IP address
415  * @v tftp_state::server::sin_port      TFTP server UDP port
416  * @v tftp_state::lport                 Client UDP port
417  * @v tftp_state::block                 Most recently received block number
418  * @ret True                            Acknowledgement packet was sent
419  * @ret False                           Acknowledgement packet was not sent
420  * @err other                           As returned by udp_transmit()
421  * 
422  * Send a TFTP ACK packet for the most recently received block.
423  *
424  * This sends only a single ACK packet; it does not wait for the
425  * server's response.
426  */
427 int tftp_ack_nowait ( struct tftp_state *state ) {
428         struct tftp_ack ack;
429
430         DBG ( "TFTPCORE: acknowledging data block %d\n", state->block );
431         ack.opcode = htons ( TFTP_ACK );
432         ack.block = htons ( state->block );
433         return udp_transmit ( state->server.sin_addr.s_addr,
434                               state->lport, state->server.sin_port,
435                               sizeof ( ack ), &ack );
436 }
437
438 /**
439  * Acknowledge a TFTP packet and wait for a response
440  *
441  * @v state                             TFTP transfer state
442  * @v tftp_state::server::sin_addr      TFTP server IP address
443  * @v tftp_state::server::sin_port      TFTP server UDP port
444  * @v tftp_state::lport                 Client UDP port
445  * @v tftp_state::block                 Most recently received block number
446  * @ret True                            Received a non-error response
447  * @ret False                           Received error response / no response
448  * @ret *reply                          The server's response, if any
449  * @err #PXENV_STATUS_TFTP_READ_TIMEOUT Timed out waiting for a response
450  * @err other                           As returned by tftp_ack_nowait()
451  * @err other                           As set by tftp_set_errno()
452  *
453  * Send a TFTP ACK packet for the most recently received data block,
454  * and keep transmitting this ACK until we get a response from the
455  * server (e.g. a new data block).
456  *
457  * If the response is a TFTP DATA packet, no processing is done.
458  * Specifically, the block number is not checked to ensure that this
459  * is indeed the next data block in the sequence, nor is
460  * tftp_state::block updated with the new block number.
461  *
462  * If the response from the server is a TFTP ERROR packet, tftp_open()
463  * will return False and #errno will be set accordingly.
464  */
465 int tftp_ack ( struct tftp_state *state, union tftp_any **reply ) {
466         int retry;
467
468         *reply = NULL;
469         for ( retry = 0 ; retry < MAX_TFTP_RETRIES ; retry++ ) {
470                 long timeout = rfc2131_sleep_interval ( TFTP_REXMT, retry );
471                 /* ACK the last data block */
472                 if ( ! tftp_ack_nowait ( state ) ) {
473                         DBG ( "TFTP: could not send ACK: %m\n" );
474                         return 0;
475                 }
476                 if ( tftp_get ( state, timeout, reply ) ) {
477                         /* We got a non-error response */
478                         return 1;
479                 }
480                 if ( *reply ) {
481                         /* We got an error response */
482                         return 0;
483                 }
484         }
485         DBG ( "TFTP: timed out during read\n" );
486         errno = PXENV_STATUS_TFTP_READ_TIMEOUT;
487         return 0;
488 }
489
490 /**
491  * Send a TFTP error
492  *
493  * @v state                             TFTP transfer state
494  * @v tftp_state::server::sin_addr      TFTP server IP address
495  * @v tftp_state::server::sin_port      TFTP server UDP port
496  * @v tftp_state::lport                 Client UDP port
497  * @v errcode                           TFTP error code
498  * @v errmsg                            Descriptive error string, or NULL
499  * @ret True                            Error packet was sent
500  * @ret False                           Error packet was not sent
501  *
502  * Send a TFTP ERROR packet back to the server to terminate the
503  * transfer.
504  *
505  * If #errmsg is NULL, the current error message string as returned by
506  * strerror(errno) will be used as the error text.
507  */
508 int tftp_error ( struct tftp_state *state, int errcode, const char *errmsg ) {
509         struct tftp_error error;
510
511         DBG ( "TFTPCORE: aborting with error %d (%s)\n", errcode, errmsg );
512         error.opcode = htons ( TFTP_ERROR );
513         error.errcode = htons ( errcode );
514         strncpy ( error.errmsg, errmsg ? errmsg : strerror ( errno ),
515                   sizeof ( error.errmsg ) );
516         return udp_transmit ( state->server.sin_addr.s_addr,
517                               state->lport, state->server.sin_port,
518                               sizeof ( error ), &error );
519 }
520
521 /**
522  * Interpret a TFTP error
523  *
524  * @v error                             Pointer to a struct tftp_error
525  *
526  * Sets #errno based on the error code in a TFTP ERROR packet.
527  */
528 void tftp_set_errno ( struct tftp_error *error ) {
529         static int errmap[] = {
530                 [TFTP_ERR_FILE_NOT_FOUND] = PXENV_STATUS_TFTP_FILE_NOT_FOUND,
531                 [TFTP_ERR_ACCESS_DENIED] = PXENV_STATUS_TFTP_ACCESS_VIOLATION,
532                 [TFTP_ERR_ILLEGAL_OP] = PXENV_STATUS_TFTP_UNKNOWN_OPCODE,
533         };
534         unsigned int errcode = ntohs ( error->errcode );
535         
536         errno = 0;
537         if ( errcode < ( sizeof(errmap) / sizeof(errmap[0]) ) )
538                 errno = errmap[errcode];
539         if ( ! errno )
540                 errno = PXENV_STATUS_TFTP_ERROR_OPCODE;
541 }