|
@@ -9,19 +9,20 @@
|
9
|
9
|
/**
|
10
|
10
|
* await_reply() filter for TFTP packets
|
11
|
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::client::sin_addr Client multicast IP address, or 0.0.0.0
|
15
|
|
- * @v tftp_state::client::sin_port Client UDP port
|
16
|
|
- * @v ip IP header
|
17
|
|
- * @v udp UDP header
|
18
|
|
- * @ret True This is our TFTP packet
|
19
|
|
- * @ret False This is not one of our 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
|
|
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
|
20
|
21
|
*
|
21
|
22
|
* Wait for a TFTP packet that is part of the current connection
|
22
|
23
|
* (i.e. comes from the TFTP server, has the correct destination port,
|
23
|
|
- * and is addressed either to our IP address or to our multicast
|
24
|
|
- * listening address).
|
|
24
|
+ * and is addressed either to our IP address and UDP port, or to our
|
|
25
|
+ * multicast listening address and UDP port).
|
25
|
26
|
*
|
26
|
27
|
* Use await_tftp() in code such as
|
27
|
28
|
*
|
|
@@ -49,39 +50,42 @@ static int await_tftp ( int ival __unused, void *ptr,
|
49
|
50
|
ip->src.s_addr, state->server.sin_addr.s_addr );
|
50
|
51
|
return 0;
|
51
|
52
|
}
|
52
|
|
- /* Packet must be addressed to the correct UDP port */
|
53
|
|
- if ( ntohs ( udp->dest ) != state->client.sin_port ) {
|
54
|
|
- DBG2 ( "TFTPCORE: to UDP port %d, not to TFTP port %d\n",
|
55
|
|
- ntohs ( udp->dest ), state->client.sin_port );
|
56
|
|
- return 0;
|
|
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;
|
57
|
59
|
}
|
58
|
|
- /* Packet must be addressed to us, or to our multicast
|
59
|
|
- * listening address (if we have one).
|
|
60
|
+ /* Packet may be addressed to our multicast IP address and UDP
|
|
61
|
+ * port, if we have one
|
60
|
62
|
*/
|
61
|
|
- if ( ! ( ( ip->dest.s_addr == arptable[ARP_CLIENT].ipaddr.s_addr ) ||
|
62
|
|
- ( ( state->client.sin_addr.s_addr ) &&
|
63
|
|
- ( ip->dest.s_addr == state->client.sin_addr.s_addr ) ) ) ) {
|
64
|
|
- DBG2 ( "TFTPCORE: to %@, not to %@ (or %@)\n",
|
65
|
|
- ip->dest.s_addr, arptable[ARP_CLIENT].ipaddr.s_addr,
|
66
|
|
- state->client.sin_addr.s_addr );
|
67
|
|
- return 0;
|
|
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;
|
68
|
67
|
}
|
69
|
|
- return 1;
|
|
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;
|
70
|
73
|
}
|
71
|
74
|
|
72
|
75
|
/**
|
73
|
76
|
* Retrieve a TFTP packet
|
74
|
77
|
*
|
75
|
|
- * @v state TFTP transfer state
|
76
|
|
- * @v tftp_state::server::sin_addr TFTP server IP address
|
77
|
|
- * @v tftp_state::client::sin_addr Client multicast IP address, or 0.0.0.0
|
78
|
|
- * @v tftp_state::client::sin_port Client UDP port
|
79
|
|
- * @v timeout Time to wait for a response
|
80
|
|
- * @ret True Received a non-error response
|
81
|
|
- * @ret False Received error response / no response
|
82
|
|
- * @ret *reply The server's response, if any
|
83
|
|
- * @err #PXENV_STATUS_TFTP_READ_TIMEOUT No response received in time
|
84
|
|
- * @err other As set by tftp_set_errno()
|
|
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()
|
85
|
89
|
*
|
86
|
90
|
* Retrieve the next packet sent by the TFTP server, if any is sent
|
87
|
91
|
* within the specified timeout period. The packet is returned via
|
|
@@ -121,15 +125,16 @@ int tftp_get ( struct tftp_state *state, long timeout,
|
121
|
125
|
* @v state TFTP transfer state
|
122
|
126
|
* @v tftp_state::server::sin_addr TFTP server IP address
|
123
|
127
|
* @v tftp_state::server::sin_port TFTP server UDP port, or 0
|
124
|
|
- * @v tftp_state::client::sin_addr Client multicast IP address, or 0.0.0.0
|
125
|
|
- * @v tftp_state::client::sin_port Client 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
|
126
|
131
|
* @v tftp_state::blksize Requested blksize, or 0
|
127
|
132
|
* @v filename File name
|
128
|
133
|
* @v multicast Enable/disable rfc2090 multicast TFTP
|
129
|
134
|
* @ret True Received a non-error response
|
130
|
135
|
* @ret False Received error response / no response
|
131
|
136
|
* @ret tftp_state::server::sin_port TFTP server UDP port
|
132
|
|
- * @ret tftp_state::client::sin_port Client UDP port
|
|
137
|
+ * @ret tftp_state::lport Client UDP port
|
133
|
138
|
* @ret tftp_state::blksize Always #TFTP_DEFAULT_BLKSIZE
|
134
|
139
|
* @ret *reply The server's response, if any
|
135
|
140
|
* @err #PXENV_STATUS_TFTP_OPEN_TIMEOUT TFTP open timed out
|
|
@@ -144,32 +149,35 @@ int tftp_get ( struct tftp_state *state, long timeout,
|
144
|
149
|
* If tftp_state::server::sin_port is 0, the standard TFTP server port
|
145
|
150
|
* (#TFTP_PORT) will be used.
|
146
|
151
|
*
|
147
|
|
- * If tftp_state::client::sin_addr is not 0.0.0.0, it will be used as
|
148
|
|
- * a multicast listening address for replies from the TFTP server.
|
149
|
|
- *
|
150
|
|
- * If tftp_state::client::sin_port is 0, the standard mechanism of
|
|
152
|
+ * If tftp_state::lport is 0, the standard mechanism of
|
151
|
153
|
* using a new, unique port number for each TFTP request will be used.
|
152
|
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
|
+ *
|
153
|
159
|
* For the various different types of TFTP server, you should treat
|
154
|
|
- * tftp_state::client as follows:
|
155
|
|
- *
|
156
|
|
- * - Standard TFTP server: set tftp_state::client::sin_addr to
|
157
|
|
- * 0.0.0.0 and tftp_state::client::sin_port to 0. tftp_open()
|
158
|
|
- * will set tftp_state::client::sin_port to the assigned local UDP
|
159
|
|
- * port.
|
160
|
|
- *
|
161
|
|
- * - TFTM server: set tftp_state::client::sin_addr to 0.0.0.0 and
|
162
|
|
- * tftp_state::client::sin_port to 0. tftp_open() will set
|
163
|
|
- * tftp_state::client::sin_port to the assigned local UDP port.
|
164
|
|
- * (Your call to tftp_process_opts() will then overwrite both
|
165
|
|
- * tftp_state::client::sin_addr and tftp_state::client::sin_port
|
166
|
|
- * with the values return in the OACK packet.)
|
167
|
|
- *
|
168
|
|
- * - MTFTP server: set tftp_state::client::sin_addr to the client
|
169
|
|
- * multicast address and tftp_state::client::sin_port to the
|
170
|
|
- * client multicast port (both of which must be previously known,
|
171
|
|
- * e.g. provided by a DHCP server). tftp_open() will not alter
|
172
|
|
- * these values.
|
|
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.
|
173
|
181
|
*
|
174
|
182
|
* If tftp_state::blksize is 0, the maximum blocksize
|
175
|
183
|
* (#TFTP_MAX_BLKSIZE) will be requested.
|
|
@@ -216,7 +224,7 @@ int tftp_open ( struct tftp_state *state, const char *filename,
|
216
|
224
|
state->server.sin_port = TFTP_PORT;
|
217
|
225
|
|
218
|
226
|
/* Determine whether or not to use lport */
|
219
|
|
- fixed_lport = state->client.sin_port;
|
|
227
|
+ fixed_lport = state->lport;
|
220
|
228
|
|
221
|
229
|
/* Set up RRQ */
|
222
|
230
|
rrq.opcode = htons ( TFTP_RRQ );
|
|
@@ -240,15 +248,14 @@ int tftp_open ( struct tftp_state *state, const char *filename,
|
240
|
248
|
|
241
|
249
|
/* Set client UDP port, if not already fixed */
|
242
|
250
|
if ( ! fixed_lport )
|
243
|
|
- state->client.sin_port = ++lport;
|
|
251
|
+ state->lport = ++lport;
|
244
|
252
|
|
245
|
253
|
/* Send the RRQ */
|
246
|
254
|
DBG ( "TFTPCORE: requesting %@:%d/%s from port %d\n",
|
247
|
255
|
state->server.sin_addr.s_addr, state->server.sin_port,
|
248
|
|
- rrq.data, state->client.sin_port );
|
|
256
|
+ rrq.data, state->lport );
|
249
|
257
|
if ( ! udp_transmit ( state->server.sin_addr.s_addr,
|
250
|
|
- state->client.sin_port,
|
251
|
|
- state->server.sin_port,
|
|
258
|
+ state->lport, state->server.sin_port,
|
252
|
259
|
rrqlen, &rrq ) )
|
253
|
260
|
return 0;
|
254
|
261
|
|
|
@@ -282,8 +289,8 @@ int tftp_open ( struct tftp_state *state, const char *filename,
|
282
|
289
|
* @ret False Options were not processed successfully
|
283
|
290
|
* @ret tftp_state::blksize Negotiated blksize
|
284
|
291
|
* @ret tftp_state::tsize File size (if known), or 0
|
285
|
|
- * @ret tftp_state::client::sin_addr Client multicast IP address, or 0.0.0.0
|
286
|
|
- * @ret tftp_state::client::sin_port Client UDP port
|
|
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
|
287
|
294
|
* @ret tftp_state::master Client is master
|
288
|
295
|
* @err EINVAL An invalid option value was encountered
|
289
|
296
|
*
|
|
@@ -338,6 +345,7 @@ int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
|
338
|
345
|
p++;
|
339
|
346
|
DBG ( "TFTPCORE: got tsize %d\n", state->tsize );
|
340
|
347
|
} else if ( strcasecmp ( "multicast", p ) == 0 ) {
|
|
348
|
+ p += 10;
|
341
|
349
|
char *e = strchr ( p, ',' );
|
342
|
350
|
if ( ( ! e ) || ( e >= end ) ) {
|
343
|
351
|
DBG ( "TFTPCORE: malformed multicast field "
|
|
@@ -345,13 +353,14 @@ int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
|
345
|
353
|
return 0;
|
346
|
354
|
}
|
347
|
355
|
/* IP address may be missing, in which case we
|
348
|
|
- * should leave state->client.sin_addr
|
|
356
|
+ * should leave state->multicast.sin_addr
|
349
|
357
|
* unaltered.
|
350
|
358
|
*/
|
351
|
359
|
if ( e != p ) {
|
352
|
360
|
int rc;
|
353
|
361
|
*e = '\0';
|
354
|
|
- rc = inet_aton ( p, &state->client.sin_addr );
|
|
362
|
+ rc = inet_aton ( p,
|
|
363
|
+ &state->multicast.sin_addr );
|
355
|
364
|
*e = ',';
|
356
|
365
|
if ( ! rc ) {
|
357
|
366
|
DBG ( "TFTPCORE: malformed multicast "
|
|
@@ -362,15 +371,15 @@ int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
|
362
|
371
|
p = e + 1;
|
363
|
372
|
/* UDP port may also be missing */
|
364
|
373
|
if ( *p != ',' ) {
|
365
|
|
- state->client.sin_port = strtoul ( p, &p, 10 );
|
|
374
|
+ state->multicast.sin_port
|
|
375
|
+ = strtoul ( p, &p, 10 );
|
366
|
376
|
if ( *p != ',' ) {
|
367
|
377
|
DBG ( "TFTPCORE: garbage \"%s\" "
|
368
|
378
|
"after multicast port\n", p );
|
369
|
379
|
return 0;
|
370
|
380
|
}
|
371
|
|
- } else {
|
372
|
|
- p++;
|
373
|
381
|
}
|
|
382
|
+ p++;
|
374
|
383
|
/* "Master Client" must always be present */
|
375
|
384
|
state->master = strtoul ( p, &p, 10 );
|
376
|
385
|
if ( *p ) {
|
|
@@ -380,8 +389,8 @@ int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
|
380
|
389
|
}
|
381
|
390
|
p++;
|
382
|
391
|
DBG ( "TFTPCORE: got multicast %@:%d (%s)\n",
|
383
|
|
- state->client.sin_addr.s_addr,
|
384
|
|
- state->client.sin_port,
|
|
392
|
+ state->multicast.sin_addr.s_addr,
|
|
393
|
+ state->multicast.sin_port,
|
385
|
394
|
( state->master ? "master" : "not master" ) );
|
386
|
395
|
} else {
|
387
|
396
|
DBG ( "TFTPCORE: unknown option \"%s\"\n", p );
|
|
@@ -404,7 +413,7 @@ int tftp_process_opts ( struct tftp_state *state, struct tftp_oack *oack ) {
|
404
|
413
|
* @v state TFTP transfer state
|
405
|
414
|
* @v tftp_state::server::sin_addr TFTP server IP address
|
406
|
415
|
* @v tftp_state::server::sin_port TFTP server UDP port
|
407
|
|
- * @v tftp_state::client::sin_port Client UDP port
|
|
416
|
+ * @v tftp_state::lport Client UDP port
|
408
|
417
|
* @v tftp_state::block Most recently received block number
|
409
|
418
|
* @ret True Acknowledgement packet was sent
|
410
|
419
|
* @ret False Acknowledgement packet was not sent
|
|
@@ -422,7 +431,7 @@ int tftp_ack_nowait ( struct tftp_state *state ) {
|
422
|
431
|
ack.opcode = htons ( TFTP_ACK );
|
423
|
432
|
ack.block = htons ( state->block );
|
424
|
433
|
return udp_transmit ( state->server.sin_addr.s_addr,
|
425
|
|
- state->client.sin_port, state->server.sin_port,
|
|
434
|
+ state->lport, state->server.sin_port,
|
426
|
435
|
sizeof ( ack ), &ack );
|
427
|
436
|
}
|
428
|
437
|
|
|
@@ -432,7 +441,7 @@ int tftp_ack_nowait ( struct tftp_state *state ) {
|
432
|
441
|
* @v state TFTP transfer state
|
433
|
442
|
* @v tftp_state::server::sin_addr TFTP server IP address
|
434
|
443
|
* @v tftp_state::server::sin_port TFTP server UDP port
|
435
|
|
- * @v tftp_state::client::sin_port Client UDP port
|
|
444
|
+ * @v tftp_state::lport Client UDP port
|
436
|
445
|
* @v tftp_state::block Most recently received block number
|
437
|
446
|
* @ret True Received a non-error response
|
438
|
447
|
* @ret False Received error response / no response
|
|
@@ -484,7 +493,7 @@ int tftp_ack ( struct tftp_state *state, union tftp_any **reply ) {
|
484
|
493
|
* @v state TFTP transfer state
|
485
|
494
|
* @v tftp_state::server::sin_addr TFTP server IP address
|
486
|
495
|
* @v tftp_state::server::sin_port TFTP server UDP port
|
487
|
|
- * @v tftp_state::client::sin_port Client UDP port
|
|
496
|
+ * @v tftp_state::lport Client UDP port
|
488
|
497
|
* @v errcode TFTP error code
|
489
|
498
|
* @v errmsg Descriptive error string, or NULL
|
490
|
499
|
* @ret True Error packet was sent
|
|
@@ -505,7 +514,7 @@ int tftp_error ( struct tftp_state *state, int errcode, const char *errmsg ) {
|
505
|
514
|
strncpy ( error.errmsg, errmsg ? errmsg : strerror ( errno ),
|
506
|
515
|
sizeof ( error.errmsg ) );
|
507
|
516
|
return udp_transmit ( state->server.sin_addr.s_addr,
|
508
|
|
- state->client.sin_port, state->server.sin_port,
|
|
517
|
+ state->lport, state->server.sin_port,
|
509
|
518
|
sizeof ( error ), &error );
|
510
|
519
|
}
|
511
|
520
|
|