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 #include "nx_packet.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_packet_process                       PORTABLE C      */
40 /*                                                           6.2.0        */
41 /*  AUTHOR                                                                */
42 /*                                                                        */
43 /*    Yuxin Zhou, Microsoft Corporation                                   */
44 /*                                                                        */
45 /*  DESCRIPTION                                                           */
46 /*                                                                        */
47 /*    This function processes an incoming TCP packet relative to the      */
48 /*    socket it belongs to, including processing state changes, and       */
49 /*    sending and receiving data.                                         */
50 /*                                                                        */
51 /*  INPUT                                                                 */
52 /*                                                                        */
53 /*    socket_ptr                            Pointer to owning socket      */
54 /*    packet_ptr                            Pointer to packet to process  */
55 /*                                                                        */
56 /*  OUTPUT                                                                */
57 /*                                                                        */
58 /*    None                                                                */
59 /*                                                                        */
60 /*  CALLS                                                                 */
61 /*                                                                        */
62 /*    _nx_packet_release                    Packet release function       */
63 /*    _nx_tcp_socket_connection_reset       Reset connection              */
64 /*    _nx_tcp_socket_state_ack_check        Process received ACKs         */
65 /*    _nx_tcp_socket_state_closing          Process CLOSING state         */
66 /*    _nx_tcp_socket_state_data_check       Process received data         */
67 /*    _nx_tcp_socket_state_established      Process ESTABLISHED state     */
68 /*    _nx_tcp_socket_state_fin_wait1        Process FIN WAIT 1 state      */
69 /*    _nx_tcp_socket_state_fin_wait2        Process FIN WAIT 2 state      */
70 /*    _nx_tcp_socket_state_last_ack         Process LAST ACK state        */
71 /*    _nx_tcp_socket_state_syn_received     Process SYN RECEIVED state    */
72 /*    _nx_tcp_socket_state_syn_sent         Process SYN SENT state        */
73 /*    _nx_tcp_socket_state_transmit_check   Check for transmit ability    */
74 /*    (nx_tcp_urgent_data_callback)         Application urgent callback   */
75 /*                                            function                    */
76 /*    _nx_http_proxy_client_connect_response_process                      */
77 /*                                          Process HTTP Proxy CONNECT    */
78 /*                                            response                    */
79 /*                                                                        */
80 /*  CALLED BY                                                             */
81 /*                                                                        */
82 /*    _nx_tcp_packet_process                Process raw TCP packet        */
83 /*                                                                        */
84 /*  RELEASE HISTORY                                                       */
85 /*                                                                        */
86 /*    DATE              NAME                      DESCRIPTION             */
87 /*                                                                        */
88 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
89 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
90 /*                                            resulting in version 6.1    */
91 /*  08-02-2021     Yuxin Zhou               Modified comment(s), and      */
92 /*                                            supported TCP/IP offload,   */
93 /*                                            resulting in version 6.1.8  */
94 /*  01-31-2022     Yuxin Zhou               Modified comment(s), and      */
95 /*                                            fixed unsigned integers     */
96 /*                                            comparison,                 */
97 /*                                            resulting in version 6.1.10 */
98 /*  10-31-2022     Wenhui Xie               Modified comment(s), and      */
99 /*                                            supported HTTP Proxy,       */
100 /*                                            resulting in version 6.2.0  */
101 /*                                                                        */
102 /**************************************************************************/
_nx_tcp_socket_packet_process(NX_TCP_SOCKET * socket_ptr,NX_PACKET * packet_ptr)103 VOID  _nx_tcp_socket_packet_process(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr)
104 {
105 
106 UINT          packet_queued =  NX_FALSE;
107 NX_TCP_HEADER tcp_header_copy;
108 VOID          (*urgent_callback)(NX_TCP_SOCKET *socket_ptr);
109 ULONG         header_length;
110 ULONG         packet_data_length;
111 ULONG         packet_sequence;
112 ULONG         rx_sequence;
113 ULONG         rx_window;
114 UINT          outside_of_window;
115 ULONG         mss = 0;
116 #ifdef NX_ENABLE_TCPIP_OFFLOAD
117 ULONG         tcpip_offload;
118 
119     tcpip_offload = socket_ptr -> nx_tcp_socket_connect_interface -> nx_interface_capability_flag &
120                     NX_INTERFACE_CAPABILITY_TCPIP_OFFLOAD;
121 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
122 
123     /* Add debug information. */
124     NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
125 
126     /* Copy the TCP header, since the actual packet can be delivered to
127        a waiting socket/thread during this routine and before we are done
128        using the header.  */
129     /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
130     tcp_header_copy =  *((NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr);
131 
132     /* Get the size of the TCP header.  */
133     header_length =  (tcp_header_copy.nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * (ULONG)sizeof(ULONG);
134 
135     /* Process the segment if socket state is equal or greater than NX_TCP_SYN_RECEIVED. According to RFC 793, Section 3.9, Page 69.  */
136     if ((socket_ptr -> nx_tcp_socket_state >= NX_TCP_SYN_RECEIVED)
137 #ifdef NX_ENABLE_TCPIP_OFFLOAD
138         && (!tcpip_offload)
139 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
140        )
141     {
142 
143         /* Step1: Check sequence number. According to RFC 793, Section 3.9, Page 69.  */
144 
145         /* Pickup the sequence of this packet. */
146         packet_sequence = tcp_header_copy.nx_tcp_sequence_number;
147 
148         /* Calculate the data length in the packet.  */
149         packet_data_length = packet_ptr -> nx_packet_length - header_length;
150 
151         /* Pickup the rx sequence.  */
152         rx_sequence = socket_ptr -> nx_tcp_socket_rx_sequence;
153 
154 #ifdef NX_ENABLE_LOW_WATERMARK
155         if ((socket_ptr -> nx_tcp_socket_rx_window_current == 0) &&
156             (socket_ptr -> nx_tcp_socket_receive_queue_head == NX_NULL) &&
157             (packet_ptr -> nx_packet_pool_owner -> nx_packet_pool_available >=
158              packet_ptr -> nx_packet_pool_owner -> nx_packet_pool_low_watermark))
159         {
160 
161             /* Window was closed due to low watermark of packet pool. */
162             /* Now reset the window size. */
163             socket_ptr -> nx_tcp_socket_rx_window_current =  socket_ptr -> nx_tcp_socket_rx_window_default;
164         }
165 #endif /* NX_ENABLE_LOW_WATERMARK */
166 
167         /* Pickup the rx window.  */
168         rx_window = socket_ptr -> nx_tcp_socket_rx_window_current;
169 
170         /* There are four cases for the acceptability test for an incoming segment.
171            Section 3.9 Page 69, RFC 793.  */
172         outside_of_window = NX_TRUE;
173 
174         if (packet_data_length == 0)
175         {
176             if (rx_window == 0)
177             {
178                 if (packet_sequence == rx_sequence)
179                 {
180                     outside_of_window = NX_FALSE;
181                 }
182                 else if ((tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_RST_BIT) ||
183                          (tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_URG_BIT) ||
184                          ((tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_CONTROL_MASK) == NX_TCP_ACK_BIT))
185                 {
186 
187                     /* If the RCV.WND is zero, no segments will be acceptable, but
188                        special allowance should be made to accept valid ACKs, URGs and RSTs.
189                        Section 3.9 Page 69, RFC 793. */
190                     outside_of_window = NX_FALSE;
191                 }
192             }
193             else if (((INT)(packet_sequence - rx_sequence) >= 0) &&
194                      ((INT)(rx_sequence + rx_window - packet_sequence) > 0))
195             {
196                 outside_of_window = NX_FALSE;
197             }
198         }
199         else
200         {
201             if ((rx_window > 0) &&
202                 ((((INT)(packet_sequence - rx_sequence) >= 0) &&
203                   ((INT)(rx_sequence + rx_window - packet_sequence) > 0)) ||
204                  (((INT)(packet_sequence + (packet_data_length - 1) - rx_sequence) >= 0) &&
205                   ((INT)(rx_sequence + 1 + (rx_window - packet_sequence) - packet_data_length) > 0))))
206             {
207                 outside_of_window = NX_FALSE;
208             }
209         }
210 
211         /* Detect whether or not the data is outside the window.  */
212         if (outside_of_window)
213         {
214 
215             /* If an incoming segment is not acceptable, an acknowledgment should be sent in reply
216                (unless the RST bit is set, if so drop the segment and return).
217                Section 3.9, Page 69, RFC 793.  */
218             if (!(tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_RST_BIT))
219             {
220 
221                 /* Send an immediate ACK.  */
222                 _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
223             }
224 
225 #ifndef NX_DISABLE_TCP_INFO
226 
227             /* Increment the TCP dropped packet count.  */
228             socket_ptr -> nx_tcp_socket_ip_ptr -> nx_ip_tcp_receive_packets_dropped++;
229 #endif
230 
231             /* Release the packet.  */
232             _nx_packet_release(packet_ptr);
233 
234             /* Finished processing, simply return!  */
235             return;
236         }
237 
238         /* Step2: Check the RST bit. According to RFC 793, Section 3.9, Page 70.  */
239         if (tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_RST_BIT)
240         {
241 
242 #ifndef NX_DISABLE_TCP_INFO
243 
244             /* Increment the resets received count.  */
245             (socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_resets_received++;
246 #endif
247 
248             /* If trace is enabled, insert this event into the trace buffer.  */
249             NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_RESET_RECEIVE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, packet_ptr, tcp_header_copy.nx_tcp_sequence_number, NX_TRACE_INTERNAL_EVENTS, 0, 0);
250 
251             /* Reset connection.  */
252             _nx_tcp_socket_connection_reset(socket_ptr);
253 
254             /* Release the packet.  */
255             _nx_packet_release(packet_ptr);
256 
257             /* Finished processing, simply return!  */
258             return;
259         }
260 
261         /* Step3: Check the SYN bit. According to RFC 793, Section 3.9, Page 71.  */
262         if (tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_SYN_BIT)
263         {
264 
265             /* The SYN is in the window it is an error, send a reset.  */
266 
267             /* Adjust the SEQ for the SYN bit. */
268             /* The reset logic uses the sequence number in tcp_header_ptr as its ACK number. */
269             tcp_header_copy.nx_tcp_sequence_number++;
270 
271             /* Send RST message.  */
272             _nx_tcp_packet_send_rst(socket_ptr, &tcp_header_copy);
273 
274             /* Reset the connection. */
275             _nx_tcp_socket_connection_reset(socket_ptr);
276 
277             /* Release the packet.  */
278             _nx_packet_release(packet_ptr);
279 
280             /* Finished processing, simply return!  */
281             return;
282         }
283 
284         /* Step4: Check the ACK field. According to RFC 793, Section 3.9, Page 72.  */
285         if (socket_ptr -> nx_tcp_socket_state != NX_TCP_SYN_RECEIVED)
286         {
287 
288             /* Check the ACK field.  */
289             if (_nx_tcp_socket_state_ack_check(socket_ptr, &tcp_header_copy) == NX_FALSE)
290             {
291 
292                 /* Release the packet.  */
293                 _nx_packet_release(packet_ptr);
294 
295                 /* Finished processing, simply return!  */
296                 return;
297             }
298         }
299     }
300 
301     /* Illegal option length check. */
302     if (header_length > sizeof(NX_TCP_HEADER))
303     {
304 
305         /* There are one or more option words.  */
306         /* The illegal option length is validated during MSS option get function. */
307         if (!_nx_tcp_mss_option_get((packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_TCP_HEADER)),
308                                     header_length - (ULONG)sizeof(NX_TCP_HEADER), &mss))
309         {
310 
311             /* TCP MUST be prepared to handle an illegal option length (e.g., zero) without crashing;
312                a suggested procedure is to reset the connection and log the reason, outlined in RFC 1122, Section 4.2.2.5, Page85. */
313 
314             /* Preprocess the sequence number if the incoming segment does not have an ACK field.
315                Reset Generation, RFC793, Section3.4, Page37. */
316             if (!(tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_ACK_BIT))
317             {
318 
319                 /* Update sequence number to set the reset acknowledge number.  */
320                 tcp_header_copy.nx_tcp_sequence_number += (packet_ptr -> nx_packet_length - header_length);
321 
322                 /* Check the SYN and FIN bits.  */
323                 if ((tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_SYN_BIT) ||
324                     (tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_FIN_BIT))
325                 {
326 
327                     /* Update sequence number to set the reset acknowledge number.  */
328                     tcp_header_copy.nx_tcp_sequence_number++;
329                 }
330             }
331 
332             /* Send RST message.  */
333             _nx_tcp_packet_send_rst(socket_ptr, &tcp_header_copy);
334 
335             /* Reset the connection. */
336             _nx_tcp_socket_connection_reset(socket_ptr);
337 
338 #ifndef NX_DISABLE_TCP_INFO
339             /* Increment the TCP invalid packet error count.  */
340             socket_ptr -> nx_tcp_socket_ip_ptr -> nx_ip_tcp_invalid_packets++;
341 #endif /* NX_DISABLE_TCP_INFO */
342 
343             /* Release the packet.  */
344             _nx_packet_release(packet_ptr);
345 
346             return;
347         }
348 
349     }
350 
351     /* Process relative to the state of the socket.  */
352     switch (socket_ptr -> nx_tcp_socket_state)
353     {
354 
355     case  NX_TCP_SYN_SENT:
356 
357         /* Call the SYN SENT state handling function to process any state
358            changes caused by this new packet.  */
359         _nx_tcp_socket_state_syn_sent(socket_ptr, &tcp_header_copy, packet_ptr);
360 
361         /* Check whether socket is established. */
362         if (socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED)
363         {
364 
365             /* Check for data in the current packet.  */
366             packet_queued =  _nx_tcp_socket_state_data_check(socket_ptr, packet_ptr);
367         }
368 
369         /* State processing is complete.  */
370         break;
371 
372     case  NX_TCP_SYN_RECEIVED:
373 
374         /* Call the SYN RECEIVED state handling function to process any state
375            changes caused by this new packet.  */
376         _nx_tcp_socket_state_syn_received(socket_ptr, &tcp_header_copy);
377 
378         /* Check whether socket is established. */
379         if (socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED)
380         {
381 
382             /* Check for data in the current packet.  */
383             packet_queued =  _nx_tcp_socket_state_data_check(socket_ptr, packet_ptr);
384         }
385 
386         /* State processing is complete.  */
387         break;
388 
389     case  NX_TCP_ESTABLISHED:
390 
391         /* Check for data in the current packet.  */
392         packet_queued =  _nx_tcp_socket_state_data_check(socket_ptr, packet_ptr);
393 
394 #ifdef NX_ENABLE_TCPIP_OFFLOAD
395         if (!tcpip_offload)
396 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
397         {
398 
399             /* Call the ESTABLISHED state handling function to process any state
400             changes caused by this new packet.  */
401             _nx_tcp_socket_state_established(socket_ptr);
402 
403             /* Determine if any transmit suspension can be lifted.  */
404             _nx_tcp_socket_state_transmit_check(socket_ptr);
405         }
406 
407         /* State processing is complete.  */
408         break;
409 
410     case  NX_TCP_CLOSE_WAIT:
411 
412         /* Determine if any transmit suspension can be lifted.  */
413         _nx_tcp_socket_state_transmit_check(socket_ptr);
414 
415         /* State processing is complete.  */
416         break;
417 
418     case  NX_TCP_LAST_ACK:
419 
420         /* Call the LAST ACK state handling function to process any state
421            changes caused by this new packet.  */
422         _nx_tcp_socket_state_last_ack(socket_ptr, &tcp_header_copy);
423 
424         /* State processing is complete.  */
425         break;
426 
427     case  NX_TCP_FIN_WAIT_1:
428 
429         /* Check for data in the current packet.  */
430         packet_queued =  _nx_tcp_socket_state_data_check(socket_ptr, packet_ptr);
431 
432         /* Call the FIN WAIT 1 state handling function to process any state
433            changes caused by this new packet.  */
434         _nx_tcp_socket_state_fin_wait1(socket_ptr);
435 
436         /* State processing is complete.  */
437         break;
438 
439     case  NX_TCP_FIN_WAIT_2:
440 
441         /* Check for data in the current packet.  */
442         packet_queued =  _nx_tcp_socket_state_data_check(socket_ptr, packet_ptr);
443 
444         /* Call the FIN WAIT 2 state handling function to process any state
445            changes caused by this new packet.  */
446         _nx_tcp_socket_state_fin_wait2(socket_ptr);
447 
448         /* State processing is complete.  */
449         break;
450 
451     case  NX_TCP_CLOSING:
452 
453         /* Call the CLOSING state handling function to process any state
454            changes caused by this new packet.  */
455         _nx_tcp_socket_state_closing(socket_ptr, &tcp_header_copy);
456 
457         /* State processing is complete.  */
458         break;
459 
460     case  NX_TCP_TIMED_WAIT:
461 
462         /* State processing is complete.  */
463         break;
464 
465     default:
466         break;
467     }
468 
469 #ifdef NX_ENABLE_HTTP_PROXY
470 
471     /* Check if HTTP Proxy is started and waiting for the response form the HTTP Proxy server.  */
472     if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED) &&
473         (socket_ptr -> nx_tcp_socket_ip_ptr -> nx_ip_http_proxy_enable) &&
474         (socket_ptr -> nx_tcp_socket_http_proxy_state == NX_HTTP_PROXY_STATE_CONNECTING))
475     {
476 
477         /* Receive and process the response.  */
478         _nx_http_proxy_client_connect_response_process(socket_ptr);
479     }
480 #endif /* NX_ENABLE_HTTP_PROXY */
481 
482     /* Check for an URG (urgent) bit set.  */
483     /*lint -e{644} suppress variable might not be initialized, since "tcp_header_copy" was initialized. */
484     if (tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_URG_BIT)
485     {
486 
487         /* Yes, an Urgent bit is set.  */
488 
489         /* Pickup the urgent callback function specified when the socket was created.  */
490         urgent_callback =  socket_ptr -> nx_tcp_urgent_data_callback;
491 
492         /* Determine if there is an urgent callback function specified.  */
493         if (urgent_callback)
494         {
495 
496             /* Yes, call the application's urgent callback function to alert the application
497                of the presence of the urgent bit.  */
498             (urgent_callback)(socket_ptr);
499         }
500     }
501 
502     /* Determine if we need to release the packet.  */
503     if (!packet_queued)
504     {
505 
506         /* Yes, the packet was not queued up above, so it needs to be released.  */
507         _nx_packet_release(packet_ptr);
508     }
509 }
510 
511