|
@@ -10,6 +10,7 @@
|
10
|
10
|
#include <ipxe/init.h>
|
11
|
11
|
#include <ipxe/retry.h>
|
12
|
12
|
#include <ipxe/refcnt.h>
|
|
13
|
+#include <ipxe/pending.h>
|
13
|
14
|
#include <ipxe/xfer.h>
|
14
|
15
|
#include <ipxe/open.h>
|
15
|
16
|
#include <ipxe/uri.h>
|
|
@@ -95,6 +96,11 @@ struct tcp_connection {
|
95
|
96
|
struct retry_timer timer;
|
96
|
97
|
/** Shutdown (TIME_WAIT) timer */
|
97
|
98
|
struct retry_timer wait;
|
|
99
|
+
|
|
100
|
+ /** Pending operations for SYN and FIN */
|
|
101
|
+ struct pending_operation pending_flags;
|
|
102
|
+ /** Pending operations for transmit queue */
|
|
103
|
+ struct pending_operation pending_data;
|
98
|
104
|
};
|
99
|
105
|
|
100
|
106
|
/** TCP flags */
|
|
@@ -291,6 +297,9 @@ static int tcp_open ( struct interface *xfer, struct sockaddr *peer,
|
291
|
297
|
/* Start timer to initiate SYN */
|
292
|
298
|
start_timer_nodelay ( &tcp->timer );
|
293
|
299
|
|
|
300
|
+ /* Add a pending operation for the SYN */
|
|
301
|
+ pending_get ( &tcp->pending_flags );
|
|
302
|
+
|
294
|
303
|
/* Attach parent interface, transfer reference to connection
|
295
|
304
|
* list and return
|
296
|
305
|
*/
|
|
@@ -340,7 +349,13 @@ static void tcp_close ( struct tcp_connection *tcp, int rc ) {
|
340
|
349
|
list_for_each_entry_safe ( iobuf, tmp, &tcp->tx_queue, list ) {
|
341
|
350
|
list_del ( &iobuf->list );
|
342
|
351
|
free_iob ( iobuf );
|
|
352
|
+ pending_put ( &tcp->pending_data );
|
343
|
353
|
}
|
|
354
|
+ assert ( ! is_pending ( &tcp->pending_data ) );
|
|
355
|
+
|
|
356
|
+ /* Remove pending operations for SYN and FIN, if applicable */
|
|
357
|
+ pending_put ( &tcp->pending_flags );
|
|
358
|
+ pending_put ( &tcp->pending_flags );
|
344
|
359
|
|
345
|
360
|
/* Remove from list and drop reference */
|
346
|
361
|
stop_timer ( &tcp->timer );
|
|
@@ -359,9 +374,14 @@ static void tcp_close ( struct tcp_connection *tcp, int rc ) {
|
359
|
374
|
tcp_rx_ack ( tcp, ( tcp->snd_seq + 1 ), 0 );
|
360
|
375
|
|
361
|
376
|
/* If we have no data remaining to send, start sending FIN */
|
362
|
|
- if ( list_empty ( &tcp->tx_queue ) ) {
|
|
377
|
+ if ( list_empty ( &tcp->tx_queue ) &&
|
|
378
|
+ ! ( tcp->tcp_state & TCP_STATE_SENT ( TCP_FIN ) ) ) {
|
|
379
|
+
|
363
|
380
|
tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN );
|
364
|
381
|
tcp_dump_state ( tcp );
|
|
382
|
+
|
|
383
|
+ /* Add a pending operation for the FIN */
|
|
384
|
+ pending_get ( &tcp->pending_flags );
|
365
|
385
|
}
|
366
|
386
|
}
|
367
|
387
|
|
|
@@ -446,6 +466,7 @@ static size_t tcp_process_tx_queue ( struct tcp_connection *tcp, size_t max_len,
|
446
|
466
|
if ( ! iob_len ( iobuf ) ) {
|
447
|
467
|
list_del ( &iobuf->list );
|
448
|
468
|
free_iob ( iobuf );
|
|
469
|
+ pending_put ( &tcp->pending_data );
|
449
|
470
|
}
|
450
|
471
|
}
|
451
|
472
|
len += frag_len;
|
|
@@ -869,8 +890,10 @@ static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack,
|
869
|
890
|
len = ack_len;
|
870
|
891
|
acked_flags = ( TCP_FLAGS_SENDING ( tcp->tcp_state ) &
|
871
|
892
|
( TCP_SYN | TCP_FIN ) );
|
872
|
|
- if ( acked_flags )
|
|
893
|
+ if ( acked_flags ) {
|
873
|
894
|
len--;
|
|
895
|
+ pending_put ( &tcp->pending_flags );
|
|
896
|
+ }
|
874
|
897
|
|
875
|
898
|
/* Update SEQ and sent counters, and window size */
|
876
|
899
|
tcp->snd_seq = ack;
|
|
@@ -885,8 +908,12 @@ static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack,
|
885
|
908
|
tcp->tcp_state |= TCP_STATE_ACKED ( acked_flags );
|
886
|
909
|
|
887
|
910
|
/* Start sending FIN if we've had all possible data ACKed */
|
888
|
|
- if ( list_empty ( &tcp->tx_queue ) && ( tcp->flags & TCP_XFER_CLOSED ) )
|
|
911
|
+ if ( list_empty ( &tcp->tx_queue ) &&
|
|
912
|
+ ( tcp->flags & TCP_XFER_CLOSED ) &&
|
|
913
|
+ ! ( tcp->tcp_state & TCP_STATE_SENT ( TCP_FIN ) ) ) {
|
889
|
914
|
tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN );
|
|
915
|
+ pending_get ( &tcp->pending_flags );
|
|
916
|
+ }
|
890
|
917
|
|
891
|
918
|
return 0;
|
892
|
919
|
}
|
|
@@ -1320,6 +1347,9 @@ static int tcp_xfer_deliver ( struct tcp_connection *tcp,
|
1320
|
1347
|
/* Enqueue packet */
|
1321
|
1348
|
list_add_tail ( &iobuf->list, &tcp->tx_queue );
|
1322
|
1349
|
|
|
1350
|
+ /* Each enqueued packet is a pending operation */
|
|
1351
|
+ pending_get ( &tcp->pending_data );
|
|
1352
|
+
|
1323
|
1353
|
/* Transmit data, if possible */
|
1324
|
1354
|
tcp_xmit ( tcp );
|
1325
|
1355
|
|