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