|
@@ -2,6 +2,7 @@
|
2
|
2
|
#include "tcp.h" /* for struct tcphdr */
|
3
|
3
|
#include "errno.h"
|
4
|
4
|
#include "etherboot.h"
|
|
5
|
+#include "tftpcore.h"
|
5
|
6
|
|
6
|
7
|
/** @file
|
7
|
8
|
*
|
|
@@ -16,6 +17,9 @@
|
16
|
17
|
* Wait for a TFTP packet
|
17
|
18
|
*
|
18
|
19
|
* @v ptr Pointer to a struct tftp_state
|
|
20
|
+ * @v tftp_state::server::sin_addr TFTP server IP address
|
|
21
|
+ * @v tftp_state::client::sin_addr Client multicast IP address, or 0.0.0.0
|
|
22
|
+ * @v tftp_state::client::sin_port Client UDP port
|
19
|
23
|
* @v ip IP header
|
20
|
24
|
* @v udp UDP header
|
21
|
25
|
* @ret True This is our TFTP packet
|
|
@@ -74,16 +78,20 @@ int await_tftp ( int ival __unused, void *ptr, unsigned short ptype __unused,
|
74
|
78
|
* @v filename File name
|
75
|
79
|
* @ret True Received a non-error response
|
76
|
80
|
* @ret False Received error response / no response
|
|
81
|
+ * @ret tftp_state::server::sin_port TFTP server UDP port
|
77
|
82
|
* @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
|
|
83
|
+ * @ret tftp_state::blksize Always #TFTP_DEFAULT_BLKSIZE
|
|
84
|
+ * @ret *reply The server's response, if any
|
|
85
|
+ * @err #PXENV_STATUS_TFTP_OPEN_TIMEOUT TFTP open timed out
|
|
86
|
+ * @err other As returned by udp_transmit()
|
|
87
|
+ * @err other As set by tftp_set_errno()
|
80
|
88
|
*
|
81
|
89
|
* Send a TFTP/TFTM/MTFTP RRQ (read request) to a TFTP server, and
|
82
|
90
|
* return the server's reply (which may be an OACK, DATA or ERROR
|
83
|
91
|
* packet). The server's reply will not be acknowledged, or processed
|
84
|
92
|
* in any way.
|
85
|
93
|
*
|
86
|
|
- * If tftp_state::server::sin_port is 0, the standard tftp server port
|
|
94
|
+ * If tftp_state::server::sin_port is 0, the standard TFTP server port
|
87
|
95
|
* (#TFTP_PORT) will be used.
|
88
|
96
|
*
|
89
|
97
|
* If tftp_state::client::sin_addr is not 0.0.0.0, it will be used as
|
|
@@ -121,6 +129,10 @@ int await_tftp ( int ival __unused, void *ptr, unsigned short ptype __unused,
|
121
|
129
|
* be assumed until the OACK packet is processed (by a subsequent call
|
122
|
130
|
* to tftp_process_opts()).
|
123
|
131
|
*
|
|
132
|
+ * tftp_state::server::sin_port will be set to the UDP port from which
|
|
133
|
+ * the server's response originated. This may or may not be the port
|
|
134
|
+ * to which the open request was sent.
|
|
135
|
+ *
|
124
|
136
|
* The options "blksize", "tsize" and "multicast" will always be
|
125
|
137
|
* appended to a TFTP open request. Servers that do not understand
|
126
|
138
|
* any of these options should simply ignore them.
|
|
@@ -129,9 +141,11 @@ int await_tftp ( int ival __unused, void *ptr, unsigned short ptype __unused,
|
129
|
141
|
* the caller is responsible for calling join_group() and
|
130
|
142
|
* leave_group() at appropriate times.
|
131
|
143
|
*
|
|
144
|
+ * If the response from the server is a TFTP ERROR packet, tftp_open()
|
|
145
|
+ * will return False and #errno will be set accordingly.
|
132
|
146
|
*/
|
133
|
147
|
int tftp_open ( struct tftp_state *state, const char *filename,
|
134
|
|
- union tftp_any **tftp ) {
|
|
148
|
+ union tftp_any **reply ) {
|
135
|
149
|
static unsigned short lport = 2000; /* local port */
|
136
|
150
|
int fixed_lport;
|
137
|
151
|
struct tftp_rrq rrq;
|
|
@@ -164,7 +178,7 @@ int tftp_open ( struct tftp_state *state, const char *filename,
|
164
|
178
|
state->blksize = TFTP_DEFAULT_BLKSIZE;
|
165
|
179
|
|
166
|
180
|
/* Nullify received packet pointer */
|
167
|
|
- *tftp = NULL;
|
|
181
|
+ *reply = NULL;
|
168
|
182
|
|
169
|
183
|
/* Transmit RRQ until we get a response */
|
170
|
184
|
for ( retry = 0 ; retry < MAX_TFTP_RETRIES ; retry++ ) {
|
|
@@ -186,7 +200,13 @@ int tftp_open ( struct tftp_state *state, const char *filename,
|
186
|
200
|
|
187
|
201
|
/* Wait for response */
|
188
|
202
|
if ( await_reply ( await_tftp, 0, state, timeout ) ) {
|
189
|
|
- *tftp = ( union tftp_any * ) &nic.packet[ETH_HLEN];
|
|
203
|
+ *reply = ( union tftp_any * ) &nic.packet[ETH_HLEN];
|
|
204
|
+ state->server.sin_port =
|
|
205
|
+ ntohs ( (*reply)->common.udp.dest );
|
|
206
|
+ if ( ntohs ( (*reply)->common.opcode ) == TFTP_ERROR ){
|
|
207
|
+ tftp_set_errno ( &(*reply)->error );
|
|
208
|
+ return 0;
|
|
209
|
+ }
|
190
|
210
|
return 1;
|
191
|
211
|
}
|
192
|
212
|
}
|
|
@@ -321,13 +341,14 @@ int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
|
321
|
341
|
* @v tftp_state::block Most recently received block number
|
322
|
342
|
* @ret True Acknowledgement packet was sent
|
323
|
343
|
* @ret False Acknowledgement packet was not sent
|
|
344
|
+ * @err other As returned by udp_transmit()
|
324
|
345
|
*
|
325
|
346
|
* Send a TFTP ACK packet for the most recently received block.
|
326
|
347
|
*
|
327
|
348
|
* This sends only a single ACK packet; it does not wait for the
|
328
|
349
|
* server's response.
|
329
|
350
|
*/
|
330
|
|
-int tftp_ack ( struct tftp_state *state ) {
|
|
351
|
+int tftp_ack_nowait ( struct tftp_state *state ) {
|
331
|
352
|
struct tftp_ack ack;
|
332
|
353
|
|
333
|
354
|
ack.opcode = htons ( TFTP_ACK );
|
|
@@ -337,6 +358,59 @@ int tftp_ack ( struct tftp_state *state ) {
|
337
|
358
|
sizeof ( ack ), &ack );
|
338
|
359
|
}
|
339
|
360
|
|
|
361
|
+/**
|
|
362
|
+ * Acknowledge a TFTP packet and wait for a response
|
|
363
|
+ *
|
|
364
|
+ * @v state TFTP transfer state
|
|
365
|
+ * @v tftp_state::server::sin_addr TFTP server IP address
|
|
366
|
+ * @v tftp_state::server::sin_port TFTP server UDP port
|
|
367
|
+ * @v tftp_state::client::sin_port Client UDP port
|
|
368
|
+ * @v tftp_state::block Most recently received block number
|
|
369
|
+ * @ret True Received a non-error response
|
|
370
|
+ * @ret False Received error response / no response
|
|
371
|
+ * @ret *reply The server's response, if any
|
|
372
|
+ * @err #PXENV_STATUS_TFTP_READ_TIMEOUT Timed out waiting for a response
|
|
373
|
+ * @err other As returned by tftp_ack_nowait()
|
|
374
|
+ * @err other As set by tftp_set_errno()
|
|
375
|
+ *
|
|
376
|
+ * Send a TFTP ACK packet for the most recently received data block,
|
|
377
|
+ * and keep transmitting this ACK until we get a response from the
|
|
378
|
+ * server (e.g. a new data block).
|
|
379
|
+ *
|
|
380
|
+ * If the response is a TFTP DATA packet, no processing is done.
|
|
381
|
+ * Specifically, the block number is not checked to ensure that this
|
|
382
|
+ * is indeed the next data block in the sequence, nor is
|
|
383
|
+ * tftp_state::block updated with the new block number.
|
|
384
|
+ *
|
|
385
|
+ * If the response from the server is a TFTP ERROR packet, tftp_open()
|
|
386
|
+ * will return False and #errno will be set accordingly.
|
|
387
|
+ */
|
|
388
|
+int tftp_ack ( struct tftp_state *state, union tftp_any **reply ) {
|
|
389
|
+ int retry;
|
|
390
|
+
|
|
391
|
+ *reply = NULL;
|
|
392
|
+ for ( retry = 0 ; retry < MAX_TFTP_RETRIES ; retry++ ) {
|
|
393
|
+ long timeout = rfc2131_sleep_interval ( TFTP_REXMT, retry );
|
|
394
|
+ /* ACK the last data block */
|
|
395
|
+ if ( ! tftp_ack_nowait ( state ) ) {
|
|
396
|
+ DBG ( "TFTP: could not send ACK: %m\n" );
|
|
397
|
+ return 0;
|
|
398
|
+ }
|
|
399
|
+ if ( await_reply ( await_tftp, 0, &state, timeout ) ) {
|
|
400
|
+ /* We received a reply */
|
|
401
|
+ *reply = ( union tftp_any * ) &nic.packet[ETH_HLEN];
|
|
402
|
+ if ( ntohs ( (*reply)->common.opcode ) == TFTP_ERROR ){
|
|
403
|
+ tftp_set_errno ( &(*reply)->error );
|
|
404
|
+ return 0;
|
|
405
|
+ }
|
|
406
|
+ return 1;
|
|
407
|
+ }
|
|
408
|
+ }
|
|
409
|
+ DBG ( "TFTP: ACK retries exceeded\n" );
|
|
410
|
+ errno = PXENV_STATUS_TFTP_READ_TIMEOUT;
|
|
411
|
+ return 0;
|
|
412
|
+}
|
|
413
|
+
|
340
|
414
|
/**
|
341
|
415
|
* Send a TFTP error
|
342
|
416
|
*
|
|
@@ -344,7 +418,7 @@ int tftp_ack ( struct tftp_state *state ) {
|
344
|
418
|
* @v tftp_state::server::sin_addr TFTP server IP address
|
345
|
419
|
* @v tftp_state::server::sin_port TFTP server UDP port
|
346
|
420
|
* @v tftp_state::client::sin_port Client UDP port
|
347
|
|
- * @v err TFTP error code
|
|
421
|
+ * @v errcode TFTP error code
|
348
|
422
|
* @v errmsg Descriptive error string
|
349
|
423
|
* @ret True Error packet was sent
|
350
|
424
|
* @ret False Error packet was not sent
|
|
@@ -352,14 +426,36 @@ int tftp_ack ( struct tftp_state *state ) {
|
352
|
426
|
* Send a TFTP ERROR packet back to the server to terminate the
|
353
|
427
|
* transfer.
|
354
|
428
|
*/
|
355
|
|
-int tftp_error ( struct tftp_state *state, int err, const char *errmsg ) {
|
|
429
|
+int tftp_error ( struct tftp_state *state, int errcode, const char *errmsg ) {
|
356
|
430
|
struct tftp_error error;
|
357
|
431
|
|
358
|
|
- DBG ( "TFTPCORE: aborting with error %d (%s)\n", err, errmsg );
|
|
432
|
+ DBG ( "TFTPCORE: aborting with error %d (%s)\n", errcode, errmsg );
|
359
|
433
|
error.opcode = htons ( TFTP_ERROR );
|
360
|
|
- error.errcode = htons ( err );
|
|
434
|
+ error.errcode = htons ( errcode );
|
361
|
435
|
strncpy ( error.errmsg, errmsg, sizeof ( error.errmsg ) );
|
362
|
436
|
return udp_transmit ( state->server.sin_addr.s_addr,
|
363
|
437
|
state->client.sin_port, state->server.sin_port,
|
364
|
438
|
sizeof ( error ), &error );
|
365
|
439
|
}
|
|
440
|
+
|
|
441
|
+/**
|
|
442
|
+ * Interpret a TFTP error
|
|
443
|
+ *
|
|
444
|
+ * @v error Pointer to a struct tftp_error
|
|
445
|
+ *
|
|
446
|
+ * Sets #errno based on the error code in a TFTP ERROR packet.
|
|
447
|
+ */
|
|
448
|
+void tftp_set_errno ( struct tftp_error *error ) {
|
|
449
|
+ static int errmap[] = {
|
|
450
|
+ [TFTP_ERR_FILE_NOT_FOUND] = PXENV_STATUS_TFTP_FILE_NOT_FOUND,
|
|
451
|
+ [TFTP_ERR_ACCESS_DENIED] = PXENV_STATUS_TFTP_ACCESS_VIOLATION,
|
|
452
|
+ [TFTP_ERR_ILLEGAL_OP] = PXENV_STATUS_TFTP_UNKNOWN_OPCODE,
|
|
453
|
+ };
|
|
454
|
+ unsigned int errcode = ntohs ( error->errcode );
|
|
455
|
+
|
|
456
|
+ errno = 0;
|
|
457
|
+ if ( errcode < ( sizeof(errmap) / sizeof(errmap[0]) ) )
|
|
458
|
+ errno = errmap[errcode];
|
|
459
|
+ if ( ! errno )
|
|
460
|
+ errno = PXENV_STATUS_TFTP_ERROR_OPCODE;
|
|
461
|
+}
|