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