Browse Source

[tcp] Mark any unacknowledged transmission as a pending operation

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 years ago
parent
commit
5482b0abb6
1 changed files with 33 additions and 3 deletions
  1. 33
    3
      src/net/tcp.c

+ 33
- 3
src/net/tcp.c View File

@@ -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
 

Loading…
Cancel
Save