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