2 #include "tcp.h" /* for struct tcphdr */
10 * This file provides functions that are common to the TFTP (rfc1350),
11 * TFTM (rfc2090) and MTFTP (PXE) protocols.
16 * Wait for a TFTP packet
18 * @v ptr Pointer to a struct tftp_state
21 * @ret True This is our TFTP packet
22 * @ret False This is not one of our TFTP packets
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
29 * Invoke await_tftp() using code such as
33 * if ( await_reply ( await_tftp, 0, &tftp_state, timeout ) ) {
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;
44 /* Must have valid UDP (and, therefore, also IP) headers */
48 /* Packet must come from the TFTP server */
49 if ( ip->src.s_addr != state->server.sin_addr.s_addr )
51 /* Packet must be addressed to the correct UDP port */
52 if ( ntohs ( udp->dest ) != state->client.sin_port )
54 /* Packet must be addressed to us, or to our multicast
55 * listening address (if we have one).
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 ) ) ) )
66 * Issue a TFTP open request (RRQ)
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
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
86 * If tftp_state::server::sin_port is 0, the standard tftp server port
87 * (#TFTP_PORT) will be used.
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.
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.
95 * For the various different types of TFTP server, you should treat
96 * tftp_state::client as follows:
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
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.)
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
116 * If tftp_state::blksize is 0, the maximum blocksize
117 * (#TFTP_MAX_BLKSIZE) will be requested.
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()).
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.
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.
133 int tftp_open ( struct tftp_state *state, const char *filename,
134 union tftp_any **tftp ) {
135 static unsigned short lport = 2000; /* local port */
141 /* Flush receive queue */
144 /* Default to blksize of TFTP_MAX_BLKSIZE if none specified */
145 if ( ! state->blksize )
146 state->blksize = TFTP_MAX_BLKSIZE;
148 /* Use default TFTP server port if none specified */
149 if ( ! state->server.sin_port )
150 state->server.sin_port = TFTP_PORT;
152 /* Determine whether or not to use lport */
153 fixed_lport = state->server.sin_port;
156 rrq.opcode = htons ( TFTP_RRQ );
157 rrqlen = ( offsetof ( typeof ( rrq ), data ) +
159 "%s%coctet%cblksize%c%d%ctsize%c0%cmulticast%c",
160 filename, 0, 0, 0, state->blksize, 0, 0, 0, 0 )
163 /* Set negotiated blksize to default value */
164 state->blksize = TFTP_DEFAULT_BLKSIZE;
166 /* Nullify received packet pointer */
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 );
173 /* Set client UDP port, if not already fixed */
175 state->client.sin_port = ++lport;
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,
187 /* Wait for response */
188 if ( await_reply ( await_tftp, 0, state, timeout ) ) {
189 *tftp = ( union tftp_any * ) &nic.packet[ETH_HLEN];
194 errno = PXENV_STATUS_TFTP_OPEN_TIMEOUT;
199 * Process a TFTP OACK packet
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
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.
217 * Where an option is not present in the OACK packet, the
218 * corresponding field(s) in #state will be left unaltered.
220 * Calling tftp_process_opts() does not send an acknowledgement for
221 * the OACK packet; this is the responsibility of the caller.
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
229 int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
234 end = ( ( char * ) &oack->udp ) + ntohs ( oack->udp.len );
236 /* Only possible error */
239 for ( p = oack->data ; p < end ; ) {
240 if ( strcasecmp ( "blksize", p ) == 0 ) {
242 state->blksize = strtoul ( p, &p, 10 );
244 DBG ( "TFTPCORE: garbage \"%s\" "
245 "after blksize\n", p );
249 } else if ( strcasecmp ( "tsize", p ) == 0 ) {
251 state->tsize = strtoul ( p, &p, 10 );
253 DBG ( "TFTPCORE: garbage \"%s\" "
254 "after tsize\n", p );
258 } else if ( strcasecmp ( "multicast", p ) == 0 ) {
259 char *e = strchr ( p, ',' );
260 if ( ( ! e ) || ( e >= end ) ) {
261 DBG ( "TFTPCORE: malformed multicast field "
265 /* IP address may be missing, in which case we
266 * should leave state->client.sin_addr
272 rc = inet_aton ( p, &state->client.sin_addr );
275 DBG ( "TFTPCORE: malformed multicast "
276 "IP address \"%s\"\n", p );
281 /* UDP port may also be missing */
283 state->client.sin_port = strtoul ( p, &p, 10 );
285 DBG ( "TFTPCORE: garbage \"%s\" "
286 "after multicast port\n", p );
292 /* "Master Client" must always be present */
293 state->master = strtoul ( p, &p, 10 );
295 DBG ( "TFTPCORE: garbage \"%s\" "
296 "after multicast mc\n", p );
301 p += strlen ( p ) + 1; /* skip option name */
302 p += strlen ( p ) + 1; /* skip option value */
307 DBG ( "TFTPCORE: overran options in OACK\n" );
315 * Acknowledge a TFTP packet
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
325 * Send a TFTP ACK packet for the most recently received block.
327 * This sends only a single ACK packet; it does not wait for the
330 int tftp_ack ( struct tftp_state *state ) {
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 );
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
352 * Send a TFTP ERROR packet back to the server to terminate the
355 int tftp_error ( struct tftp_state *state, int err, const char *errmsg ) {
356 struct tftp_error error;
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 );