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