Add tftp_ack() and tftp_error()
[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
6 /** @file
7  *
8  * TFTP core functions
9  *
10  * This file provides functions that are common to the TFTP (rfc1350),
11  * TFTM (rfc2090) and MTFTP (PXE) protocols.
12  *
13  */
14
15 /**
16  * Wait for a TFTP packet
17  *
18  * @v ptr                       Pointer to a struct tftp_state
19  * @v ip                        IP header
20  * @v udp                       UDP header
21  * @ret True                    This is our TFTP packet
22  * @ret False                   This is not one of our TFTP packets
23  *
24  * Wait for a TFTP packet that is part of the current connection
25  * (i.e. comes from the TFTP server, has the correct destination port,
26  * and is addressed either to our IP address or to our multicast
27  * listening address).
28  *
29  * Invoke await_tftp() using code such as
30  *
31  * @code
32  *
33  * if ( await_reply ( await_tftp, 0, &tftp_state, timeout ) ) {
34  *      ...
35  * }
36  *
37  * @endcode
38  */
39 int await_tftp ( int ival __unused, void *ptr, unsigned short ptype __unused,
40                  struct iphdr *ip, struct udphdr *udp,
41                  struct tcphdr *tcp __unused ) {
42         struct tftp_state *state = ptr;
43
44         /* Must have valid UDP (and, therefore, also IP) headers */
45         if ( ! udp ) {
46                 return 0;
47         }
48         /* Packet must come from the TFTP server */
49         if ( ip->src.s_addr != state->server.sin_addr.s_addr )
50                 return 0;
51         /* Packet must be addressed to the correct UDP port */
52         if ( ntohs ( udp->dest ) != state->client.sin_port )
53                 return 0;
54         /* Packet must be addressed to us, or to our multicast
55          * listening address (if we have one).
56          */
57         if ( ! ( ( ip->dest.s_addr == arptable[ARP_CLIENT].ipaddr.s_addr ) ||
58                  ( ( state->client.sin_addr.s_addr ) && 
59                    ( ip->dest.s_addr == state->client.sin_addr.s_addr ) ) ) )
60                 return 0;
61         return 1;
62 }
63
64
65 /**
66  * Issue a TFTP open request (RRQ)
67  *
68  * @v state                             TFTP transfer state
69  * @v tftp_state::server::sin_addr      TFTP server IP address
70  * @v tftp_state::server::sin_port      TFTP server UDP port, or 0
71  * @v tftp_state::client::sin_addr      Client multicast IP address, or 0.0.0.0
72  * @v tftp_state::client::sin_port      Client UDP port, or 0
73  * @v tftp_state::blksize               Requested blksize, or 0
74  * @v filename                          File name
75  * @ret True                            Received a non-error response
76  * @ret False                           Received error response / no response
77  * @ret tftp_state::client::sin_port    Client UDP port
78  * @ret tftp_state::client::blksize     Always #TFTP_DEFAULT_BLKSIZE
79  * @ret *tftp                           The server's response, if any
80  *
81  * Send a TFTP/TFTM/MTFTP RRQ (read request) to a TFTP server, and
82  * return the server's reply (which may be an OACK, DATA or ERROR
83  * packet).  The server's reply will not be acknowledged, or processed
84  * in any way.
85  *
86  * If tftp_state::server::sin_port is 0, the standard tftp server port
87  * (#TFTP_PORT) will be used.
88  *
89  * If tftp_state::client::sin_addr is not 0.0.0.0, it will be used as
90  * a multicast listening address for replies from the TFTP server.
91  *
92  * If tftp_state::client::sin_port is 0, the standard mechanism of
93  * using a new, unique port number for each TFTP request will be used.
94  * 
95  * For the various different types of TFTP server, you should treat
96  * tftp_state::client as follows:
97  *
98  *   - Standard TFTP server: set tftp_state::client::sin_addr to
99  *     0.0.0.0 and tftp_state::client::sin_port to 0.  tftp_open()
100  *     will set tftp_state::client::sin_port to the assigned local UDP
101  *     port.
102  *
103  *   - TFTM server: set tftp_state::client::sin_addr to 0.0.0.0 and
104  *     tftp_state::client::sin_port to 0.  tftp_open() will set
105  *     tftp_state::client::sin_port to the assigned local UDP port.
106  *     (Your call to tftp_process_opts() will then overwrite both
107  *     tftp_state::client::sin_addr and tftp_state::client::sin_port
108  *     with the values return in the OACK packet.)
109  *
110  *   - MTFTP server: set tftp_state::client::sin_addr to the client
111  *     multicast address and tftp_state::client::sin_port to the
112  *     client multicast port (both of which must be previously known,
113  *     e.g. provided by a DHCP server).  tftp_open() will not alter
114  *     these values.
115  *
116  * If tftp_state::blksize is 0, the maximum blocksize
117  * (#TFTP_MAX_BLKSIZE) will be requested.
118  *
119  * On exit, tftp_state::blksize will always contain
120  * #TFTP_DEFAULT_BLKSIZE, since this is the blocksize value that must
121  * be assumed until the OACK packet is processed (by a subsequent call
122  * to tftp_process_opts()).
123  *
124  * The options "blksize", "tsize" and "multicast" will always be
125  * appended to a TFTP open request.  Servers that do not understand
126  * any of these options should simply ignore them.
127  *
128  * tftp_open() will not automatically join or leave multicast groups;
129  * the caller is responsible for calling join_group() and
130  * leave_group() at appropriate times.
131  *
132  */
133 int tftp_open ( struct tftp_state *state, const char *filename,
134                 union tftp_any **tftp ) {
135         static unsigned short lport = 2000; /* local port */
136         int fixed_lport;
137         struct tftp_rrq rrq;
138         unsigned int rrqlen;
139         int retry;
140
141         /* Flush receive queue */
142         rx_qdrain();
143
144         /* Default to blksize of TFTP_MAX_BLKSIZE if none specified */
145         if ( ! state->blksize )
146                 state->blksize = TFTP_MAX_BLKSIZE;
147
148         /* Use default TFTP server port if none specified */
149         if ( ! state->server.sin_port )
150                 state->server.sin_port = TFTP_PORT;
151
152         /* Determine whether or not to use lport */
153         fixed_lport = state->server.sin_port;
154
155         /* Set up RRQ */
156         rrq.opcode = htons ( TFTP_RRQ );
157         rrqlen = ( offsetof ( typeof ( rrq ), data ) +
158                     sprintf ( rrq.data,
159                               "%s%coctet%cblksize%c%d%ctsize%c0%cmulticast%c",
160                               filename, 0, 0, 0, state->blksize, 0, 0, 0, 0 )
161                     + 1 );
162
163         /* Set negotiated blksize to default value */
164         state->blksize = TFTP_DEFAULT_BLKSIZE;
165         
166         /* Nullify received packet pointer */
167         *tftp = NULL;
168
169         /* Transmit RRQ until we get a response */
170         for ( retry = 0 ; retry < MAX_TFTP_RETRIES ; retry++ ) {
171                 long timeout = rfc2131_sleep_interval ( TIMEOUT, retry );
172
173                 /* Set client UDP port, if not already fixed */
174                 if ( ! fixed_lport )
175                         state->client.sin_port = ++lport;
176                 
177                 /* Send the RRQ */
178                 DBG ( "TFTPCORE: requesting %@:%d/%s from port %d\n",
179                       state->server.sin_addr.s_addr, state->server.sin_port,
180                       rrq.data, state->client.sin_port );
181                 if ( ! udp_transmit ( state->server.sin_addr.s_addr,
182                                       state->client.sin_port,
183                                       state->server.sin_port,
184                                       rrqlen, &rrq ) )
185                         return 0;
186                 
187                 /* Wait for response */
188                 if ( await_reply ( await_tftp, 0, state, timeout ) ) {
189                         *tftp = ( union tftp_any * ) &nic.packet[ETH_HLEN];
190                         return 1;
191                 }
192         }
193
194         errno = PXENV_STATUS_TFTP_OPEN_TIMEOUT;
195         return 0;
196 }
197
198 /**
199  * Process a TFTP OACK packet
200  *
201  * @v state                             TFTP transfer state
202  * @v oack                              The TFTP OACK packet
203  * @ret True                            Options were processed successfully
204  * @ret False                           Options were not processed successfully
205  * @ret tftp_state::blksize             Negotiated blksize
206  * @ret tftp_state::tsize               File size (if known), or 0
207  * @ret tftp_state::client::sin_addr    Client multicast IP address, or 0.0.0.0
208  * @ret tftp_state::client::sin_port    Client UDP port
209  * @ret tftp_state::master              Client is master
210  * @err EINVAL                          An invalid option value was encountered
211  *
212  * Process the options returned by the TFTP server in an rfc2347 OACK
213  * packet.  The options "blksize" (rfc2348), "tsize" (rfc2349) and
214  * "multicast" (rfc2090) are recognised and processed; any other
215  * options are silently ignored.
216  *
217  * Where an option is not present in the OACK packet, the
218  * corresponding field(s) in #state will be left unaltered.
219  *
220  * Calling tftp_process_opts() does not send an acknowledgement for
221  * the OACK packet; this is the responsibility of the caller.
222  *
223  * @note If the "blksize" option is not present, tftp_state::blksize
224  * will @b not be implicitly set to #TFTP_DEFAULT_BLKSIZE.  However,
225  * since tftp_open() always sets tftp_state::blksize to
226  * #TFTP_DEFAULT_BLKSIZE before returning, you probably don't need to
227  * worry about this.
228  */
229 int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
230         const char *p;
231         const char *end;
232
233         /* End of options */
234         end = ( ( char * ) &oack->udp ) + ntohs ( oack->udp.len );
235
236         /* Only possible error */
237         errno = EINVAL;
238
239         for ( p = oack->data ; p < end ; ) {
240                 if ( strcasecmp ( "blksize", p ) == 0 ) {
241                         p += 8;
242                         state->blksize = strtoul ( p, &p, 10 );
243                         if ( *p ) {
244                                 DBG ( "TFTPCORE: garbage \"%s\" "
245                                       "after blksize\n", p );
246                                 return 0;
247                         }
248                         p++;
249                 } else if ( strcasecmp ( "tsize", p ) == 0 ) {
250                         p += 6;
251                         state->tsize = strtoul ( p, &p, 10 );
252                         if ( *p ) {
253                                 DBG ( "TFTPCORE: garbage \"%s\" "
254                                       "after tsize\n", p );
255                                 return 0;
256                         }
257                         p++;
258                 } else if ( strcasecmp ( "multicast", p ) == 0 ) {
259                         char *e = strchr ( p, ',' );
260                         if ( ( ! e ) || ( e >= end ) ) {
261                                 DBG ( "TFTPCORE: malformed multicast field "
262                                       "\"%s\"\n", p );
263                                 return 0;
264                         }
265                         /* IP address may be missing, in which case we
266                          * should leave state->client.sin_addr
267                          * unaltered.
268                          */
269                         if ( e != p ) {
270                                 int rc;
271                                 *e = '\0';
272                                 rc = inet_aton ( p, &state->client.sin_addr );
273                                 *e = ',';
274                                 if ( ! rc ) {
275                                         DBG ( "TFTPCORE: malformed multicast "
276                                               "IP address \"%s\"\n", p );
277                                         return 0;
278                                 }
279                         }
280                         p = e + 1;
281                         /* UDP port may also be missing */
282                         if ( *p != ',' ) {
283                                 state->client.sin_port = strtoul ( p, &p, 10 );
284                                 if ( *p != ',' ) {
285                                         DBG ( "TFTPCORE: garbage \"%s\" "
286                                               "after multicast port\n", p );
287                                         return 0;
288                                 }
289                         } else {
290                                 p++;
291                         }
292                         /* "Master Client" must always be present */
293                         state->master = strtoul ( p, &p, 10 );
294                         if ( *p ) {
295                                 DBG ( "TFTPCORE: garbage \"%s\" "
296                                       "after multicast mc\n", p );
297                                 return 0;
298                         }
299                         p++;
300                 } else {
301                         p += strlen ( p ) + 1; /* skip option name */
302                         p += strlen ( p ) + 1; /* skip option value */
303                 }
304         }
305
306         if ( p > end ) {
307                 DBG ( "TFTPCORE: overran options in OACK\n" );
308                 return 0;
309         }
310
311         return 1;
312 }
313
314 /**
315  * Acknowledge a TFTP packet
316  *
317  * @v state                             TFTP transfer state
318  * @v tftp_state::server::sin_addr      TFTP server IP address
319  * @v tftp_state::server::sin_port      TFTP server UDP port
320  * @v tftp_state::client::sin_port      Client UDP port
321  * @v tftp_state::block                 Most recently received block number
322  * @ret True                            Acknowledgement packet was sent
323  * @ret False                           Acknowledgement packet was not sent
324  * 
325  * Send a TFTP ACK packet for the most recently received block.
326  *
327  * This sends only a single ACK packet; it does not wait for the
328  * server's response.
329  */
330 int tftp_ack ( struct tftp_state *state ) {
331         struct tftp_ack ack;
332
333         ack.opcode = htons ( TFTP_ACK );
334         ack.block = htons ( state->block );
335         return udp_transmit ( state->server.sin_addr.s_addr,
336                               state->client.sin_port, state->server.sin_port,
337                               sizeof ( ack ), &ack );
338 }
339
340 /**
341  * Send a TFTP error
342  *
343  * @v state                             TFTP transfer state
344  * @v tftp_state::server::sin_addr      TFTP server IP address
345  * @v tftp_state::server::sin_port      TFTP server UDP port
346  * @v tftp_state::client::sin_port      Client UDP port
347  * @v err                               TFTP error code
348  * @v errmsg                            Descriptive error string
349  * @ret True                            Error packet was sent
350  * @ret False                           Error packet was not sent
351  *
352  * Send a TFTP ERROR packet back to the server to terminate the
353  * transfer.
354  */
355 int tftp_error ( struct tftp_state *state, int err, const char *errmsg ) {
356         struct tftp_error error;
357
358         DBG ( "TFTPCORE: aborting with error %d (%s)\n", err, errmsg );
359         error.opcode = htons ( TFTP_ERROR );
360         error.errcode = htons ( err );
361         strncpy ( error.errmsg, errmsg, sizeof ( error.errmsg ) );
362         return udp_transmit ( state->server.sin_addr.s_addr,
363                               state->client.sin_port, state->server.sin_port,
364                               sizeof ( error ), &error );
365 }