1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** NetX Component                                                        */
16 /**                                                                       */
17 /**   Transmission Control Protocol (TCP)                                 */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define NX_SOURCE_CODE
23 
24 
25 /* Include necessary system files.  */
26 
27 #include "nx_api.h"
28 #include "nx_ip.h"
29 #ifdef FEATURE_NX_IPV6
30 #include "nx_ipv6.h"
31 #endif /* FEATURE_NX_IPV6 */
32 #include "nx_packet.h"
33 #include "nx_tcp.h"
34 
35 
36 /**************************************************************************/
37 /*                                                                        */
38 /*  FUNCTION                                               RELEASE        */
39 /*                                                                        */
40 /*    _nx_tcp_fast_periodic_processing                    PORTABLE C      */
41 /*                                                           6.1          */
42 /*  AUTHOR                                                                */
43 /*                                                                        */
44 /*    Yuxin Zhou, Microsoft Corporation                                   */
45 /*                                                                        */
46 /*  DESCRIPTION                                                           */
47 /*                                                                        */
48 /*    This function processes the fast periodic TCP processing for        */
49 /*    sending delayed ACK messages for previous receive operations and    */
50 /*    for re-transmitting packets that have not been ACKed by the other   */
51 /*    side of the connection.                                             */
52 /*                                                                        */
53 /*  INPUT                                                                 */
54 /*                                                                        */
55 /*    ip_ptr                                Pointer to IP control block   */
56 /*                                                                        */
57 /*  OUTPUT                                                                */
58 /*                                                                        */
59 /*    None                                                                */
60 /*                                                                        */
61 /*  CALLS                                                                 */
62 /*                                                                        */
63 /*    _nx_tcp_packet_send_ack               Send a delayed ACK            */
64 /*    _nx_tcp_packet_send_syn               Send initial SYN again        */
65 /*    _nx_tcp_socket_connection_reset       Reset connection on timeout   */
66 /*    _nx_tcp_socket_block_cleanup          Cleanup the socket block      */
67 /*    _nx_tcp_socket_retransmit             Retransmit packet             */
68 /*                                                                        */
69 /*  CALLED BY                                                             */
70 /*                                                                        */
71 /*    _nx_ip_thread_entry                   IP helper thread              */
72 /*                                                                        */
73 /*  RELEASE HISTORY                                                       */
74 /*                                                                        */
75 /*    DATE              NAME                      DESCRIPTION             */
76 /*                                                                        */
77 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
78 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
79 /*                                            resulting in version 6.1    */
80 /*                                                                        */
81 /**************************************************************************/
_nx_tcp_fast_periodic_processing(NX_IP * ip_ptr)82 VOID  _nx_tcp_fast_periodic_processing(NX_IP *ip_ptr)
83 {
84 
85 NX_TCP_SOCKET *socket_ptr;
86 ULONG          sockets;
87 ULONG          timer_rate;
88 
89 
90     /* Pickup this timer's periodic rate.  */
91     timer_rate =  _nx_tcp_fast_timer_rate;
92 
93     /* Pickup the number of created TCP sockets.  */
94     sockets =  ip_ptr -> nx_ip_tcp_created_sockets_count;
95 
96     /* Pickup the first socket.  */
97     socket_ptr =  ip_ptr -> nx_ip_tcp_created_sockets_ptr;
98 
99     /* Loop through the created sockets.  */
100     while (sockets--)
101     {
102 
103         /* Determine if the socket is in an established or disconnect state and has delayed sending an ACK
104            from a previous receive packet event.  */
105         if ((socket_ptr -> nx_tcp_socket_state >= NX_TCP_ESTABLISHED) &&
106             ((socket_ptr -> nx_tcp_socket_rx_sequence != socket_ptr -> nx_tcp_socket_rx_sequence_acked) ||
107              (socket_ptr -> nx_tcp_socket_rx_window_last_sent < socket_ptr -> nx_tcp_socket_rx_window_current)))
108         {
109 
110             /* Determine if the ACK has expired.  */
111             if (socket_ptr -> nx_tcp_socket_delayed_ack_timeout <= timer_rate)
112             {
113 
114                 /* Send the delayed ACK, which also resets the ACK timeout.  */
115                 _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
116             }
117             else
118             {
119 
120                 /* No, it hasn't expired yet.  Just decrement it for now.  */
121                 socket_ptr -> nx_tcp_socket_delayed_ack_timeout -= timer_rate;
122             }
123         }
124 
125         /* Determine if a timeout is active.  */
126         if (socket_ptr -> nx_tcp_socket_timeout)
127         {
128 
129             /* Yes, a timeout is active.  Determine if it has expired.  */
130             if (socket_ptr -> nx_tcp_socket_timeout > timer_rate)
131             {
132 
133                 /* No, it hasn't expired yet.  Just decrement the timeout value.  */
134                 socket_ptr -> nx_tcp_socket_timeout -= timer_rate;
135             }
136             else if (((socket_ptr -> nx_tcp_socket_timeout_retries >= socket_ptr -> nx_tcp_socket_timeout_max_retries) &&
137                       (socket_ptr -> nx_tcp_socket_zero_window_probe_has_data == NX_FALSE)) ||
138                      ((socket_ptr -> nx_tcp_socket_zero_window_probe_failure >= socket_ptr -> nx_tcp_socket_timeout_max_retries) &&
139                       (socket_ptr -> nx_tcp_socket_zero_window_probe_has_data == NX_TRUE))
140                     )
141             {
142 
143                 /* Number of retries has been exceeded.  */
144 
145                 /* Close the socket via a connection reset.  */
146                 _nx_tcp_socket_connection_reset(socket_ptr);
147             }
148             /* YUXIN MODIFIED HERE */
149             else if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_SENT) ||
150                      (socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_RECEIVED))
151             {
152 
153                 /* Yes, the timeout on the SYN message has expired.  */
154 
155                 /* Increment the retry counter.  */
156                 socket_ptr -> nx_tcp_socket_timeout_retries++;
157 
158                 /* Setup the next timeout.  */
159                 socket_ptr -> nx_tcp_socket_timeout = socket_ptr -> nx_tcp_socket_timeout_rate <<
160                     (socket_ptr -> nx_tcp_socket_timeout_retries * socket_ptr -> nx_tcp_socket_timeout_shift);
161 
162                 /* Send the initial SYN message again.  Adjust the sequence number before and
163                    after to ensure the same sequence as the initial SYN.  */
164                 _nx_tcp_packet_send_syn(socket_ptr, (socket_ptr -> nx_tcp_socket_tx_sequence - 1));
165             }
166             /* Has the TCP timeout for transmit packet or probing zero window expired?  */
167             else if (socket_ptr -> nx_tcp_socket_transmit_sent_head ||
168                      ((socket_ptr -> nx_tcp_socket_tx_window_advertised == 0) &&
169                       (socket_ptr -> nx_tcp_socket_state <= NX_TCP_CLOSE_WAIT)))
170             {
171 
172                 /* Update the transmit sequence that entered fast transmit. */
173                 socket_ptr -> nx_tcp_socket_tx_sequence_recover = socket_ptr -> nx_tcp_socket_tx_sequence - 1;
174 
175                 /* Retransmit the packet. */
176                 _nx_tcp_socket_retransmit(ip_ptr, socket_ptr, NX_FALSE);
177 
178                 /* Exit fast recovery procedure. */
179                 socket_ptr -> nx_tcp_socket_fast_recovery = NX_FALSE;
180                 socket_ptr -> nx_tcp_socket_tx_window_congestion = socket_ptr -> nx_tcp_socket_tx_slow_start_threshold;
181             }
182             else if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_FIN_WAIT_1) ||
183                      (socket_ptr -> nx_tcp_socket_state == NX_TCP_CLOSING)    ||
184                      (socket_ptr -> nx_tcp_socket_state == NX_TCP_LAST_ACK))
185             {
186 
187                 /* We have a timeout condition on sending the FIN... so it needs to be
188                    retried.  */
189 
190                 /* Increment the retry counter.  */
191                 socket_ptr -> nx_tcp_socket_timeout_retries++;
192 
193                 /* Setup the next timeout.  */
194                 socket_ptr -> nx_tcp_socket_timeout = socket_ptr -> nx_tcp_socket_timeout_rate <<
195                     (socket_ptr -> nx_tcp_socket_timeout_retries * socket_ptr -> nx_tcp_socket_timeout_shift);
196 
197                 /* Send another FIN packet.  */
198                 _nx_tcp_packet_send_fin(socket_ptr, (socket_ptr -> nx_tcp_socket_tx_sequence - 1));
199             }
200             else if (socket_ptr -> nx_tcp_socket_state == NX_TCP_TIMED_WAIT)
201             {
202 
203                 /* Clean the transmission control block.  */
204                 _nx_tcp_socket_block_cleanup(socket_ptr);
205             }
206         }
207 
208         /* Move to the next TCP socket.  */
209         socket_ptr =  socket_ptr -> nx_tcp_socket_created_next;
210     }
211 }
212 
213