Skip to content

Commit 7685eaf

Browse files
jackctj117danielinux
authored andcommitted
fix TCP simultaneous close: drive CLOSING → TIME_WAIT from incoming ACK
1 parent 2be9958 commit 7685eaf

2 files changed

Lines changed: 49 additions & 0 deletions

File tree

src/test/unit/unit.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6390,6 +6390,50 @@ START_TEST(test_tcp_ack_fin_wait_1_ack_of_fin_moves_to_fin_wait_2_and_stops_time
63906390
}
63916391
END_TEST
63926392

6393+
START_TEST(test_tcp_ack_closing_ack_of_fin_moves_to_time_wait_and_stops_timer)
6394+
{
6395+
struct wolfIP s;
6396+
struct tsocket *ts;
6397+
struct wolfIP_tcp_seg ackseg;
6398+
struct wolfIP_timer tmr;
6399+
6400+
wolfIP_init(&s);
6401+
ts = &s.tcpsockets[0];
6402+
memset(ts, 0, sizeof(*ts));
6403+
ts->proto = WI_IPPROTO_TCP;
6404+
ts->S = &s;
6405+
/* Simultaneous close: we sent FIN (last=100), peer sent FIN too,
6406+
* tcp_input moved us to CLOSING. Now peer's ACK of our FIN arrives. */
6407+
ts->sock.tcp.state = TCP_CLOSING;
6408+
ts->sock.tcp.last = 100;
6409+
ts->sock.tcp.snd_una = 100;
6410+
ts->sock.tcp.seq = 1000;
6411+
ts->sock.tcp.rto = 100;
6412+
ts->sock.tcp.ctrl_rto_active = 1;
6413+
ts->sock.tcp.ctrl_rto_retries = 2;
6414+
6415+
memset(&tmr, 0, sizeof(tmr));
6416+
tmr.cb = test_timer_cb;
6417+
tmr.expires = 200;
6418+
tmr.arg = ts;
6419+
ts->sock.tcp.tmr_rto = timers_binheap_insert(&s.timers, tmr);
6420+
ck_assert_int_ne(ts->sock.tcp.tmr_rto, NO_TIMER);
6421+
6422+
memset(&ackseg, 0, sizeof(ackseg));
6423+
ackseg.hlen = TCP_HEADER_LEN << 2;
6424+
ackseg.flags = TCP_FLAG_ACK;
6425+
ackseg.ack = ee32(101); /* acknowledges our FIN at seq 100 */
6426+
ackseg.ip.len = ee16(IP_HEADER_LEN + TCP_HEADER_LEN);
6427+
6428+
tcp_ack(ts, &ackseg);
6429+
6430+
ck_assert_int_eq(ts->sock.tcp.state, TCP_TIME_WAIT);
6431+
ck_assert_int_eq(ts->sock.tcp.tmr_rto, NO_TIMER);
6432+
ck_assert_uint_eq(ts->sock.tcp.ctrl_rto_active, 0);
6433+
ck_assert_uint_eq(ts->sock.tcp.ctrl_rto_retries, 0);
6434+
}
6435+
END_TEST
6436+
63936437
START_TEST(test_tcp_rto_cb_control_retry_cap_closes_socket)
63946438
{
63956439
struct wolfIP s;
@@ -17054,6 +17098,7 @@ Suite *wolf_suite(void)
1705417098
tcase_add_test(tc_utils, test_tcp_rto_cb_fin_wait_1_with_data_uses_data_recovery);
1705517099
tcase_add_test(tc_utils, test_tcp_rto_cb_fin_wait_1_no_data_requeues_finack);
1705617100
tcase_add_test(tc_utils, test_tcp_ack_fin_wait_1_ack_of_fin_moves_to_fin_wait_2_and_stops_timer);
17101+
tcase_add_test(tc_utils, test_tcp_ack_closing_ack_of_fin_moves_to_time_wait_and_stops_timer);
1705717102
tcase_add_test(tc_utils, test_tcp_rto_cb_control_retry_cap_closes_socket);
1705817103
tcase_add_test(tc_utils, test_tcp_rto_cb_cancels_existing_timer);
1705917104
tcase_add_test(tc_utils, test_tcp_rto_cb_clears_sack_and_marks_lowest_only);

src/wolfip.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2961,6 +2961,10 @@ static void tcp_ack(struct tsocket *t, const struct wolfIP_tcp_seg *tcp)
29612961
t->sock.tcp.state = TCP_FIN_WAIT_2;
29622962
tcp_ctrl_rto_stop(t);
29632963
}
2964+
if (t->sock.tcp.state == TCP_CLOSING && tcp_seq_leq(fin_acked, ack)) {
2965+
t->sock.tcp.state = TCP_TIME_WAIT;
2966+
tcp_ctrl_rto_stop(t);
2967+
}
29642968

29652969
tcp_process_sack(t, tcp,
29662970
(uint32_t)(ETH_HEADER_LEN + IP_HEADER_LEN + (tcp->hlen >> 2)));

0 commit comments

Comments
 (0)