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_tcp.h"
30 #ifdef NX_ENABLE_HTTP_PROXY
31 #include "nx_http_proxy_client.h"
32 #endif /* NX_ENABLE_HTTP_PROXY */
33
34
35 /**************************************************************************/
36 /* */
37 /* FUNCTION RELEASE */
38 /* */
39 /* _nx_tcp_socket_state_syn_sent PORTABLE C */
40 /* 6.2.0 */
41 /* AUTHOR */
42 /* */
43 /* Yuxin Zhou, Microsoft Corporation */
44 /* */
45 /* DESCRIPTION */
46 /* */
47 /* This function processes packets during the SYN SENT state, which is */
48 /* the state of the socket immediately after the initial SYN is sent */
49 /* in the establishment of a TCP connection. We are expecting a SYN */
50 /* and an ACK from the other side of the connection in order to move */
51 /* into an established state. */
52 /* */
53 /* INPUT */
54 /* */
55 /* socket_ptr Pointer to owning socket */
56 /* tcp_header_ptr Pointer to packet header */
57 /* */
58 /* OUTPUT */
59 /* */
60 /* None */
61 /* */
62 /* CALLS */
63 /* */
64 /* _nx_tcp_packet_send_ack Send ACK packet */
65 /* _nx_tcp_packet_send_syn Send SYN packet */
66 /* _nx_tcp_packet_send_rst Send RST packet */
67 /* _nx_tcp_socket_thread_resume Resume suspended thread */
68 /* _nx_http_proxy_client_connect Connect with HTTP Proxy */
69 /* */
70 /* CALLED BY */
71 /* */
72 /* _nx_tcp_socket_packet_process Process TCP packet for socket */
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 /* 10-31-2022 Wenhui Xie Modified comment(s), and */
82 /* supported HTTP Proxy, */
83 /* resulting in version 6.2.0 */
84 /* */
85 /**************************************************************************/
_nx_tcp_socket_state_syn_sent(NX_TCP_SOCKET * socket_ptr,NX_TCP_HEADER * tcp_header_ptr,NX_PACKET * packet_ptr)86 VOID _nx_tcp_socket_state_syn_sent(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *tcp_header_ptr, NX_PACKET *packet_ptr)
87 {
88
89
90 #ifndef TX_ENABLE_EVENT_TRACE
91 NX_PARAMETER_NOT_USED(packet_ptr);
92 #endif /* TX_ENABLE_EVENT_TRACE */
93
94 /* Check if a RST is present. */
95 if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_RST_BIT)
96 {
97
98 /* Check if the ACK was acceptable. According to RFC 793, Section 3.9, Page 67. */
99 if ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT) &&
100 (tcp_header_ptr -> nx_tcp_acknowledgment_number == socket_ptr -> nx_tcp_socket_tx_sequence))
101 {
102
103 #ifndef NX_DISABLE_TCP_INFO
104
105 /* Increment the resets received count. */
106 (socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_resets_received++;
107 #endif
108
109 /* If trace is enabled, insert this event into the trace buffer. */
110 NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_RESET_RECEIVE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, packet_ptr, tcp_header_ptr -> nx_tcp_sequence_number, NX_TRACE_INTERNAL_EVENTS, 0, 0);
111
112 /* Reset connection. */
113 _nx_tcp_socket_connection_reset(socket_ptr);
114 }
115
116 /* Finished processing, simply return! */
117 return;
118 }
119 /* Determine if a valid SYN/ACK is present. */
120 else if ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT) &&
121 (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT) &&
122 (tcp_header_ptr -> nx_tcp_acknowledgment_number == socket_ptr -> nx_tcp_socket_tx_sequence))
123 {
124
125 /* Yes, this is a proper SYN/ACK message. We need to send an ACK
126 back the other direction before we go into the ESTABLISHED
127 state. */
128
129 /* Save the sequence number. */
130 socket_ptr -> nx_tcp_socket_rx_sequence = tcp_header_ptr -> nx_tcp_sequence_number + 1;
131
132 /* Save the window size. */
133 socket_ptr -> nx_tcp_socket_tx_window_advertised = tcp_header_ptr -> nx_tcp_header_word_3 & NX_LOWER_16_MASK;
134
135 #ifdef NX_ENABLE_TCP_WINDOW_SCALING
136
137 /* The window size advertised in the SYN packet is NEVER scaled. Therefore there is no
138 need to apply the scale shift. However validate snd_win_scale and rcv_win_scale. */
139 if (socket_ptr -> nx_tcp_snd_win_scale_value == 0xFF)
140 {
141 /* Peer does not support window scale option. */
142 socket_ptr -> nx_tcp_snd_win_scale_value = 0;
143 socket_ptr -> nx_tcp_rcv_win_scale_value = 0;
144
145 /* Since the peer does not offer window scaling feature, make sure
146 our default window size for this connection does not exceed 65535 bytes. */
147 if (socket_ptr -> nx_tcp_socket_rx_window_maximum > 65535)
148 {
149 socket_ptr -> nx_tcp_socket_rx_window_default = 65535;
150 socket_ptr -> nx_tcp_socket_rx_window_current = 65535;
151 }
152 }
153
154 #endif /* NX_ENABLE_TCP_WINDOW_SCALING */
155
156 /* Initialize the slow start threshold to be the advertised window size. */
157 socket_ptr -> nx_tcp_socket_tx_slow_start_threshold = socket_ptr -> nx_tcp_socket_tx_window_advertised;
158
159 /* Set the Initial transmit outstanding byte count. */
160 socket_ptr -> nx_tcp_socket_tx_outstanding_bytes = 0;
161
162 /* Set the initial congestion control window size. */
163 /* Section 3.1, Page 5, RFC5681. */
164 if (socket_ptr -> nx_tcp_socket_timeout_retries > 0)
165 {
166
167 /* Set the initial congestion control window size to be the mss. */
168 socket_ptr -> nx_tcp_socket_tx_window_congestion = socket_ptr -> nx_tcp_socket_connect_mss;
169 }
170 else
171 {
172 socket_ptr -> nx_tcp_socket_tx_window_congestion = (socket_ptr -> nx_tcp_socket_connect_mss << 2);
173 if (socket_ptr -> nx_tcp_socket_connect_mss > 1095)
174 {
175 socket_ptr -> nx_tcp_socket_tx_window_congestion -= socket_ptr -> nx_tcp_socket_connect_mss;
176 }
177 if (socket_ptr -> nx_tcp_socket_connect_mss > 2190)
178 {
179 socket_ptr -> nx_tcp_socket_tx_window_congestion -= socket_ptr -> nx_tcp_socket_connect_mss;
180 }
181 }
182
183 /* Send the ACK. */
184 _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
185
186 /* If trace is enabled, insert this event into the trace buffer. */
187 NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_ESTABLISHED, NX_TRACE_INTERNAL_EVENTS, 0, 0);
188
189 /* Move to the ESTABLISHED state. */
190 socket_ptr -> nx_tcp_socket_state = NX_TCP_ESTABLISHED;
191
192 /* Clear the socket timeout. */
193 socket_ptr -> nx_tcp_socket_timeout = 0;
194
195 #ifdef NX_ENABLE_TCP_KEEPALIVE
196 /* Is the keepalive feature enabled on this socket? */
197 if (socket_ptr -> nx_tcp_socket_keepalive_enabled)
198 {
199 /* Setup the TCP Keepalive timer to initial values. */
200 socket_ptr -> nx_tcp_socket_keepalive_timeout = NX_TCP_KEEPALIVE_INITIAL;
201 socket_ptr -> nx_tcp_socket_keepalive_retries = 0;
202 }
203 #endif
204
205 #ifdef NX_ENABLE_HTTP_PROXY
206
207 /* Check if the HTTP Proxy is started and waiting for TCP socket connection. */
208 if ((socket_ptr -> nx_tcp_socket_ip_ptr -> nx_ip_http_proxy_enable) &&
209 (socket_ptr -> nx_tcp_socket_http_proxy_state == NX_HTTP_PROXY_STATE_WAITING))
210 {
211
212 /* TCP connection established, start the HTTP Proxy connection. */
213 _nx_http_proxy_client_connect(socket_ptr);
214 }
215 else
216 #endif /* NX_ENABLE_HTTP_PROXY */
217 {
218 #ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT
219
220 /* Is a connection completion callback registered with the TCP socket? */
221 if (socket_ptr -> nx_tcp_establish_notify)
222 {
223
224 /* Call the application's establish callback function. */
225 (socket_ptr -> nx_tcp_establish_notify)(socket_ptr);
226 }
227 #endif
228
229 /* Determine if we need to wake a thread suspended on the connection. */
230 if (socket_ptr -> nx_tcp_socket_connect_suspended_thread)
231 {
232
233 /* Resume the suspended thread. */
234 _nx_tcp_socket_thread_resume(&(socket_ptr -> nx_tcp_socket_connect_suspended_thread), NX_SUCCESS);
235 }
236 }
237 }
238 else if ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT) &&
239 (!(tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT)))
240 {
241
242 /* Simultaneous Connection Synchronization,
243 A SYN message was received. We need to send both a SYN and ACK and move to the SYN RECEIVED state. */
244
245 /* Save the sequence number. */
246 socket_ptr -> nx_tcp_socket_rx_sequence = tcp_header_ptr -> nx_tcp_sequence_number + 1;
247
248 /* Save the window size. */
249 socket_ptr -> nx_tcp_socket_tx_window_advertised = tcp_header_ptr -> nx_tcp_header_word_3 & NX_LOWER_16_MASK;
250
251 #ifdef NX_ENABLE_TCP_WINDOW_SCALING
252 socket_ptr -> nx_tcp_socket_tx_window_advertised <<= socket_ptr -> nx_tcp_rcv_win_scale_value;
253 #endif /* NX_ENABLE_TCP_WINDOW_SCALING */
254
255 /* Initialize the slow start threshold to be the advertised window size. */
256 socket_ptr -> nx_tcp_socket_tx_slow_start_threshold = socket_ptr -> nx_tcp_socket_tx_window_advertised;
257
258 /* Set the initial congestion control window size. */
259 /* Section 3.1, Page 5, RFC5681. */
260 socket_ptr -> nx_tcp_socket_tx_window_congestion = (socket_ptr -> nx_tcp_socket_connect_mss << 2);
261 if (socket_ptr -> nx_tcp_socket_connect_mss > 1095)
262 {
263 socket_ptr -> nx_tcp_socket_tx_window_congestion -= socket_ptr -> nx_tcp_socket_connect_mss;
264 }
265 if (socket_ptr -> nx_tcp_socket_connect_mss > 2190)
266 {
267 socket_ptr -> nx_tcp_socket_tx_window_congestion -= socket_ptr -> nx_tcp_socket_connect_mss;
268 }
269
270 /* Set the Initial transmit outstanding byte count. */
271 socket_ptr -> nx_tcp_socket_tx_outstanding_bytes = 0;
272
273 /* If trace is enabled, insert this event into the trace buffer. */
274 NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_SYN_RECEIVED, NX_TRACE_INTERNAL_EVENTS, 0, 0);
275
276 /* Move to the SYN RECEIVED state. */
277 socket_ptr -> nx_tcp_socket_state = NX_TCP_SYN_RECEIVED;
278
279 /* Clear the timeout. */
280 socket_ptr -> nx_tcp_socket_timeout = 0;
281
282 /* Send the SYN packet. */
283 _nx_tcp_packet_send_syn(socket_ptr, (socket_ptr -> nx_tcp_socket_tx_sequence - 1));
284 }
285 /* Check for an invalid response to an attempted connection. */
286 else if ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT) &&
287 (tcp_header_ptr -> nx_tcp_acknowledgment_number != socket_ptr -> nx_tcp_socket_tx_sequence))
288 {
289
290 /* Invalid response was received, it is likely that the other side still
291 thinks a previous connection is active. Send a reset (RST) message to
292 the other side to clear any previous connection. */
293
294 /* Send the RST packet. */
295 _nx_tcp_packet_send_rst(socket_ptr, tcp_header_ptr);
296 }
297 }
298
299