|
@@ -1,541 +0,0 @@
|
1
|
|
-#include "tftp.h"
|
2
|
|
-#include "old_tcp.h" /* for struct tcphdr */
|
3
|
|
-#include "errno.h"
|
4
|
|
-#include "etherboot.h"
|
5
|
|
-#include "tftpcore.h"
|
6
|
|
-
|
7
|
|
-/** @file */
|
8
|
|
-
|
9
|
|
-/**
|
10
|
|
- * await_reply() filter for TFTP packets
|
11
|
|
- *
|
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
|
17
|
|
- * @v ip IP header
|
18
|
|
- * @v udp UDP header
|
19
|
|
- * @ret True This is our TFTP packet
|
20
|
|
- * @ret False This is not one of our TFTP packets
|
21
|
|
- *
|
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).
|
26
|
|
- *
|
27
|
|
- * Use await_tftp() in code such as
|
28
|
|
- *
|
29
|
|
- * @code
|
30
|
|
- *
|
31
|
|
- * if ( await_reply ( await_tftp, 0, &tftp_state, timeout ) ) {
|
32
|
|
- * ...
|
33
|
|
- * }
|
34
|
|
- *
|
35
|
|
- * @endcode
|
36
|
|
- */
|
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;
|
41
|
|
-
|
42
|
|
- /* Must have valid UDP (and, therefore, also IP) headers */
|
43
|
|
- if ( ! udp ) {
|
44
|
|
- DBG2 ( "TFTPCORE: not UDP\n" );
|
45
|
|
- return 0;
|
46
|
|
- }
|
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 );
|
51
|
|
- return 0;
|
52
|
|
- }
|
53
|
|
- /* Packet may be addressed to our IP address and unicast UDP
|
54
|
|
- * port
|
55
|
|
- */
|
56
|
|
- if ( ( ip->dest.s_addr == arptable[ARP_CLIENT].ipaddr.s_addr ) &&
|
57
|
|
- ( ntohs ( udp->dest ) == state->lport ) ) {
|
58
|
|
- return 1;
|
59
|
|
- }
|
60
|
|
- /* Packet may be addressed to our multicast IP address and UDP
|
61
|
|
- * port, if we have one
|
62
|
|
- */
|
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 ) ) {
|
66
|
|
- return 1;
|
67
|
|
- }
|
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 );
|
72
|
|
- return 0;
|
73
|
|
-}
|
74
|
|
-
|
75
|
|
-/**
|
76
|
|
- * Retrieve a TFTP packet
|
77
|
|
- *
|
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()
|
89
|
|
- *
|
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.
|
94
|
|
- *
|
95
|
|
- * If the response from the server is a TFTP ERROR packet, tftp_get()
|
96
|
|
- * will return False and #errno will be set accordingly.
|
97
|
|
- *
|
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.
|
101
|
|
- */
|
102
|
|
-int tftp_get ( struct tftp_state *state, long timeout,
|
103
|
|
- union tftp_any **reply ) {
|
104
|
|
-
|
105
|
|
- *reply = NULL;
|
106
|
|
-
|
107
|
|
- if ( ! await_reply ( await_tftp, 0, state, timeout ) ) {
|
108
|
|
- errno = PXENV_STATUS_TFTP_READ_TIMEOUT;
|
109
|
|
- return 0;
|
110
|
|
- }
|
111
|
|
-
|
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 );
|
117
|
|
- return 0;
|
118
|
|
- }
|
119
|
|
- return 1;
|
120
|
|
-}
|
121
|
|
-
|
122
|
|
-/**
|
123
|
|
- * Issue a TFTP open request (RRQ)
|
124
|
|
- *
|
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()
|
143
|
|
- *
|
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
|
147
|
|
- * in any way.
|
148
|
|
- *
|
149
|
|
- * If tftp_state::server::sin_port is 0, the standard TFTP server port
|
150
|
|
- * (#TFTP_PORT) will be used.
|
151
|
|
- *
|
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.
|
154
|
|
- *
|
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.
|
158
|
|
- *
|
159
|
|
- * For the various different types of TFTP server, you should treat
|
160
|
|
- * tftp_state::lport and tftp_state::multicast as follows:
|
161
|
|
- *
|
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.
|
166
|
|
- *
|
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
|
174
|
|
- * the OACK packet.)
|
175
|
|
- *
|
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.
|
181
|
|
- *
|
182
|
|
- * If tftp_state::blksize is 0, the maximum blocksize
|
183
|
|
- * (#TFTP_MAX_BLKSIZE) will be requested.
|
184
|
|
- *
|
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()).
|
189
|
|
- *
|
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.
|
193
|
|
- *
|
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.
|
198
|
|
- *
|
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.
|
202
|
|
- *
|
203
|
|
- * If the response from the server is a TFTP ERROR packet, tftp_open()
|
204
|
|
- * will return False and #errno will be set accordingly.
|
205
|
|
- */
|
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 */
|
209
|
|
- int fixed_lport;
|
210
|
|
- struct tftp_rrq rrq;
|
211
|
|
- char *p;
|
212
|
|
- unsigned int rrqlen;
|
213
|
|
- int retry;
|
214
|
|
-
|
215
|
|
- /* Flush receive queue */
|
216
|
|
- rx_qdrain();
|
217
|
|
-
|
218
|
|
- /* Default to blksize of TFTP_MAX_BLKSIZE if none specified */
|
219
|
|
- if ( ! state->blksize )
|
220
|
|
- state->blksize = TFTP_MAX_BLKSIZE;
|
221
|
|
-
|
222
|
|
- /* Use default TFTP server port if none specified */
|
223
|
|
- if ( ! state->server.sin_port )
|
224
|
|
- state->server.sin_port = TFTP_PORT;
|
225
|
|
-
|
226
|
|
- /* Determine whether or not to use lport */
|
227
|
|
- fixed_lport = state->lport;
|
228
|
|
-
|
229
|
|
- /* Set up RRQ */
|
230
|
|
- rrq.opcode = htons ( TFTP_RRQ );
|
231
|
|
- p = rrq.data;
|
232
|
|
- p += sprintf ( p, "%s%coctet%cblksize%c%d%ctsize%c0",
|
233
|
|
- filename, 0, 0, 0, state->blksize, 0, 0 ) + 1;
|
234
|
|
- if ( multicast ) {
|
235
|
|
- p += sprintf ( p, "multicast%c", 0 ) + 1;
|
236
|
|
- }
|
237
|
|
- rrqlen = ( p - ( char * ) &rrq );
|
238
|
|
-
|
239
|
|
- /* Set negotiated blksize to default value */
|
240
|
|
- state->blksize = TFTP_DEFAULT_BLKSIZE;
|
241
|
|
-
|
242
|
|
- /* Nullify received packet pointer */
|
243
|
|
- *reply = NULL;
|
244
|
|
-
|
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 );
|
248
|
|
-
|
249
|
|
- /* Set client UDP port, if not already fixed */
|
250
|
|
- if ( ! fixed_lport )
|
251
|
|
- state->lport = ++lport;
|
252
|
|
-
|
253
|
|
- /* Send the RRQ */
|
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,
|
259
|
|
- rrqlen, &rrq ) )
|
260
|
|
- return 0;
|
261
|
|
-
|
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 );
|
270
|
|
- return 1;
|
271
|
|
- }
|
272
|
|
- if ( *reply ) {
|
273
|
|
- /* We got an error response; abort */
|
274
|
|
- return 0;
|
275
|
|
- }
|
276
|
|
- }
|
277
|
|
-
|
278
|
|
- DBG ( "TFTPCORE: open request timed out\n" );
|
279
|
|
- errno = PXENV_STATUS_TFTP_OPEN_TIMEOUT;
|
280
|
|
- return 0;
|
281
|
|
-}
|
282
|
|
-
|
283
|
|
-/**
|
284
|
|
- * Process a TFTP OACK packet
|
285
|
|
- *
|
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
|
296
|
|
- *
|
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.
|
301
|
|
- *
|
302
|
|
- * Where an option is not present in the OACK packet, the
|
303
|
|
- * corresponding field(s) in #state will be left unaltered.
|
304
|
|
- *
|
305
|
|
- * Calling tftp_process_opts() does not send an acknowledgement for
|
306
|
|
- * the OACK packet; this is the responsibility of the caller.
|
307
|
|
- *
|
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
|
312
|
|
- * worry about this.
|
313
|
|
- */
|
314
|
|
-int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
|
315
|
|
- const char *p;
|
316
|
|
- const char *end;
|
317
|
|
-
|
318
|
|
- DBG ( "TFTPCORE: processing OACK\n" );
|
319
|
|
-
|
320
|
|
- /* End of options */
|
321
|
|
- end = ( ( char * ) &oack->udp ) + ntohs ( oack->udp.len );
|
322
|
|
-
|
323
|
|
- /* Only possible error */
|
324
|
|
- errno = EINVAL;
|
325
|
|
-
|
326
|
|
- for ( p = oack->data ; p < end ; ) {
|
327
|
|
- if ( strcasecmp ( "blksize", p ) == 0 ) {
|
328
|
|
- p += 8;
|
329
|
|
- state->blksize = strtoul ( p, &p, 10 );
|
330
|
|
- if ( *p ) {
|
331
|
|
- DBG ( "TFTPCORE: garbage \"%s\" "
|
332
|
|
- "after blksize\n", p );
|
333
|
|
- return 0;
|
334
|
|
- }
|
335
|
|
- p++;
|
336
|
|
- DBG ( "TFTPCORE: got blksize %d\n", state->blksize );
|
337
|
|
- } else if ( strcasecmp ( "tsize", p ) == 0 ) {
|
338
|
|
- p += 6;
|
339
|
|
- state->tsize = strtoul ( p, &p, 10 );
|
340
|
|
- if ( *p ) {
|
341
|
|
- DBG ( "TFTPCORE: garbage \"%s\" "
|
342
|
|
- "after tsize\n", p );
|
343
|
|
- return 0;
|
344
|
|
- }
|
345
|
|
- p++;
|
346
|
|
- DBG ( "TFTPCORE: got tsize %d\n", state->tsize );
|
347
|
|
- } else if ( strcasecmp ( "multicast", p ) == 0 ) {
|
348
|
|
- p += 10;
|
349
|
|
- char *e = strchr ( p, ',' );
|
350
|
|
- if ( ( ! e ) || ( e >= end ) ) {
|
351
|
|
- DBG ( "TFTPCORE: malformed multicast field "
|
352
|
|
- "\"%s\"\n", p );
|
353
|
|
- return 0;
|
354
|
|
- }
|
355
|
|
- /* IP address may be missing, in which case we
|
356
|
|
- * should leave state->multicast.sin_addr
|
357
|
|
- * unaltered.
|
358
|
|
- */
|
359
|
|
- if ( e != p ) {
|
360
|
|
- int rc;
|
361
|
|
- *e = '\0';
|
362
|
|
- rc = inet_aton ( p,
|
363
|
|
- &state->multicast.sin_addr );
|
364
|
|
- *e = ',';
|
365
|
|
- if ( ! rc ) {
|
366
|
|
- DBG ( "TFTPCORE: malformed multicast "
|
367
|
|
- "IP address \"%s\"\n", p );
|
368
|
|
- return 0;
|
369
|
|
- }
|
370
|
|
- }
|
371
|
|
- p = e + 1;
|
372
|
|
- /* UDP port may also be missing */
|
373
|
|
- if ( *p != ',' ) {
|
374
|
|
- state->multicast.sin_port
|
375
|
|
- = strtoul ( p, &p, 10 );
|
376
|
|
- if ( *p != ',' ) {
|
377
|
|
- DBG ( "TFTPCORE: garbage \"%s\" "
|
378
|
|
- "after multicast port\n", p );
|
379
|
|
- return 0;
|
380
|
|
- }
|
381
|
|
- }
|
382
|
|
- p++;
|
383
|
|
- /* "Master Client" must always be present */
|
384
|
|
- state->master = strtoul ( p, &p, 10 );
|
385
|
|
- if ( *p ) {
|
386
|
|
- DBG ( "TFTPCORE: garbage \"%s\" "
|
387
|
|
- "after multicast mc\n", p );
|
388
|
|
- return 0;
|
389
|
|
- }
|
390
|
|
- 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" ) );
|
395
|
|
- } else {
|
396
|
|
- DBG ( "TFTPCORE: unknown option \"%s\"\n", p );
|
397
|
|
- p += strlen ( p ) + 1; /* skip option name */
|
398
|
|
- p += strlen ( p ) + 1; /* skip option value */
|
399
|
|
- }
|
400
|
|
- }
|
401
|
|
-
|
402
|
|
- if ( p > end ) {
|
403
|
|
- DBG ( "TFTPCORE: overran options in OACK\n" );
|
404
|
|
- return 0;
|
405
|
|
- }
|
406
|
|
-
|
407
|
|
- return 1;
|
408
|
|
-}
|
409
|
|
-
|
410
|
|
-/**
|
411
|
|
- * Acknowledge a TFTP packet
|
412
|
|
- *
|
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()
|
421
|
|
- *
|
422
|
|
- * Send a TFTP ACK packet for the most recently received block.
|
423
|
|
- *
|
424
|
|
- * This sends only a single ACK packet; it does not wait for the
|
425
|
|
- * server's response.
|
426
|
|
- */
|
427
|
|
-int tftp_ack_nowait ( struct tftp_state *state ) {
|
428
|
|
- struct tftp_ack ack;
|
429
|
|
-
|
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 );
|
436
|
|
-}
|
437
|
|
-
|
438
|
|
-/**
|
439
|
|
- * Acknowledge a TFTP packet and wait for a response
|
440
|
|
- *
|
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()
|
452
|
|
- *
|
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).
|
456
|
|
- *
|
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.
|
461
|
|
- *
|
462
|
|
- * If the response from the server is a TFTP ERROR packet, tftp_open()
|
463
|
|
- * will return False and #errno will be set accordingly.
|
464
|
|
- */
|
465
|
|
-int tftp_ack ( struct tftp_state *state, union tftp_any **reply ) {
|
466
|
|
- int retry;
|
467
|
|
-
|
468
|
|
- *reply = NULL;
|
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" );
|
474
|
|
- return 0;
|
475
|
|
- }
|
476
|
|
- if ( tftp_get ( state, timeout, reply ) ) {
|
477
|
|
- /* We got a non-error response */
|
478
|
|
- return 1;
|
479
|
|
- }
|
480
|
|
- if ( *reply ) {
|
481
|
|
- /* We got an error response */
|
482
|
|
- return 0;
|
483
|
|
- }
|
484
|
|
- }
|
485
|
|
- DBG ( "TFTP: timed out during read\n" );
|
486
|
|
- errno = PXENV_STATUS_TFTP_READ_TIMEOUT;
|
487
|
|
- return 0;
|
488
|
|
-}
|
489
|
|
-
|
490
|
|
-/**
|
491
|
|
- * Send a TFTP error
|
492
|
|
- *
|
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
|
501
|
|
- *
|
502
|
|
- * Send a TFTP ERROR packet back to the server to terminate the
|
503
|
|
- * transfer.
|
504
|
|
- *
|
505
|
|
- * If #errmsg is NULL, the current error message string as returned by
|
506
|
|
- * strerror(errno) will be used as the error text.
|
507
|
|
- */
|
508
|
|
-int tftp_error ( struct tftp_state *state, int errcode, const char *errmsg ) {
|
509
|
|
- struct tftp_error error;
|
510
|
|
-
|
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 );
|
519
|
|
-}
|
520
|
|
-
|
521
|
|
-/**
|
522
|
|
- * Interpret a TFTP error
|
523
|
|
- *
|
524
|
|
- * @v error Pointer to a struct tftp_error
|
525
|
|
- *
|
526
|
|
- * Sets #errno based on the error code in a TFTP ERROR packet.
|
527
|
|
- */
|
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,
|
533
|
|
- };
|
534
|
|
- unsigned int errcode = ntohs ( error->errcode );
|
535
|
|
-
|
536
|
|
- errno = 0;
|
537
|
|
- if ( errcode < ( sizeof(errmap) / sizeof(errmap[0]) ) )
|
538
|
|
- errno = errmap[errcode];
|
539
|
|
- if ( ! errno )
|
540
|
|
- errno = PXENV_STATUS_TFTP_ERROR_OPCODE;
|
541
|
|
-}
|