|
@@ -74,24 +74,23 @@ struct tftp_request {
|
74
|
74
|
* "tsize" option, this value will be zero.
|
75
|
75
|
*/
|
76
|
76
|
unsigned long tsize;
|
77
|
|
- /** Multicast address
|
78
|
|
- *
|
79
|
|
- * This is the destination address for multicast data
|
80
|
|
- * transmissions.
|
81
|
|
- */
|
82
|
|
- struct sockaddr_tcpip multicast;
|
83
|
|
- /** Master client
|
|
77
|
+
|
|
78
|
+ /** Server port
|
84
|
79
|
*
|
85
|
|
- * True if this is the client responsible for sending ACKs.
|
|
80
|
+ * This is the port to which RRQ packets are sent.
|
86
|
81
|
*/
|
87
|
|
- int master;
|
88
|
|
-
|
|
82
|
+ unsigned int port;
|
89
|
83
|
/** Peer address
|
90
|
84
|
*
|
91
|
85
|
* The peer address is determined by the first response
|
92
|
86
|
* received to the TFTP RRQ.
|
93
|
87
|
*/
|
94
|
88
|
struct sockaddr_tcpip peer;
|
|
89
|
+ /** Request flags */
|
|
90
|
+ unsigned int flags;
|
|
91
|
+ /** MTFTP timeout count */
|
|
92
|
+ unsigned int mtftp_timeouts;
|
|
93
|
+
|
95
|
94
|
/** Block bitmap */
|
96
|
95
|
struct bitmap bitmap;
|
97
|
96
|
/** Maximum known length
|
|
@@ -110,6 +109,21 @@ struct tftp_request {
|
110
|
109
|
struct retry_timer timer;
|
111
|
110
|
};
|
112
|
111
|
|
|
112
|
+/** TFTP request flags */
|
|
113
|
+enum {
|
|
114
|
+ /** Send ACK packets */
|
|
115
|
+ TFTP_FL_SEND_ACK = 0x0001,
|
|
116
|
+ /** Request blksize and tsize options */
|
|
117
|
+ TFTP_FL_RRQ_SIZES = 0x0002,
|
|
118
|
+ /** Request multicast option */
|
|
119
|
+ TFTP_FL_RRQ_MULTICAST = 0x0004,
|
|
120
|
+ /** Perform MTFTP recovery on timeout */
|
|
121
|
+ TFTP_FL_MTFTP_RECOVERY = 0x0008,
|
|
122
|
+};
|
|
123
|
+
|
|
124
|
+/** Maximum number of MTFTP open requests before falling back to TFTP */
|
|
125
|
+#define MTFTP_MAX_TIMEOUTS 3
|
|
126
|
+
|
113
|
127
|
/**
|
114
|
128
|
* Free TFTP request
|
115
|
129
|
*
|
|
@@ -147,6 +161,67 @@ static void tftp_done ( struct tftp_request *tftp, int rc ) {
|
147
|
161
|
xfer_close ( &tftp->xfer, rc );
|
148
|
162
|
}
|
149
|
163
|
|
|
164
|
+/**
|
|
165
|
+ * Reopen TFTP socket
|
|
166
|
+ *
|
|
167
|
+ * @v tftp TFTP connection
|
|
168
|
+ * @ret rc Return status code
|
|
169
|
+ */
|
|
170
|
+static int tftp_reopen ( struct tftp_request *tftp ) {
|
|
171
|
+ struct sockaddr_tcpip server;
|
|
172
|
+ int rc;
|
|
173
|
+
|
|
174
|
+ /* Close socket */
|
|
175
|
+ xfer_close ( &tftp->socket, 0 );
|
|
176
|
+
|
|
177
|
+ /* Disable ACK sending. */
|
|
178
|
+ tftp->flags &= ~TFTP_FL_SEND_ACK;
|
|
179
|
+
|
|
180
|
+ /* Reset peer address */
|
|
181
|
+ memset ( &tftp->peer, 0, sizeof ( tftp->peer ) );
|
|
182
|
+
|
|
183
|
+ /* Open socket */
|
|
184
|
+ memset ( &server, 0, sizeof ( server ) );
|
|
185
|
+ server.st_port = htons ( tftp->port );
|
|
186
|
+ if ( ( rc = xfer_open_named_socket ( &tftp->socket, SOCK_DGRAM,
|
|
187
|
+ ( struct sockaddr * ) &server,
|
|
188
|
+ tftp->uri->host, NULL ) ) != 0 ) {
|
|
189
|
+ DBGC ( tftp, "TFTP %p could not open socket: %s\n",
|
|
190
|
+ tftp, strerror ( rc ) );
|
|
191
|
+ return rc;
|
|
192
|
+ }
|
|
193
|
+
|
|
194
|
+ return 0;
|
|
195
|
+}
|
|
196
|
+
|
|
197
|
+/**
|
|
198
|
+ * Reopen TFTP multicast socket
|
|
199
|
+ *
|
|
200
|
+ * @v tftp TFTP connection
|
|
201
|
+ * @v local Local socket address
|
|
202
|
+ * @ret rc Return status code
|
|
203
|
+ */
|
|
204
|
+static int tftp_reopen_mc ( struct tftp_request *tftp,
|
|
205
|
+ struct sockaddr *local ) {
|
|
206
|
+ int rc;
|
|
207
|
+
|
|
208
|
+ /* Close multicast socket */
|
|
209
|
+ xfer_close ( &tftp->mc_socket, 0 );
|
|
210
|
+
|
|
211
|
+ /* Open multicast socket. We never send via this socket, so
|
|
212
|
+ * use the local address as the peer address (since the peer
|
|
213
|
+ * address cannot be NULL).
|
|
214
|
+ */
|
|
215
|
+ if ( ( rc = xfer_open_socket ( &tftp->mc_socket, SOCK_DGRAM,
|
|
216
|
+ local, local ) ) != 0 ) {
|
|
217
|
+ DBGC ( tftp, "TFTP %p could not open multicast "
|
|
218
|
+ "socket: %s\n", tftp, strerror ( rc ) );
|
|
219
|
+ return rc;
|
|
220
|
+ }
|
|
221
|
+
|
|
222
|
+ return 0;
|
|
223
|
+}
|
|
224
|
+
|
150
|
225
|
/**
|
151
|
226
|
* Presize TFTP receive buffers and block bitmap
|
152
|
227
|
*
|
|
@@ -201,6 +276,35 @@ void tftp_set_request_blksize ( unsigned int blksize ) {
|
201
|
276
|
tftp_request_blksize = blksize;
|
202
|
277
|
}
|
203
|
278
|
|
|
279
|
+/**
|
|
280
|
+ * MTFTP multicast receive address
|
|
281
|
+ *
|
|
282
|
+ * This is treated as a global configuration parameter.
|
|
283
|
+ */
|
|
284
|
+static struct sockaddr_in tftp_mtftp_socket = {
|
|
285
|
+ .sin_family = AF_INET,
|
|
286
|
+ .sin_addr.s_addr = htonl ( 0xefff0101 ),
|
|
287
|
+ .sin_port = htons ( 3001 ),
|
|
288
|
+};
|
|
289
|
+
|
|
290
|
+/**
|
|
291
|
+ * Set MTFTP multicast address
|
|
292
|
+ *
|
|
293
|
+ * @v address Multicast IPv4 address
|
|
294
|
+ */
|
|
295
|
+void tftp_set_mtftp_address ( struct in_addr address ) {
|
|
296
|
+ tftp_mtftp_socket.sin_addr = address;
|
|
297
|
+}
|
|
298
|
+
|
|
299
|
+/**
|
|
300
|
+ * Set MTFTP multicast port
|
|
301
|
+ *
|
|
302
|
+ * @v port Multicast port
|
|
303
|
+ */
|
|
304
|
+void tftp_set_mtftp_port ( unsigned int port ) {
|
|
305
|
+ tftp_mtftp_socket.sin_port = htons ( port );
|
|
306
|
+}
|
|
307
|
+
|
204
|
308
|
/**
|
205
|
309
|
* Transmit RRQ
|
206
|
310
|
*
|
|
@@ -227,11 +331,19 @@ static int tftp_send_rrq ( struct tftp_request *tftp ) {
|
227
|
331
|
/* Build request */
|
228
|
332
|
rrq = iob_put ( iobuf, sizeof ( *rrq ) );
|
229
|
333
|
rrq->opcode = htons ( TFTP_RRQ );
|
230
|
|
- iob_put ( iobuf,
|
231
|
|
- snprintf ( rrq->data, iob_tailroom ( iobuf ),
|
232
|
|
- "%s%coctet%cblksize%c%d%ctsize%c0%cmulticast%c",
|
233
|
|
- path, 0, 0, 0, tftp_request_blksize, 0,
|
234
|
|
- 0, 0, 0 ) + 1 );
|
|
334
|
+ iob_put ( iobuf, snprintf ( iobuf->tail, iob_tailroom ( iobuf ),
|
|
335
|
+ "%s%coctet", path, 0 ) + 1 );
|
|
336
|
+ if ( tftp->flags & TFTP_FL_RRQ_SIZES ) {
|
|
337
|
+ iob_put ( iobuf, snprintf ( iobuf->tail,
|
|
338
|
+ iob_tailroom ( iobuf ),
|
|
339
|
+ "blksize%c%d%ctsize%c0", 0,
|
|
340
|
+ tftp_request_blksize, 0, 0 ) + 1 );
|
|
341
|
+ }
|
|
342
|
+ if ( tftp->flags & TFTP_FL_RRQ_MULTICAST ) {
|
|
343
|
+ iob_put ( iobuf, snprintf ( iobuf->tail,
|
|
344
|
+ iob_tailroom ( iobuf ),
|
|
345
|
+ "multicast%c", 0 ) + 1 );
|
|
346
|
+ }
|
235
|
347
|
|
236
|
348
|
/* RRQ always goes to the address specified in the initial
|
237
|
349
|
* xfer_open() call
|
|
@@ -283,16 +395,15 @@ static int tftp_send_packet ( struct tftp_request *tftp ) {
|
283
|
395
|
stop_timer ( &tftp->timer );
|
284
|
396
|
start_timer ( &tftp->timer );
|
285
|
397
|
|
286
|
|
- /* If we are the master client, send RRQ or ACK as appropriate */
|
287
|
|
- if ( tftp->master ) {
|
288
|
|
- if ( ! tftp->peer.st_family ) {
|
289
|
|
- return tftp_send_rrq ( tftp );
|
290
|
|
- } else {
|
|
398
|
+ /* Send RRQ or ACK as appropriate */
|
|
399
|
+ if ( ! tftp->peer.st_family ) {
|
|
400
|
+ return tftp_send_rrq ( tftp );
|
|
401
|
+ } else {
|
|
402
|
+ if ( tftp->flags & TFTP_FL_SEND_ACK ) {
|
291
|
403
|
return tftp_send_ack ( tftp );
|
|
404
|
+ } else {
|
|
405
|
+ return 0;
|
292
|
406
|
}
|
293
|
|
- } else {
|
294
|
|
- /* Do nothing when not the master client */
|
295
|
|
- return 0;
|
296
|
407
|
}
|
297
|
408
|
}
|
298
|
409
|
|
|
@@ -305,12 +416,61 @@ static int tftp_send_packet ( struct tftp_request *tftp ) {
|
305
|
416
|
static void tftp_timer_expired ( struct retry_timer *timer, int fail ) {
|
306
|
417
|
struct tftp_request *tftp =
|
307
|
418
|
container_of ( timer, struct tftp_request, timer );
|
|
419
|
+ int rc;
|
308
|
420
|
|
309
|
|
- if ( fail ) {
|
310
|
|
- tftp_done ( tftp, -ETIMEDOUT );
|
|
421
|
+ /* If we are doing MTFTP, attempt the various recovery strategies */
|
|
422
|
+ if ( tftp->flags & TFTP_FL_MTFTP_RECOVERY ) {
|
|
423
|
+ if ( tftp->peer.st_family ) {
|
|
424
|
+ /* If we have received any response from the server,
|
|
425
|
+ * try resending the RRQ to restart the download.
|
|
426
|
+ */
|
|
427
|
+ DBGC ( tftp, "TFTP %p attempting reopen\n", tftp );
|
|
428
|
+ if ( ( rc = tftp_reopen ( tftp ) ) != 0 )
|
|
429
|
+ goto err;
|
|
430
|
+ } else {
|
|
431
|
+ /* Fall back to plain TFTP after several attempts */
|
|
432
|
+ tftp->mtftp_timeouts++;
|
|
433
|
+ DBGC ( tftp, "TFTP %p timeout %d waiting for MTFTP "
|
|
434
|
+ "open\n", tftp, tftp->mtftp_timeouts );
|
|
435
|
+
|
|
436
|
+ if ( tftp->mtftp_timeouts > MTFTP_MAX_TIMEOUTS ) {
|
|
437
|
+ DBGC ( tftp, "TFTP %p falling back to plain "
|
|
438
|
+ "TFTP\n", tftp );
|
|
439
|
+ tftp->flags = TFTP_FL_RRQ_SIZES;
|
|
440
|
+
|
|
441
|
+ /* Close multicast socket */
|
|
442
|
+ xfer_close ( &tftp->mc_socket, 0 );
|
|
443
|
+
|
|
444
|
+ /* Reset retry timer */
|
|
445
|
+ start_timer_nodelay ( &tftp->timer );
|
|
446
|
+
|
|
447
|
+ /* The blocksize may change: discard
|
|
448
|
+ * the block bitmap
|
|
449
|
+ */
|
|
450
|
+ bitmap_free ( &tftp->bitmap );
|
|
451
|
+ memset ( &tftp->bitmap, 0,
|
|
452
|
+ sizeof ( tftp->bitmap ) );
|
|
453
|
+
|
|
454
|
+ /* Reopen on standard TFTP port */
|
|
455
|
+ tftp->port = TFTP_PORT;
|
|
456
|
+ if ( ( rc = tftp_reopen ( tftp ) ) != 0 )
|
|
457
|
+ goto err;
|
|
458
|
+ }
|
|
459
|
+ }
|
311
|
460
|
} else {
|
312
|
|
- tftp_send_packet ( tftp );
|
|
461
|
+ /* Not doing MTFTP (or have fallen back to plain
|
|
462
|
+ * TFTP); fail as per normal.
|
|
463
|
+ */
|
|
464
|
+ if ( fail ) {
|
|
465
|
+ rc = -ETIMEDOUT;
|
|
466
|
+ goto err;
|
|
467
|
+ }
|
313
|
468
|
}
|
|
469
|
+ tftp_send_packet ( tftp );
|
|
470
|
+ return;
|
|
471
|
+
|
|
472
|
+ err:
|
|
473
|
+ tftp_done ( tftp, rc );
|
314
|
474
|
}
|
315
|
475
|
|
316
|
476
|
/**
|
|
@@ -366,15 +526,16 @@ static int tftp_process_tsize ( struct tftp_request *tftp,
|
366
|
526
|
*/
|
367
|
527
|
static int tftp_process_multicast ( struct tftp_request *tftp,
|
368
|
528
|
const char *value ) {
|
369
|
|
- struct sockaddr_in *sin = ( struct sockaddr_in * ) &tftp->multicast;
|
|
529
|
+ union {
|
|
530
|
+ struct sockaddr sa;
|
|
531
|
+ struct sockaddr_in sin;
|
|
532
|
+ } socket;
|
370
|
533
|
char buf[ strlen ( value ) + 1 ];
|
371
|
534
|
char *addr;
|
372
|
535
|
char *port;
|
373
|
536
|
char *port_end;
|
374
|
537
|
char *mc;
|
375
|
538
|
char *mc_end;
|
376
|
|
- struct sockaddr *mc_peer;
|
377
|
|
- struct sockaddr *mc_local;
|
378
|
539
|
int rc;
|
379
|
540
|
|
380
|
541
|
/* Split value into "addr,port,mc" fields */
|
|
@@ -394,45 +555,33 @@ static int tftp_process_multicast ( struct tftp_request *tftp,
|
394
|
555
|
*(mc++) = '\0';
|
395
|
556
|
|
396
|
557
|
/* Parse parameters */
|
397
|
|
- if ( *addr ) {
|
398
|
|
- if ( inet_aton ( addr, &sin->sin_addr ) == 0 ) {
|
|
558
|
+ if ( strtoul ( mc, &mc_end, 0 ) == 0 )
|
|
559
|
+ tftp->flags &= ~TFTP_FL_SEND_ACK;
|
|
560
|
+ if ( *mc_end ) {
|
|
561
|
+ DBGC ( tftp, "TFTP %p multicast invalid mc %s\n", tftp, mc );
|
|
562
|
+ return -EINVAL;
|
|
563
|
+ }
|
|
564
|
+ DBGC ( tftp, "TFTP %p is%s the master client\n",
|
|
565
|
+ tftp, ( ( tftp->flags & TFTP_FL_SEND_ACK ) ? "" : " not" ) );
|
|
566
|
+ if ( *addr && *port ) {
|
|
567
|
+ socket.sin.sin_family = AF_INET;
|
|
568
|
+ if ( inet_aton ( addr, &socket.sin.sin_addr ) == 0 ) {
|
399
|
569
|
DBGC ( tftp, "TFTP %p multicast invalid IP address "
|
400
|
570
|
"%s\n", tftp, addr );
|
401
|
571
|
return -EINVAL;
|
402
|
572
|
}
|
403
|
573
|
DBGC ( tftp, "TFTP %p multicast IP address %s\n",
|
404
|
|
- tftp, inet_ntoa ( sin->sin_addr ) );
|
405
|
|
- }
|
406
|
|
- if ( *port ) {
|
407
|
|
- sin->sin_port = htons ( strtoul ( port, &port_end, 0 ) );
|
|
574
|
+ tftp, inet_ntoa ( socket.sin.sin_addr ) );
|
|
575
|
+ socket.sin.sin_port = htons ( strtoul ( port, &port_end, 0 ) );
|
408
|
576
|
if ( *port_end ) {
|
409
|
577
|
DBGC ( tftp, "TFTP %p multicast invalid port %s\n",
|
410
|
578
|
tftp, port );
|
411
|
579
|
return -EINVAL;
|
412
|
580
|
}
|
413
|
581
|
DBGC ( tftp, "TFTP %p multicast port %d\n",
|
414
|
|
- tftp, ntohs ( sin->sin_port ) );
|
415
|
|
- }
|
416
|
|
- tftp->master = strtoul ( mc, &mc_end, 0 );
|
417
|
|
- if ( *mc_end ) {
|
418
|
|
- DBGC ( tftp, "TFTP %p multicast invalid mc %s\n", tftp, mc );
|
419
|
|
- return -EINVAL;
|
420
|
|
- }
|
421
|
|
- DBGC ( tftp, "TFTP %p is%s the master client\n",
|
422
|
|
- tftp, ( tftp->master ? "" : " not" ) );
|
423
|
|
-
|
424
|
|
- /* Open multicast socket, if new address specified */
|
425
|
|
- if ( *addr || *port ) {
|
426
|
|
- xfer_close ( &tftp->mc_socket, 0 );
|
427
|
|
- mc_peer = ( ( struct sockaddr * ) &tftp->peer );
|
428
|
|
- mc_local = ( ( struct sockaddr * ) &tftp->multicast );
|
429
|
|
- mc_local->sa_family = mc_peer->sa_family;
|
430
|
|
- if ( ( rc = xfer_open_socket ( &tftp->mc_socket, SOCK_DGRAM,
|
431
|
|
- mc_peer, mc_local ) ) != 0 ) {
|
432
|
|
- DBGC ( tftp, "TFTP %p could not open multicast "
|
433
|
|
- "socket: %s\n", tftp, strerror ( rc ) );
|
|
582
|
+ tftp, ntohs ( socket.sin.sin_port ) );
|
|
583
|
+ if ( ( rc = tftp_reopen_mc ( tftp, &socket.sa ) ) != 0 )
|
434
|
584
|
return rc;
|
435
|
|
- }
|
436
|
585
|
}
|
437
|
586
|
|
438
|
587
|
return 0;
|
|
@@ -614,10 +763,10 @@ static int tftp_rx_data ( struct tftp_request *tftp,
|
614
|
763
|
}
|
615
|
764
|
|
616
|
765
|
/** Translation between TFTP errors and internal error numbers */
|
617
|
|
-static const uint8_t tftp_errors[] = {
|
618
|
|
- [TFTP_ERR_FILE_NOT_FOUND] = PXENV_STATUS_TFTP_FILE_NOT_FOUND,
|
619
|
|
- [TFTP_ERR_ACCESS_DENIED] = PXENV_STATUS_TFTP_ACCESS_VIOLATION,
|
620
|
|
- [TFTP_ERR_ILLEGAL_OP] = PXENV_STATUS_TFTP_UNKNOWN_OPCODE,
|
|
766
|
+static const int tftp_errors[] = {
|
|
767
|
+ [TFTP_ERR_FILE_NOT_FOUND] = ENOENT,
|
|
768
|
+ [TFTP_ERR_ACCESS_DENIED] = EACCES,
|
|
769
|
+ [TFTP_ERR_ILLEGAL_OP] = ENOTSUP,
|
621
|
770
|
};
|
622
|
771
|
|
623
|
772
|
/**
|
|
@@ -648,7 +797,7 @@ static int tftp_rx_error ( struct tftp_request *tftp, void *buf, size_t len ) {
|
648
|
797
|
if ( err < ( sizeof ( tftp_errors ) / sizeof ( tftp_errors[0] ) ) )
|
649
|
798
|
rc = -tftp_errors[err];
|
650
|
799
|
if ( ! rc )
|
651
|
|
- rc = -PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION;
|
|
800
|
+ rc = -ENOTSUP;
|
652
|
801
|
|
653
|
802
|
/* Close TFTP request */
|
654
|
803
|
tftp_done ( tftp, rc );
|
|
@@ -739,32 +888,29 @@ static int tftp_socket_deliver_iob ( struct xfer_interface *socket,
|
739
|
888
|
struct tftp_request *tftp =
|
740
|
889
|
container_of ( socket, struct tftp_request, socket );
|
741
|
890
|
|
742
|
|
- return tftp_rx ( tftp, iobuf, meta );
|
743
|
|
-}
|
744
|
|
-
|
745
|
|
-/**
|
746
|
|
- * TFTP connection closed by network stack
|
747
|
|
- *
|
748
|
|
- * @v socket Transport layer interface
|
749
|
|
- * @v rc Reason for close
|
750
|
|
- */
|
751
|
|
-static void tftp_socket_close ( struct xfer_interface *socket, int rc ) {
|
752
|
|
- struct tftp_request *tftp =
|
753
|
|
- container_of ( socket, struct tftp_request, socket );
|
754
|
|
-
|
755
|
|
- DBGC ( tftp, "TFTP %p socket closed: %s\n",
|
756
|
|
- tftp, strerror ( rc ) );
|
757
|
|
-
|
758
|
|
- /* Any close counts as an error */
|
759
|
|
- if ( ! rc )
|
760
|
|
- rc = -ECONNRESET;
|
|
891
|
+ /* Enable sending ACKs when we receive a unicast packet. This
|
|
892
|
+ * covers three cases:
|
|
893
|
+ *
|
|
894
|
+ * 1. Standard TFTP; we should always send ACKs, and will
|
|
895
|
+ * always receive a unicast packet before we need to send the
|
|
896
|
+ * first ACK.
|
|
897
|
+ *
|
|
898
|
+ * 2. RFC2090 multicast TFTP; the only unicast packets we will
|
|
899
|
+ * receive are the OACKs; enable sending ACKs here (before
|
|
900
|
+ * processing the OACK) and disable it when processing the
|
|
901
|
+ * multicast option if we are not the master client.
|
|
902
|
+ *
|
|
903
|
+ * 3. MTFTP; receiving a unicast datagram indicates that we
|
|
904
|
+ * are the "master client" and should send ACKs.
|
|
905
|
+ */
|
|
906
|
+ tftp->flags |= TFTP_FL_SEND_ACK;
|
761
|
907
|
|
762
|
|
- tftp_done ( tftp, rc );
|
|
908
|
+ return tftp_rx ( tftp, iobuf, meta );
|
763
|
909
|
}
|
764
|
910
|
|
765
|
911
|
/** TFTP socket operations */
|
766
|
912
|
static struct xfer_interface_operations tftp_socket_operations = {
|
767
|
|
- .close = tftp_socket_close,
|
|
913
|
+ .close = ignore_xfer_close,
|
768
|
914
|
.vredirect = xfer_vopen,
|
769
|
915
|
.window = unlimited_xfer_window,
|
770
|
916
|
.alloc_iob = default_xfer_alloc_iob,
|
|
@@ -789,29 +935,9 @@ static int tftp_mc_socket_deliver_iob ( struct xfer_interface *mc_socket,
|
789
|
935
|
return tftp_rx ( tftp, iobuf, meta );
|
790
|
936
|
}
|
791
|
937
|
|
792
|
|
-/**
|
793
|
|
- * TFTP multicast connection closed by network stack
|
794
|
|
- *
|
795
|
|
- * @v socket Multicast transport layer interface
|
796
|
|
- * @v rc Reason for close
|
797
|
|
- */
|
798
|
|
-static void tftp_mc_socket_close ( struct xfer_interface *mc_socket,
|
799
|
|
- int rc ) {
|
800
|
|
- struct tftp_request *tftp =
|
801
|
|
- container_of ( mc_socket, struct tftp_request, mc_socket );
|
802
|
|
-
|
803
|
|
- DBGC ( tftp, "TFTP %p multicast socket closed: %s\n",
|
804
|
|
- tftp, strerror ( rc ) );
|
805
|
|
-
|
806
|
|
- /* The multicast socket may be closed when we receive a new
|
807
|
|
- * OACK and open/reopen the socket; we should not call
|
808
|
|
- * tftp_done() at this point.
|
809
|
|
- */
|
810
|
|
-}
|
811
|
|
-
|
812
|
938
|
/** TFTP multicast socket operations */
|
813
|
939
|
static struct xfer_interface_operations tftp_mc_socket_operations = {
|
814
|
|
- .close = tftp_mc_socket_close,
|
|
940
|
+ .close = ignore_xfer_close,
|
815
|
941
|
.vredirect = xfer_vopen,
|
816
|
942
|
.window = unlimited_xfer_window,
|
817
|
943
|
.alloc_iob = default_xfer_alloc_iob,
|
|
@@ -846,15 +972,17 @@ static struct xfer_interface_operations tftp_xfer_operations = {
|
846
|
972
|
};
|
847
|
973
|
|
848
|
974
|
/**
|
849
|
|
- * Initiate TFTP download
|
|
975
|
+ * Initiate TFTP/TFTM/MTFTP download
|
850
|
976
|
*
|
851
|
977
|
* @v xfer Data transfer interface
|
852
|
978
|
* @v uri Uniform Resource Identifier
|
853
|
979
|
* @ret rc Return status code
|
854
|
980
|
*/
|
855
|
|
-int tftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
|
|
981
|
+static int tftp_core_open ( struct xfer_interface *xfer, struct uri *uri,
|
|
982
|
+ unsigned int default_port,
|
|
983
|
+ struct sockaddr *multicast,
|
|
984
|
+ unsigned int flags ) {
|
856
|
985
|
struct tftp_request *tftp;
|
857
|
|
- struct sockaddr_tcpip server;
|
858
|
986
|
int rc;
|
859
|
987
|
|
860
|
988
|
/* Sanity checks */
|
|
@@ -874,17 +1002,20 @@ int tftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
|
874
|
1002
|
xfer_init ( &tftp->mc_socket, &tftp_mc_socket_operations,
|
875
|
1003
|
&tftp->refcnt );
|
876
|
1004
|
tftp->blksize = TFTP_DEFAULT_BLKSIZE;
|
877
|
|
- tftp->master = 1;
|
|
1005
|
+ tftp->flags = flags;
|
878
|
1006
|
tftp->timer.expired = tftp_timer_expired;
|
879
|
1007
|
|
880
|
1008
|
/* Open socket */
|
881
|
|
- memset ( &server, 0, sizeof ( server ) );
|
882
|
|
- server.st_port = htons ( uri_port ( tftp->uri, TFTP_PORT ) );
|
883
|
|
- if ( ( rc = xfer_open_named_socket ( &tftp->socket, SOCK_DGRAM,
|
884
|
|
- ( struct sockaddr * ) &server,
|
885
|
|
- uri->host, NULL ) ) != 0 )
|
|
1009
|
+ tftp->port = uri_port ( tftp->uri, default_port );
|
|
1010
|
+ if ( ( rc = tftp_reopen ( tftp ) ) != 0 )
|
886
|
1011
|
goto err;
|
887
|
1012
|
|
|
1013
|
+ /* Open multicast socket */
|
|
1014
|
+ if ( multicast ) {
|
|
1015
|
+ if ( ( rc = tftp_reopen_mc ( tftp, multicast ) ) != 0 )
|
|
1016
|
+ goto err;
|
|
1017
|
+ }
|
|
1018
|
+
|
888
|
1019
|
/* Start timer to initiate RRQ */
|
889
|
1020
|
start_timer_nodelay ( &tftp->timer );
|
890
|
1021
|
|
|
@@ -901,8 +1032,60 @@ int tftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
|
901
|
1032
|
return rc;
|
902
|
1033
|
}
|
903
|
1034
|
|
|
1035
|
+/**
|
|
1036
|
+ * Initiate TFTP download
|
|
1037
|
+ *
|
|
1038
|
+ * @v xfer Data transfer interface
|
|
1039
|
+ * @v uri Uniform Resource Identifier
|
|
1040
|
+ * @ret rc Return status code
|
|
1041
|
+ */
|
|
1042
|
+static int tftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
|
|
1043
|
+ return tftp_core_open ( xfer, uri, TFTP_PORT, NULL,
|
|
1044
|
+ TFTP_FL_RRQ_SIZES );
|
|
1045
|
+
|
|
1046
|
+}
|
|
1047
|
+
|
904
|
1048
|
/** TFTP URI opener */
|
905
|
1049
|
struct uri_opener tftp_uri_opener __uri_opener = {
|
906
|
1050
|
.scheme = "tftp",
|
907
|
1051
|
.open = tftp_open,
|
908
|
1052
|
};
|
|
1053
|
+
|
|
1054
|
+/**
|
|
1055
|
+ * Initiate TFTM download
|
|
1056
|
+ *
|
|
1057
|
+ * @v xfer Data transfer interface
|
|
1058
|
+ * @v uri Uniform Resource Identifier
|
|
1059
|
+ * @ret rc Return status code
|
|
1060
|
+ */
|
|
1061
|
+static int tftm_open ( struct xfer_interface *xfer, struct uri *uri ) {
|
|
1062
|
+ return tftp_core_open ( xfer, uri, TFTP_PORT, NULL,
|
|
1063
|
+ ( TFTP_FL_RRQ_SIZES |
|
|
1064
|
+ TFTP_FL_RRQ_MULTICAST ) );
|
|
1065
|
+
|
|
1066
|
+}
|
|
1067
|
+
|
|
1068
|
+/** TFTM URI opener */
|
|
1069
|
+struct uri_opener tftm_uri_opener __uri_opener = {
|
|
1070
|
+ .scheme = "tftm",
|
|
1071
|
+ .open = tftm_open,
|
|
1072
|
+};
|
|
1073
|
+
|
|
1074
|
+/**
|
|
1075
|
+ * Initiate MTFTP download
|
|
1076
|
+ *
|
|
1077
|
+ * @v xfer Data transfer interface
|
|
1078
|
+ * @v uri Uniform Resource Identifier
|
|
1079
|
+ * @ret rc Return status code
|
|
1080
|
+ */
|
|
1081
|
+static int mtftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
|
|
1082
|
+ return tftp_core_open ( xfer, uri, MTFTP_PORT,
|
|
1083
|
+ ( struct sockaddr * ) &tftp_mtftp_socket,
|
|
1084
|
+ TFTP_FL_MTFTP_RECOVERY );
|
|
1085
|
+}
|
|
1086
|
+
|
|
1087
|
+/** MTFTP URI opener */
|
|
1088
|
+struct uri_opener mtftp_uri_opener __uri_opener = {
|
|
1089
|
+ .scheme = "mtftp",
|
|
1090
|
+ .open = mtftp_open,
|
|
1091
|
+};
|