|
@@ -25,10 +25,20 @@
|
25
|
25
|
* (i.e. comes from the TFTP server, has the correct destination port,
|
26
|
26
|
* and is addressed either to our IP address or to our multicast
|
27
|
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
|
28
|
38
|
*/
|
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 ) {
|
|
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 ) {
|
32
|
42
|
struct tftp_state *state = ptr;
|
33
|
43
|
|
34
|
44
|
/* Must have valid UDP (and, therefore, also IP) headers */
|
|
@@ -55,13 +65,13 @@ static int await_tftp ( int ival __unused, void *ptr,
|
55
|
65
|
/**
|
56
|
66
|
* Issue a TFTP open request (RRQ)
|
57
|
67
|
*
|
58
|
|
- * @v filename File name
|
59
|
68
|
* @v state TFTP transfer state
|
60
|
69
|
* @v tftp_state::server::sin_addr TFTP server IP address
|
61
|
70
|
* @v tftp_state::server::sin_port TFTP server UDP port, or 0
|
62
|
71
|
* @v tftp_state::client::sin_addr Client multicast IP address, or 0.0.0.0
|
63
|
72
|
* @v tftp_state::client::sin_port Client UDP port, or 0
|
64
|
73
|
* @v tftp_state::blksize Requested blksize, or 0
|
|
74
|
+ * @v filename File name
|
65
|
75
|
* @ret True Received a non-error response
|
66
|
76
|
* @ret False Received error response / no response
|
67
|
77
|
* @ret tftp_state::client::sin_port Client UDP port
|
|
@@ -120,7 +130,7 @@ static int await_tftp ( int ival __unused, void *ptr,
|
120
|
130
|
* leave_group() at appropriate times.
|
121
|
131
|
*
|
122
|
132
|
*/
|
123
|
|
-int tftp_open ( const char *filename, struct tftp_state *state,
|
|
133
|
+int tftp_open ( struct tftp_state *state, const char *filename,
|
124
|
134
|
union tftp_any **tftp ) {
|
125
|
135
|
static unsigned short lport = 2000; /* local port */
|
126
|
136
|
int fixed_lport;
|
|
@@ -165,6 +175,9 @@ int tftp_open ( const char *filename, struct tftp_state *state,
|
165
|
175
|
state->client.sin_port = ++lport;
|
166
|
176
|
|
167
|
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 );
|
168
|
181
|
if ( ! udp_transmit ( state->server.sin_addr.s_addr,
|
169
|
182
|
state->client.sin_port,
|
170
|
183
|
state->server.sin_port,
|
|
@@ -185,8 +198,8 @@ int tftp_open ( const char *filename, struct tftp_state *state,
|
185
|
198
|
/**
|
186
|
199
|
* Process a TFTP OACK packet
|
187
|
200
|
*
|
188
|
|
- * @v oack The TFTP OACK packet
|
189
|
201
|
* @v state TFTP transfer state
|
|
202
|
+ * @v oack The TFTP OACK packet
|
190
|
203
|
* @ret True Options were processed successfully
|
191
|
204
|
* @ret False Options were not processed successfully
|
192
|
205
|
* @ret tftp_state::blksize Negotiated blksize
|
|
@@ -213,7 +226,7 @@ int tftp_open ( const char *filename, struct tftp_state *state,
|
213
|
226
|
* #TFTP_DEFAULT_BLKSIZE before returning, you probably don't need to
|
214
|
227
|
* worry about this.
|
215
|
228
|
*/
|
216
|
|
-int tftp_process_opts ( struct tftp_oack *oack, struct tftp_state *state ) {
|
|
229
|
+int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
|
217
|
230
|
const char *p;
|
218
|
231
|
const char *end;
|
219
|
232
|
|
|
@@ -297,3 +310,56 @@ int tftp_process_opts ( struct tftp_oack *oack, struct tftp_state *state ) {
|
297
|
310
|
|
298
|
311
|
return 1;
|
299
|
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
|
+}
|