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