소스 검색

[tcp] Mark any unacknowledged transmission as a pending operation

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 년 전
부모
커밋
5482b0abb6
1개의 변경된 파일33개의 추가작업 그리고 3개의 파일을 삭제
  1. 33
    3
      src/net/tcp.c

+ 33
- 3
src/net/tcp.c 파일 보기

10
 #include <ipxe/init.h>
10
 #include <ipxe/init.h>
11
 #include <ipxe/retry.h>
11
 #include <ipxe/retry.h>
12
 #include <ipxe/refcnt.h>
12
 #include <ipxe/refcnt.h>
13
+#include <ipxe/pending.h>
13
 #include <ipxe/xfer.h>
14
 #include <ipxe/xfer.h>
14
 #include <ipxe/open.h>
15
 #include <ipxe/open.h>
15
 #include <ipxe/uri.h>
16
 #include <ipxe/uri.h>
95
 	struct retry_timer timer;
96
 	struct retry_timer timer;
96
 	/** Shutdown (TIME_WAIT) timer */
97
 	/** Shutdown (TIME_WAIT) timer */
97
 	struct retry_timer wait;
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
 /** TCP flags */
106
 /** TCP flags */
291
 	/* Start timer to initiate SYN */
297
 	/* Start timer to initiate SYN */
292
 	start_timer_nodelay ( &tcp->timer );
298
 	start_timer_nodelay ( &tcp->timer );
293
 
299
 
300
+	/* Add a pending operation for the SYN */
301
+	pending_get ( &tcp->pending_flags );
302
+
294
 	/* Attach parent interface, transfer reference to connection
303
 	/* Attach parent interface, transfer reference to connection
295
 	 * list and return
304
 	 * list and return
296
 	 */
305
 	 */
340
 		list_for_each_entry_safe ( iobuf, tmp, &tcp->tx_queue, list ) {
349
 		list_for_each_entry_safe ( iobuf, tmp, &tcp->tx_queue, list ) {
341
 			list_del ( &iobuf->list );
350
 			list_del ( &iobuf->list );
342
 			free_iob ( iobuf );
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
 		/* Remove from list and drop reference */
360
 		/* Remove from list and drop reference */
346
 		stop_timer ( &tcp->timer );
361
 		stop_timer ( &tcp->timer );
359
 		tcp_rx_ack ( tcp, ( tcp->snd_seq + 1 ), 0 );
374
 		tcp_rx_ack ( tcp, ( tcp->snd_seq + 1 ), 0 );
360
 
375
 
361
 	/* If we have no data remaining to send, start sending FIN */
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
 		tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN );
380
 		tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN );
364
 		tcp_dump_state ( tcp );
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
 			if ( ! iob_len ( iobuf ) ) {
466
 			if ( ! iob_len ( iobuf ) ) {
447
 				list_del ( &iobuf->list );
467
 				list_del ( &iobuf->list );
448
 				free_iob ( iobuf );
468
 				free_iob ( iobuf );
469
+				pending_put ( &tcp->pending_data );
449
 			}
470
 			}
450
 		}
471
 		}
451
 		len += frag_len;
472
 		len += frag_len;
869
 	len = ack_len;
890
 	len = ack_len;
870
 	acked_flags = ( TCP_FLAGS_SENDING ( tcp->tcp_state ) &
891
 	acked_flags = ( TCP_FLAGS_SENDING ( tcp->tcp_state ) &
871
 			( TCP_SYN | TCP_FIN ) );
892
 			( TCP_SYN | TCP_FIN ) );
872
-	if ( acked_flags )
893
+	if ( acked_flags ) {
873
 		len--;
894
 		len--;
895
+		pending_put ( &tcp->pending_flags );
896
+	}
874
 
897
 
875
 	/* Update SEQ and sent counters, and window size */
898
 	/* Update SEQ and sent counters, and window size */
876
 	tcp->snd_seq = ack;
899
 	tcp->snd_seq = ack;
885
 		tcp->tcp_state |= TCP_STATE_ACKED ( acked_flags );
908
 		tcp->tcp_state |= TCP_STATE_ACKED ( acked_flags );
886
 
909
 
887
 	/* Start sending FIN if we've had all possible data ACKed */
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
 		tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN );
914
 		tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN );
915
+		pending_get ( &tcp->pending_flags );
916
+	}
890
 
917
 
891
 	return 0;
918
 	return 0;
892
 }
919
 }
1320
 	/* Enqueue packet */
1347
 	/* Enqueue packet */
1321
 	list_add_tail ( &iobuf->list, &tcp->tx_queue );
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
 	/* Transmit data, if possible */
1353
 	/* Transmit data, if possible */
1324
 	tcp_xmit ( tcp );
1354
 	tcp_xmit ( tcp );
1325
 
1355
 

Loading…
취소
저장