2 #include "old_tcp.h" /* for struct tcphdr */
10 * await_reply() filter for TFTP packets
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
19 * @ret True This is our TFTP packet
20 * @ret False This is not one of our TFTP packets
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).
27 * Use await_tftp() in code such as
31 * if ( await_reply ( await_tftp, 0, &tftp_state, timeout ) ) {
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;
42 /* Must have valid UDP (and, therefore, also IP) headers */
44 DBG2 ( "TFTPCORE: not UDP\n" );
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 );
53 /* Packet may be addressed to our IP address and unicast UDP
56 if ( ( ip->dest.s_addr == arptable[ARP_CLIENT].ipaddr.s_addr ) &&
57 ( ntohs ( udp->dest ) == state->lport ) ) {
60 /* Packet may be addressed to our multicast IP address and UDP
61 * port, if we have one
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 ) ) {
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 );
76 * Retrieve a TFTP packet
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()
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.
95 * If the response from the server is a TFTP ERROR packet, tftp_get()
96 * will return False and #errno will be set accordingly.
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.
102 int tftp_get ( struct tftp_state *state, long timeout,
103 union tftp_any **reply ) {
107 if ( ! await_reply ( await_tftp, 0, state, timeout ) ) {
108 errno = PXENV_STATUS_TFTP_READ_TIMEOUT;
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 );
123 * Issue a TFTP open request (RRQ)
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()
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
149 * If tftp_state::server::sin_port is 0, the standard TFTP server port
150 * (#TFTP_PORT) will be used.
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.
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.
159 * For the various different types of TFTP server, you should treat
160 * tftp_state::lport and tftp_state::multicast as follows:
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.
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
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.
182 * If tftp_state::blksize is 0, the maximum blocksize
183 * (#TFTP_MAX_BLKSIZE) will be requested.
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()).
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.
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.
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.
203 * If the response from the server is a TFTP ERROR packet, tftp_open()
204 * will return False and #errno will be set accordingly.
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 */
215 /* Flush receive queue */
218 /* Default to blksize of TFTP_MAX_BLKSIZE if none specified */
219 if ( ! state->blksize )
220 state->blksize = TFTP_MAX_BLKSIZE;
222 /* Use default TFTP server port if none specified */
223 if ( ! state->server.sin_port )
224 state->server.sin_port = TFTP_PORT;
226 /* Determine whether or not to use lport */
227 fixed_lport = state->lport;
230 rrq.opcode = htons ( TFTP_RRQ );
232 p += sprintf ( p, "%s%coctet%cblksize%c%d%ctsize%c0",
233 filename, 0, 0, 0, state->blksize, 0, 0 ) + 1;
235 p += sprintf ( p, "multicast%c", 0 ) + 1;
237 rrqlen = ( p - ( char * ) &rrq );
239 /* Set negotiated blksize to default value */
240 state->blksize = TFTP_DEFAULT_BLKSIZE;
242 /* Nullify received packet pointer */
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 );
249 /* Set client UDP port, if not already fixed */
251 state->lport = ++lport;
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,
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 );
273 /* We got an error response; abort */
278 DBG ( "TFTPCORE: open request timed out\n" );
279 errno = PXENV_STATUS_TFTP_OPEN_TIMEOUT;
284 * Process a TFTP OACK packet
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
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.
302 * Where an option is not present in the OACK packet, the
303 * corresponding field(s) in #state will be left unaltered.
305 * Calling tftp_process_opts() does not send an acknowledgement for
306 * the OACK packet; this is the responsibility of the caller.
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
314 int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
318 DBG ( "TFTPCORE: processing OACK\n" );
321 end = ( ( char * ) &oack->udp ) + ntohs ( oack->udp.len );
323 /* Only possible error */
326 for ( p = oack->data ; p < end ; ) {
327 if ( strcasecmp ( "blksize", p ) == 0 ) {
329 state->blksize = strtoul ( p, &p, 10 );
331 DBG ( "TFTPCORE: garbage \"%s\" "
332 "after blksize\n", p );
336 DBG ( "TFTPCORE: got blksize %d\n", state->blksize );
337 } else if ( strcasecmp ( "tsize", p ) == 0 ) {
339 state->tsize = strtoul ( p, &p, 10 );
341 DBG ( "TFTPCORE: garbage \"%s\" "
342 "after tsize\n", p );
346 DBG ( "TFTPCORE: got tsize %d\n", state->tsize );
347 } else if ( strcasecmp ( "multicast", p ) == 0 ) {
349 char *e = strchr ( p, ',' );
350 if ( ( ! e ) || ( e >= end ) ) {
351 DBG ( "TFTPCORE: malformed multicast field "
355 /* IP address may be missing, in which case we
356 * should leave state->multicast.sin_addr
363 &state->multicast.sin_addr );
366 DBG ( "TFTPCORE: malformed multicast "
367 "IP address \"%s\"\n", p );
372 /* UDP port may also be missing */
374 state->multicast.sin_port
375 = strtoul ( p, &p, 10 );
377 DBG ( "TFTPCORE: garbage \"%s\" "
378 "after multicast port\n", p );
383 /* "Master Client" must always be present */
384 state->master = strtoul ( p, &p, 10 );
386 DBG ( "TFTPCORE: garbage \"%s\" "
387 "after multicast mc\n", 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" ) );
396 DBG ( "TFTPCORE: unknown option \"%s\"\n", p );
397 p += strlen ( p ) + 1; /* skip option name */
398 p += strlen ( p ) + 1; /* skip option value */
403 DBG ( "TFTPCORE: overran options in OACK\n" );
411 * Acknowledge a TFTP packet
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()
422 * Send a TFTP ACK packet for the most recently received block.
424 * This sends only a single ACK packet; it does not wait for the
427 int tftp_ack_nowait ( struct tftp_state *state ) {
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 );
439 * Acknowledge a TFTP packet and wait for a response
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()
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).
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.
462 * If the response from the server is a TFTP ERROR packet, tftp_open()
463 * will return False and #errno will be set accordingly.
465 int tftp_ack ( struct tftp_state *state, union tftp_any **reply ) {
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" );
476 if ( tftp_get ( state, timeout, reply ) ) {
477 /* We got a non-error response */
481 /* We got an error response */
485 DBG ( "TFTP: timed out during read\n" );
486 errno = PXENV_STATUS_TFTP_READ_TIMEOUT;
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
502 * Send a TFTP ERROR packet back to the server to terminate the
505 * If #errmsg is NULL, the current error message string as returned by
506 * strerror(errno) will be used as the error text.
508 int tftp_error ( struct tftp_state *state, int errcode, const char *errmsg ) {
509 struct tftp_error error;
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 );
522 * Interpret a TFTP error
524 * @v error Pointer to a struct tftp_error
526 * Sets #errno based on the error code in a TFTP ERROR packet.
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,
534 unsigned int errcode = ntohs ( error->errcode );
537 if ( errcode < ( sizeof(errmap) / sizeof(errmap[0]) ) )
538 errno = errmap[errcode];
540 errno = PXENV_STATUS_TFTP_ERROR_OPCODE;