@@ -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
@@ -1593,9 +1595,9 @@ static void tcp_resend_data(struct k_work *work)
1593
1595
conn -> send_data_retries ++ ;
1594
1596
if (ret == 0 ) {
1595
1597
if (conn -> in_close && conn -> send_data_total == 0 ) {
1596
- NET_DBG ("TCP connection in active close, "
1598
+ NET_DBG ("TCP connection in %s close, "
1597
1599
"not disposing yet (waiting %dms)" ,
1598
- tcp_fin_timeout_ms );
1600
+ "active" , tcp_fin_timeout_ms );
1599
1601
k_work_reschedule_for_queue (& tcp_work_q ,
1600
1602
& conn -> fin_timer ,
1601
1603
FIN_TIMEOUT );
@@ -1675,6 +1677,40 @@ static void tcp_fin_timeout(struct k_work *work)
1675
1677
(void )tcp_conn_close (conn , - ETIMEDOUT );
1676
1678
}
1677
1679
1680
+ static void tcp_last_ack_timeout (struct k_work * work )
1681
+ {
1682
+ struct k_work_delayable * dwork = k_work_delayable_from_work (work );
1683
+ struct tcp * conn = CONTAINER_OF (dwork , struct tcp , fin_timer );
1684
+
1685
+ NET_DBG ("Did not receive %s in %dms" , "last ACK" , LAST_ACK_TIMEOUT_MS );
1686
+ NET_DBG ("conn: %p %s" , conn , tcp_conn_state (conn , NULL ));
1687
+
1688
+ (void )tcp_conn_close (conn , - ETIMEDOUT );
1689
+ }
1690
+
1691
+ static void tcp_setup_last_ack_timer (struct tcp * conn )
1692
+ {
1693
+ /* Just in case the last ack is lost, install a timer that will
1694
+ * close the connection in that case. Use the fin_timer for that
1695
+ * as the fin handling cannot be done in this passive close state.
1696
+ * Instead of default tcp_fin_timeout() function, have a separate
1697
+ * function to catch this last ack case.
1698
+ */
1699
+ k_work_init_delayable (& conn -> fin_timer , tcp_last_ack_timeout );
1700
+
1701
+ NET_DBG ("TCP connection in %s close, "
1702
+ "not disposing yet (waiting %dms)" ,
1703
+ "passive" , LAST_ACK_TIMEOUT_MS );
1704
+ k_work_reschedule_for_queue (& tcp_work_q ,
1705
+ & conn -> fin_timer ,
1706
+ LAST_ACK_TIMEOUT );
1707
+ }
1708
+
1709
+ static void tcp_cancel_last_ack_timer (struct tcp * conn )
1710
+ {
1711
+ k_work_cancel_delayable (& conn -> fin_timer );
1712
+ }
1713
+
1678
1714
static void tcp_send_zwp (struct k_work * work )
1679
1715
{
1680
1716
struct k_work_delayable * dwork = k_work_delayable_from_work (work );
@@ -2694,6 +2730,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
2694
2730
tcp_out (conn , FIN | ACK );
2695
2731
next = TCP_LAST_ACK ;
2696
2732
verdict = NET_OK ;
2733
+ tcp_setup_last_ack_timer (conn );
2697
2734
break ;
2698
2735
} else if (th && FL (& fl , = = , FIN , th_seq (th ) == conn -> ack )) {
2699
2736
conn_ack (conn , + 1 );
@@ -2716,6 +2753,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
2716
2753
conn_ack (conn , + len + 1 );
2717
2754
tcp_out (conn , FIN | ACK );
2718
2755
next = TCP_LAST_ACK ;
2756
+ tcp_setup_last_ack_timer (conn );
2719
2757
break ;
2720
2758
}
2721
2759
@@ -2890,13 +2928,17 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
2890
2928
case TCP_CLOSE_WAIT :
2891
2929
tcp_out (conn , FIN );
2892
2930
next = TCP_LAST_ACK ;
2931
+ tcp_setup_last_ack_timer (conn );
2893
2932
break ;
2894
2933
case TCP_LAST_ACK :
2895
2934
if (th && FL (& fl , = = , ACK , th_seq (th ) == conn -> ack )) {
2896
2935
tcp_send_timer_cancel (conn );
2897
2936
do_close = true;
2898
2937
verdict = NET_OK ;
2899
2938
close_status = 0 ;
2939
+
2940
+ /* Remove the last ack timer if we received it in time */
2941
+ tcp_cancel_last_ack_timer (conn );
2900
2942
}
2901
2943
break ;
2902
2944
case TCP_CLOSED :
@@ -3222,8 +3264,9 @@ int net_tcp_put(struct net_context *context)
3222
3264
} else {
3223
3265
int ret ;
3224
3266
3225
- NET_DBG ("TCP connection in active close, not "
3226
- "disposing yet (waiting %dms)" , tcp_fin_timeout_ms );
3267
+ NET_DBG ("TCP connection in %s close, "
3268
+ "not disposing yet (waiting %dms)" ,
3269
+ "active" , tcp_fin_timeout_ms );
3227
3270
k_work_reschedule_for_queue (& tcp_work_q ,
3228
3271
& conn -> fin_timer ,
3229
3272
FIN_TIMEOUT );
0 commit comments