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