@@ -28,6 +28,8 @@ LOG_MODULE_REGISTER(net_tcp, CONFIG_NET_TCP_LOG_LEVEL);
28
28
29
29
#define ACK_TIMEOUT_MS CONFIG_NET_TCP_ACK_TIMEOUT
30
30
#define ACK_TIMEOUT K_MSEC(ACK_TIMEOUT_MS)
31
+ #define LAST_ACK_TIMEOUT_MS tcp_fin_timeout_ms
32
+ #define LAST_ACK_TIMEOUT K_MSEC(LAST_ACK_TIMEOUT_MS)
31
33
#define FIN_TIMEOUT K_MSEC(tcp_fin_timeout_ms)
32
34
#define ACK_DELAY K_MSEC(100)
33
35
#define ZWP_MAX_DELAY_MS 120000
@@ -1493,9 +1495,9 @@ static void tcp_resend_data(struct k_work *work)
1493
1495
conn -> send_data_retries ++ ;
1494
1496
if (ret == 0 ) {
1495
1497
if (conn -> in_close && conn -> send_data_total == 0 ) {
1496
- NET_DBG ("TCP connection in active close, "
1498
+ NET_DBG ("TCP connection in %s close, "
1497
1499
"not disposing yet (waiting %dms)" ,
1498
- tcp_fin_timeout_ms );
1500
+ "active" , tcp_fin_timeout_ms );
1499
1501
k_work_reschedule_for_queue (& tcp_work_q ,
1500
1502
& conn -> fin_timer ,
1501
1503
FIN_TIMEOUT );
@@ -1572,6 +1574,40 @@ static void tcp_fin_timeout(struct k_work *work)
1572
1574
(void )tcp_conn_close (conn , - ETIMEDOUT );
1573
1575
}
1574
1576
1577
+ static void tcp_last_ack_timeout (struct k_work * work )
1578
+ {
1579
+ struct k_work_delayable * dwork = k_work_delayable_from_work (work );
1580
+ struct tcp * conn = CONTAINER_OF (dwork , struct tcp , fin_timer );
1581
+
1582
+ NET_DBG ("Did not receive %s in %dms" , "last ACK" , LAST_ACK_TIMEOUT_MS );
1583
+ NET_DBG ("conn: %p %s" , conn , tcp_conn_state (conn , NULL ));
1584
+
1585
+ (void )tcp_conn_close (conn , - ETIMEDOUT );
1586
+ }
1587
+
1588
+ static void tcp_setup_last_ack_timer (struct tcp * conn )
1589
+ {
1590
+ /* Just in case the last ack is lost, install a timer that will
1591
+ * close the connection in that case. Use the fin_timer for that
1592
+ * as the fin handling cannot be done in this passive close state.
1593
+ * Instead of default tcp_fin_timeout() function, have a separate
1594
+ * function to catch this last ack case.
1595
+ */
1596
+ k_work_init_delayable (& conn -> fin_timer , tcp_last_ack_timeout );
1597
+
1598
+ NET_DBG ("TCP connection in %s close, "
1599
+ "not disposing yet (waiting %dms)" ,
1600
+ "passive" , LAST_ACK_TIMEOUT_MS );
1601
+ k_work_reschedule_for_queue (& tcp_work_q ,
1602
+ & conn -> fin_timer ,
1603
+ LAST_ACK_TIMEOUT );
1604
+ }
1605
+
1606
+ static void tcp_cancel_last_ack_timer (struct tcp * conn )
1607
+ {
1608
+ k_work_cancel_delayable (& conn -> fin_timer );
1609
+ }
1610
+
1575
1611
static void tcp_send_zwp (struct k_work * work )
1576
1612
{
1577
1613
struct k_work_delayable * dwork = k_work_delayable_from_work (work );
@@ -2520,6 +2556,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
2520
2556
tcp_out (conn , FIN | ACK );
2521
2557
next = TCP_LAST_ACK ;
2522
2558
verdict = NET_OK ;
2559
+ tcp_setup_last_ack_timer (conn );
2523
2560
break ;
2524
2561
} else if (th && FL (& fl , = = , FIN , th_seq (th ) == conn -> ack )) {
2525
2562
conn_ack (conn , + 1 );
@@ -2542,6 +2579,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
2542
2579
conn_ack (conn , + len + 1 );
2543
2580
tcp_out (conn , FIN | ACK );
2544
2581
next = TCP_LAST_ACK ;
2582
+ tcp_setup_last_ack_timer (conn );
2545
2583
break ;
2546
2584
}
2547
2585
@@ -2716,13 +2754,17 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
2716
2754
case TCP_CLOSE_WAIT :
2717
2755
tcp_out (conn , FIN );
2718
2756
next = TCP_LAST_ACK ;
2757
+ tcp_setup_last_ack_timer (conn );
2719
2758
break ;
2720
2759
case TCP_LAST_ACK :
2721
2760
if (th && FL (& fl , = = , ACK , th_seq (th ) == conn -> ack )) {
2722
2761
tcp_send_timer_cancel (conn );
2723
2762
do_close = true;
2724
2763
verdict = NET_OK ;
2725
2764
close_status = 0 ;
2765
+
2766
+ /* Remove the last ack timer if we received it in time */
2767
+ tcp_cancel_last_ack_timer (conn );
2726
2768
}
2727
2769
break ;
2728
2770
case TCP_CLOSED :
@@ -3048,8 +3090,9 @@ int net_tcp_put(struct net_context *context)
3048
3090
} else {
3049
3091
int ret ;
3050
3092
3051
- NET_DBG ("TCP connection in active close, not "
3052
- "disposing yet (waiting %dms)" , tcp_fin_timeout_ms );
3093
+ NET_DBG ("TCP connection in %s close, "
3094
+ "not disposing yet (waiting %dms)" ,
3095
+ "active" , tcp_fin_timeout_ms );
3053
3096
k_work_reschedule_for_queue (& tcp_work_q ,
3054
3097
& conn -> fin_timer ,
3055
3098
FIN_TIMEOUT );
0 commit comments