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