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 /* Include necessary system files.  */
24 
25 #include "nx_api.h"
26 #include "nx_packet.h"
27 #include "nx_ip.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_data_trim                      PORTABLE C      */
39 /*                                                           6.2.0        */
40 /*  AUTHOR                                                                */
41 /*                                                                        */
42 /*    Yuxin Zhou, Microsoft Corporation                                   */
43 /*                                                                        */
44 /*  DESCRIPTION                                                           */
45 /*                                                                        */
46 /*    This function trims extra bytes from the data packet.               */
47 /*    This is an internal utility function, only used by                  */
48 /*    _nx_tcp_socket_state_data_check.                                    */
49 /*                                                                        */
50 /*  INPUT                                                                 */
51 /*                                                                        */
52 /*    packet_ptr                            Pointer to packet to process  */
53 /*    amount                                Number of bytes to remove     */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    None                                                                */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    _nx_packet_release                    Release packet on overlap     */
62 /*                                                                        */
63 /*  CALLED BY                                                             */
64 /*                                                                        */
65 /*    _nx_tcp_socket_state_data_check       Process TCP packet for socket */
66 /*                                                                        */
67 /*  RELEASE HISTORY                                                       */
68 /*                                                                        */
69 /*    DATE              NAME                      DESCRIPTION             */
70 /*                                                                        */
71 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
72 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
73 /*                                            resulting in version 6.1    */
74 /*  10-31-2022     Wenhui Xie               Modified comment(s), and      */
75 /*                                            supported HTTP Proxy,       */
76 /*                                            resulting in version 6.2.0  */
77 /*                                                                        */
78 /**************************************************************************/
_nx_tcp_socket_state_data_trim(NX_PACKET * packet_ptr,ULONG amount)79 VOID _nx_tcp_socket_state_data_trim(NX_PACKET *packet_ptr, ULONG amount)
80 {
81 ULONG      bytes_to_keep;
82 NX_PACKET *work_ptr;
83 
84     if (amount >= packet_ptr -> nx_packet_length)
85     {
86         /* Invalid input. */
87         return;
88     }
89 
90     bytes_to_keep = packet_ptr -> nx_packet_length - amount;
91 
92     packet_ptr -> nx_packet_length = bytes_to_keep;
93 
94     work_ptr = packet_ptr;
95 
96 #ifndef NX_DISABLE_PACKET_CHAIN
97     /* Walk down the packet chain for the "bytes_to_keep" amount. */
98     while (work_ptr)
99     {
100 
101     NX_PACKET *tmp_ptr;
102 
103         /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
104         if ((INT)(work_ptr -> nx_packet_append_ptr - work_ptr -> nx_packet_prepend_ptr) < (INT)bytes_to_keep)
105         {
106 
107             /*lint -e{923} suppress cast of pointer to ULONG.  */
108             bytes_to_keep -= (ULONG)((ALIGN_TYPE)work_ptr -> nx_packet_append_ptr - (ALIGN_TYPE)work_ptr -> nx_packet_prepend_ptr);
109 
110             work_ptr = work_ptr -> nx_packet_next;
111 
112             continue;
113         }
114 #endif /* NX_DISABLE_PACKET_CHAIN */
115 
116         /* This is the last packet. */
117         work_ptr -> nx_packet_append_ptr = work_ptr -> nx_packet_prepend_ptr + bytes_to_keep;
118 
119 #ifndef NX_DISABLE_PACKET_CHAIN
120         /* Free the rest of the packet chain. */
121         tmp_ptr = work_ptr -> nx_packet_next;
122         work_ptr -> nx_packet_next = NX_NULL;
123         work_ptr = tmp_ptr;
124 
125         if (work_ptr)
126         {
127 
128             /*lint -e{923} suppress cast of ULONG to pointer.  */
129             work_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED;
130 
131             _nx_packet_release(work_ptr);
132 
133             /* All done. Break out of the while loop and return. */
134             break;
135         }
136     }
137 #endif /* NX_DISABLE_PACKET_CHAIN */
138 }
139 
140 /**************************************************************************/
141 /*                                                                        */
142 /*  FUNCTION                                               RELEASE        */
143 /*                                                                        */
144 /*    _nx_tcp_socket_state_data_trim_front                PORTABLE C      */
145 /*                                                           6.1          */
146 /*  AUTHOR                                                                */
147 /*                                                                        */
148 /*    Yuxin Zhou, Microsoft Corporation                                   */
149 /*                                                                        */
150 /*  DESCRIPTION                                                           */
151 /*                                                                        */
152 /*    This function trims extra bytes from the data packet.               */
153 /*    This is an internal utility function, only used by                  */
154 /*    _nx_tcp_socket_state_data_check.                                    */
155 /*                                                                        */
156 /*  INPUT                                                                 */
157 /*                                                                        */
158 /*    packet_ptr                            Pointer to packet to process  */
159 /*    amount                                Number of bytes to remove     */
160 /*                                                                        */
161 /*  OUTPUT                                                                */
162 /*                                                                        */
163 /*    None                                                                */
164 /*                                                                        */
165 /*  CALLS                                                                 */
166 /*                                                                        */
167 /*    _nx_packet_release                    Release packet on overlap     */
168 /*                                                                        */
169 /*  CALLED BY                                                             */
170 /*                                                                        */
171 /*    _nx_tcp_socket_state_data_check       Process TCP packet for socket */
172 /*                                                                        */
173 /*  RELEASE HISTORY                                                       */
174 /*                                                                        */
175 /*    DATE              NAME                      DESCRIPTION             */
176 /*                                                                        */
177 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
178 /*  09-30-2020     Yuxin Zhou               Modified comment(s), and      */
179 /*                                            verified memmove use cases, */
180 /*                                            resulting in version 6.1    */
181 /*                                                                        */
182 /**************************************************************************/
_nx_tcp_socket_state_data_trim_front(NX_PACKET * packet_ptr,ULONG amount)183 VOID _nx_tcp_socket_state_data_trim_front(NX_PACKET *packet_ptr, ULONG amount)
184 {
185 NX_PACKET *work_ptr = packet_ptr;
186 ULONG      work_length;
187 
188     if (amount >= packet_ptr -> nx_packet_length || amount == 0)
189     {
190         /* Invalid input. */
191         return;
192     }
193 
194     /* Adjust the packet length.  */
195     packet_ptr -> nx_packet_length -= amount;
196 
197     /* Move prepend_ptr of first packet to TCP data.  */
198     packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_TCP_HEADER);
199 
200 #ifndef NX_DISABLE_PACKET_CHAIN
201     /* Walk down the packet chain for the amount. */
202     while (amount)
203     {
204 #endif /* NX_DISABLE_PACKET_CHAIN */
205 
206         /* Compute the size of the data portion work_ptr.  */
207         /*lint -e{923} suppress cast of pointer to ULONG.  */
208         work_length = (ULONG)((ALIGN_TYPE)work_ptr -> nx_packet_append_ptr - (ALIGN_TYPE)work_ptr -> nx_packet_prepend_ptr);
209 
210 #ifndef NX_DISABLE_PACKET_CHAIN
211         if (amount > work_length)
212         {
213 
214             /* All data in work_ptr need to be trimmed.  */
215             if (work_ptr == packet_ptr)
216             {
217 
218                 /* This packet is the header of packet chain.  */
219                 /* Clear TCP data in this packet.  */
220                 work_ptr -> nx_packet_append_ptr = work_ptr -> nx_packet_prepend_ptr;
221             }
222             else
223             {
224 
225                 /* This packet is not the first packet.  */
226                 /* Remove work_ptr from packet chain.  */
227                 packet_ptr -> nx_packet_next = work_ptr -> nx_packet_next;
228 
229                 /* Disconnect work_ptr from the rest of the packet chain. */
230                 work_ptr -> nx_packet_next = NX_NULL;
231 
232                 /* Mark the packet as ALLOCATED. */
233                 /*lint -e{923} suppress cast of ULONG to pointer.  */
234                 work_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED;
235 
236                 _nx_packet_release(work_ptr);
237             }
238             /* Reduce the amount being trimmed.  */
239             amount -= work_length;
240 
241             /* Move to the next packet. */
242             work_ptr = packet_ptr -> nx_packet_next;
243         }
244         else
245         {
246 
247             /* This is the last packet to trim.  */
248 
249             if (work_ptr == packet_ptr)
250             {
251 #endif /* NX_DISABLE_PACKET_CHAIN */
252 
253                 /* For the first packet, move data towards the beginning
254                    of the packet, right after TCP header.  */
255                 memmove(packet_ptr -> nx_packet_prepend_ptr, /* Use case of memmove is verified.  */
256                         packet_ptr -> nx_packet_prepend_ptr + amount,
257                         work_length - amount);
258                 packet_ptr -> nx_packet_append_ptr -= amount;
259 #ifndef NX_DISABLE_PACKET_CHAIN
260             }
261             else
262             {
263 
264                 /* Advance nx_packet_prepend_ptr to where the usable data starts. */
265                 work_ptr -> nx_packet_prepend_ptr += amount;
266             }
267 
268             /* Cut down amount*/
269             amount = 0;
270         }
271     }
272 #endif /* NX_DISABLE_PACKET_CHAIN */
273 
274     /* Restore prepend_ptr of first packet to TCP data.  */
275     packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_TCP_HEADER);
276 }
277 
278 
279 /**************************************************************************/
280 /*                                                                        */
281 /*  FUNCTION                                               RELEASE        */
282 /*                                                                        */
283 /*    _nx_tcp_socket_state_data_check                     PORTABLE C      */
284 /*                                                           6.3.0        */
285 /*  AUTHOR                                                                */
286 /*                                                                        */
287 /*    Yuxin Zhou, Microsoft Corporation                                   */
288 /*                                                                        */
289 /*  DESCRIPTION                                                           */
290 /*                                                                        */
291 /*    This function looks for incoming data from packets received         */
292 /*    primarily in the ESTABLISHED state, but also in the later states    */
293 /*    of connection and the early disconnection states.                   */
294 /*                                                                        */
295 /*  INPUT                                                                 */
296 /*                                                                        */
297 /*    socket_ptr                            Pointer to owning socket      */
298 /*    packet_ptr                            Pointer to packet to process  */
299 /*                                                                        */
300 /*  OUTPUT                                                                */
301 /*                                                                        */
302 /*    NX_TRUE                               If the packet had data        */
303 /*    NX_FALSE                              If the packet had no data     */
304 /*                                                                        */
305 /*  CALLS                                                                 */
306 /*                                                                        */
307 /*    _nx_packet_release                    Release packet on overlap     */
308 /*    _nx_tcp_socket_thread_resume          Resume suspended thread       */
309 /*    _nx_tcp_packet_send_ack               Send immediate ACK            */
310 /*    (nx_tcp_receive_callback)             Packet receive notify function*/
311 /*    _nx_tcp_socket_state_data_trim        Trim off extra bytes          */
312 /*    _nx_tcp_socket_state_data_trim_front  Trim off front extra bytes    */
313 /*                                                                        */
314 /*  CALLED BY                                                             */
315 /*                                                                        */
316 /*    _nx_tcp_socket_packet_process         Process TCP packet for socket */
317 /*                                                                        */
318 /*  RELEASE HISTORY                                                       */
319 /*                                                                        */
320 /*    DATE              NAME                      DESCRIPTION             */
321 /*                                                                        */
322 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
323 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
324 /*                                            resulting in version 6.1    */
325 /*  08-02-2021     Yuxin Zhou               Modified comment(s), and      */
326 /*                                            supported TCP/IP offload,   */
327 /*                                            resulting in version 6.1.8  */
328 /*  01-31-2022     Yuxin Zhou               Modified comment(s), and      */
329 /*                                            fixed unsigned integers     */
330 /*                                            comparison,                 */
331 /*                                            resulting in version 6.1.10 */
332 /*  10-31-2022     Wenhui Xie               Modified comment(s), and      */
333 /*                                            supported HTTP Proxy,       */
334 /*                                            resulting in version 6.2.0  */
335 /*  10-31-2023     Bo Chen                 Modified comment(s), corrected */
336 /*                                            the acked packet count,     */
337 /*                                            resulting in version 6.3.0  */
338 /*                                                                        */
339 /**************************************************************************/
_nx_tcp_socket_state_data_check(NX_TCP_SOCKET * socket_ptr,NX_PACKET * packet_ptr)340 UINT  _nx_tcp_socket_state_data_check(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr)
341 {
342 
343 NX_TCP_HEADER *tcp_header_ptr;
344 NX_TCP_HEADER *search_header_ptr;
345 NX_PACKET     *search_ptr;
346 NX_PACKET     *previous_ptr;
347 ULONG          expected_sequence;
348 ULONG          header_length;
349 ULONG          search_header_length;
350 ULONG          packet_begin_sequence;
351 ULONG          packet_end_sequence;
352 ULONG          packet_data_length;
353 ULONG          search_begin_sequence;
354 ULONG          search_end_sequence;
355 ULONG          original_rx_sequence;
356 ULONG          trim_data_length;
357 TX_THREAD     *thread_ptr;
358 ULONG          acked_packets = 0;
359 UINT           need_ack = NX_FALSE;
360 #ifdef NX_ENABLE_TCPIP_OFFLOAD
361 ULONG          tcpip_offload;
362 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
363 #ifdef NX_ENABLE_LOW_WATERMARK
364 UCHAR          drop_packet = NX_FALSE;
365 #endif /* NX_ENABLE_LOW_WATERMARK */
366 #if ((!defined(NX_DISABLE_TCP_INFO)) || defined(TX_ENABLE_EVENT_TRACE))
367 NX_IP         *ip_ptr;
368 
369     /* Setup the IP pointer.  */
370     ip_ptr =  socket_ptr -> nx_tcp_socket_ip_ptr;
371 #endif
372 
373 #ifdef NX_ENABLE_TCPIP_OFFLOAD
374     tcpip_offload = socket_ptr -> nx_tcp_socket_connect_interface -> nx_interface_capability_flag &
375                     NX_INTERFACE_CAPABILITY_TCPIP_OFFLOAD;
376 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
377 
378     /* Pickup the pointer to the head of the TCP packet.  */
379     /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
380     tcp_header_ptr =  (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
381 
382     /* Determine the size of the TCP header.  */
383     header_length =  (tcp_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * (ULONG)sizeof(ULONG);
384 
385     /* Record the original rx_sequence. */
386     original_rx_sequence = socket_ptr -> nx_tcp_socket_rx_sequence;
387 
388     /* Pickup the begin sequence of this packet. */
389     packet_begin_sequence = tcp_header_ptr -> nx_tcp_sequence_number;
390 
391     /* Calculate the data length in the packet.  */
392     packet_data_length = packet_ptr -> nx_packet_length - header_length;
393 
394     /* Pickup the end sequence of this packet. The end sequence is one byte to the last byte in this packet. */
395     packet_end_sequence =  tcp_header_ptr -> nx_tcp_sequence_number + packet_data_length;
396 
397     /* Trim the data that out of the receive window, make sure all data are in receive window.  */
398     if (packet_data_length
399 #ifdef NX_ENABLE_TCPIP_OFFLOAD
400         && (!tcpip_offload)
401 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
402        )
403     {
404 
405         /* Step1. trim the data on the left side of the receive window.  */
406         if (((INT)(socket_ptr -> nx_tcp_socket_rx_sequence - packet_begin_sequence)) > 0)
407         {
408 
409             /* Calculate the data length that out of window.  */
410             trim_data_length = socket_ptr -> nx_tcp_socket_rx_sequence - packet_begin_sequence;
411 
412             /* Trim the data that exceed the receive window.  */
413             _nx_tcp_socket_state_data_trim_front(packet_ptr, trim_data_length);
414 
415             /* Fix the sequence of this packet. */
416             tcp_header_ptr -> nx_tcp_sequence_number += trim_data_length;
417 
418             /* Update the data length and begin sequence.  */
419             packet_data_length -= trim_data_length;
420             packet_begin_sequence += trim_data_length;
421         }
422 
423         /* Step2. trim the data on the right side of the receive window.  */
424         if (((INT)((packet_end_sequence - socket_ptr -> nx_tcp_socket_rx_sequence) -
425                    socket_ptr -> nx_tcp_socket_rx_window_current)) > 0)
426         {
427 
428             /* Calculate the data length that out of window.  */
429             trim_data_length = packet_end_sequence - (socket_ptr -> nx_tcp_socket_rx_sequence + socket_ptr -> nx_tcp_socket_rx_window_current);
430 
431             /* Trim the data that exceed the receive window.  */
432             _nx_tcp_socket_state_data_trim(packet_ptr, trim_data_length);
433 
434             /* Update the data length and end sequence.  */
435             packet_data_length -= trim_data_length;
436             packet_end_sequence -= trim_data_length;
437         }
438     }
439 
440     /* Determine if the packet has the FIN bit set to signal a disconnect.  */
441     if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_FIN_BIT)
442     {
443 
444         /* Setup the FIN sequence number that we need to look at.  */
445         socket_ptr -> nx_tcp_socket_fin_sequence =  tcp_header_ptr -> nx_tcp_sequence_number + packet_data_length;
446 
447         /* Indicate that the FIN sequence is now valid.  Once the receive chain is complete
448            we will process (ACK) the FIN command which is part of a disconnect started by the
449            other side of the connection.  */
450         socket_ptr -> nx_tcp_socket_fin_received =  NX_TRUE;
451 
452         /* If trace is enabled, insert this event into the trace buffer.  */
453         NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_FIN_RECEIVE, ip_ptr, socket_ptr, packet_ptr, tcp_header_ptr -> nx_tcp_sequence_number, NX_TRACE_INTERNAL_EVENTS, 0, 0);
454     }
455 
456     /* Compute the amount of payload data in this packet. */
457     if (packet_data_length == 0)
458     {
459         /* This packet does not contain TCP data payload.  */
460 
461         /* Check for invalid sequence number.  */
462         if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED) &&
463             (socket_ptr -> nx_tcp_socket_receive_queue_count == 0) &&
464             (socket_ptr -> nx_tcp_socket_rx_sequence != tcp_header_ptr -> nx_tcp_sequence_number) &&
465             ((socket_ptr -> nx_tcp_socket_rx_sequence - 1) != tcp_header_ptr -> nx_tcp_sequence_number))
466         {
467 
468             /* Send an immediate ACK.  */
469             _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
470         }
471 
472         /* This packet does not have data, so return false. */
473         return(NX_FALSE);
474     }
475 
476 
477     /* If trace is enabled, insert this event into the trace buffer.  */
478     NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_DATA_RECEIVE, ip_ptr, socket_ptr, packet_ptr, tcp_header_ptr -> nx_tcp_sequence_number, NX_TRACE_INTERNAL_EVENTS, 0, 0);
479 
480     /* Ensure the next pointer in the packet is set to NULL, which will indicate to the
481        receive logic that it is not yet part of a contiguous stream.  */
482     packet_ptr -> nx_packet_queue_next =  (NX_PACKET *)NX_NULL;
483 
484     /* Otherwise, the packet is within the receive window so continue processing
485        the incoming TCP data.  */
486 
487     /* Pickup the tail pointer of the receive queue.  */
488     search_ptr = socket_ptr -> nx_tcp_socket_receive_queue_tail;
489 
490     /* Check to see if the tail pointer is part of a contiguous stream.  */
491     if (search_ptr)
492     {
493 
494         /* Setup a pointer to header of this packet in the sent list.  */
495         /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
496         search_header_ptr =  (NX_TCP_HEADER *)search_ptr -> nx_packet_prepend_ptr;
497 
498         /* Determine the size of the search TCP header.  */
499         search_header_length =  (search_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * (ULONG)sizeof(ULONG);
500 
501         /* Now see if the current sequence number accounts for the last packet.  */
502         search_end_sequence = search_header_ptr -> nx_tcp_sequence_number  + search_ptr -> nx_packet_length - search_header_length;
503     }
504     else
505     {
506 
507         /* Set the sequence number to the socket's receive sequence if there isn't a receive
508            packet on the queue.  */
509         search_end_sequence =  socket_ptr -> nx_tcp_socket_rx_sequence;
510     }
511 
512     /* Does the number of queued packets exceed the maximum rx queue length, or the number of
513      * available packets in the default packet pool reaches low watermark? */
514 #ifdef NX_ENABLE_LOW_WATERMARK
515     if (((socket_ptr -> nx_tcp_socket_receive_queue_count >=
516           socket_ptr -> nx_tcp_socket_receive_queue_maximum) ||
517          (packet_ptr -> nx_packet_pool_owner -> nx_packet_pool_available <
518           packet_ptr -> nx_packet_pool_owner -> nx_packet_pool_low_watermark))
519 #ifdef NX_ENABLE_TCPIP_OFFLOAD
520          && (!tcpip_offload)
521 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
522        )
523     {
524 
525         /* Yes it is. The last packet in queue should be dropped. */
526         drop_packet = NX_TRUE;
527     }
528 #endif /* NX_ENABLE_LOW_WATERMARK */
529 
530     /* Determine if we have a simple case of TCP data coming in the correct order.  This means
531        the socket's sequence number matches the incoming packet sequence number and the last packet's
532        data on the socket's receive queue (if any) matches the current sequence number.  */
533     if (((tcp_header_ptr -> nx_tcp_sequence_number == socket_ptr -> nx_tcp_socket_rx_sequence) &&
534          (search_end_sequence == socket_ptr -> nx_tcp_socket_rx_sequence))
535 #ifdef NX_ENABLE_TCPIP_OFFLOAD
536          || tcpip_offload
537 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
538        )
539     {
540 
541         /* Yes, this is the simple case of adding receive packets in sequence.  */
542 #ifdef NX_ENABLE_LOW_WATERMARK
543         /* If this packet is to be dropped, do nothing. */
544         if (drop_packet == NX_FALSE)
545         {
546 #endif /* NX_ENABLE_LOW_WATERMARK */
547 
548             /* Mark the packet as ready. This is done to simplify the logic in socket receive.  */
549             /*lint -e{923} suppress cast of ULONG to pointer.  */
550             packet_ptr -> nx_packet_queue_next =  (NX_PACKET *)NX_PACKET_READY;
551 
552             /* Add debug information. */
553             NX_PACKET_DEBUG(NX_PACKET_TCP_RECEIVE_QUEUE, __LINE__, packet_ptr);
554 
555             /* Place the packet on the receive queue.  Search pointer still points to the tail packet on
556                the queue.  */
557             if (search_ptr)
558             {
559 
560                 /* Nonempty receive queue, add packet to the end of the receive queue.  */
561                 search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next =  packet_ptr;
562 
563                 /* Update the tail of the receive queue.  */
564                 socket_ptr -> nx_tcp_socket_receive_queue_tail =  packet_ptr;
565             }
566             else
567             {
568 
569                 /* Empty receive queue.  Set both the head and the tail pointers this packet.  */
570                 socket_ptr -> nx_tcp_socket_receive_queue_head =  packet_ptr;
571                 socket_ptr -> nx_tcp_socket_receive_queue_tail =  packet_ptr;
572 
573                 /* Setup a new delayed ACK timeout.  */
574 #ifdef NX_ENABLE_TCPIP_OFFLOAD
575                 if (!tcpip_offload)
576 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
577                 {
578                     socket_ptr -> nx_tcp_socket_delayed_ack_timeout =  _nx_tcp_ack_timer_rate;
579                 }
580             }
581 
582             /* Increment the receive TCP packet count.  */
583             socket_ptr -> nx_tcp_socket_receive_queue_count++;
584 
585             /* Set the next pointer to indicate the packet is part of a TCP queue.  */
586             /*lint -e{923} suppress cast of ULONG to pointer.  */
587             packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next =  (NX_PACKET *)NX_PACKET_ENQUEUED;
588 
589             /* Calculate the next sequence number.  */
590             socket_ptr -> nx_tcp_socket_rx_sequence =  packet_end_sequence;
591 
592             /* All packets can be acked. */
593             acked_packets = socket_ptr -> nx_tcp_socket_receive_queue_count;
594 #ifdef NX_ENABLE_LOW_WATERMARK
595         }
596         else
597         {
598 
599             /* Release this packet. */
600             _nx_packet_release(packet_ptr);
601 
602             /* Set window to zero. */
603             socket_ptr -> nx_tcp_socket_rx_window_current = 0;
604             socket_ptr -> nx_tcp_socket_rx_window_last_sent = 0;
605 
606             /* Send zero window. */
607             _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
608 
609             /* All packets can be acked. */
610             acked_packets = socket_ptr -> nx_tcp_socket_receive_queue_count;
611         }
612 #endif /* NX_ENABLE_LOW_WATERMARK */
613 
614         /* End of the simple case: add new packet towards the end of the recv queue.
615            All packets in the receive queue are in sequence. */
616     }
617     else if (socket_ptr -> nx_tcp_socket_receive_queue_head == NX_NULL)
618     {
619 
620 #ifdef NX_ENABLE_LOW_WATERMARK
621         /* If this packet is to be dropped, do nothing. */
622         if (drop_packet == NX_FALSE)
623         {
624 #endif /* NX_ENABLE_LOW_WATERMARK */
625 
626             /* Packet data begins to the right of the expected sequence (out of sequence data). Force an ACK. */
627             _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
628 
629             /* Add debug information. */
630             NX_PACKET_DEBUG(NX_PACKET_TCP_RECEIVE_QUEUE, __LINE__, packet_ptr);
631 
632             /* There are no packets chained on the receive queue.  Simply add the
633                new packet to the receive queue. */
634             socket_ptr -> nx_tcp_socket_receive_queue_head = packet_ptr;
635             socket_ptr -> nx_tcp_socket_receive_queue_tail = packet_ptr;
636 
637             /* Increase the receive queue count. */
638             socket_ptr -> nx_tcp_socket_receive_queue_count = 1;
639 
640             /* Setup a new delayed ACK timeout.  */
641             socket_ptr -> nx_tcp_socket_delayed_ack_timeout =  _nx_tcp_ack_timer_rate;
642 
643             /* Mark the packet as being part of a TCP queue.  */
644             /*lint -e{923} suppress cast of ULONG to pointer.  */
645             packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next =  (NX_PACKET *)NX_PACKET_ENQUEUED;
646 #ifdef NX_ENABLE_LOW_WATERMARK
647         }
648         else
649         {
650 
651             /* Release this packet. */
652             _nx_packet_release(packet_ptr);
653 
654             /* Set window to zero. */
655             socket_ptr -> nx_tcp_socket_rx_window_current = 0;
656             socket_ptr -> nx_tcp_socket_rx_window_last_sent = 0;
657 
658             /* Send zero window. */
659             _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
660         }
661 #endif /* NX_ENABLE_LOW_WATERMARK */
662     }
663     else
664     {
665 
666         /* Out of order insertion with packets on the queue. */
667 
668         /* Either this packet is not in order or other out-of-order packets have already been
669            received.  In this case searching the receive list must be done to find the proper
670            place for the new packet.  */
671 
672         /* Go through the received packet chain, and locate the first packet that the
673            packet_begin_sequence is to the right of the end of it. */
674 
675         /* Packet data begins to the right of the expected sequence (out of sequence data). Force an ACK. */
676         if (((INT)(packet_begin_sequence - socket_ptr -> nx_tcp_socket_rx_sequence)) > 0)
677         {
678             _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
679         }
680 
681         /* At this point, it is guaranteed that the receive queue contains packets. */
682         search_ptr = socket_ptr -> nx_tcp_socket_receive_queue_head;
683 
684         previous_ptr = NX_NULL;
685 
686         while (search_ptr)
687         {
688 
689             /*lint -e{923} suppress cast of ULONG to pointer.  */
690             if (search_ptr == (NX_PACKET *)NX_PACKET_ENQUEUED)
691             {
692                 /* We hit the end of the receive queue. */
693                 search_ptr = NX_NULL;
694 
695                 /* Terminate the out-of-order search.  */
696                 break;
697             }
698 
699             /* Setup a pointer to header of this packet in the receive list.  */
700             /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
701             search_header_ptr =  (NX_TCP_HEADER *)search_ptr -> nx_packet_prepend_ptr;
702 
703             search_begin_sequence = search_header_ptr -> nx_tcp_sequence_number;
704 
705             /* Calculate the header size for this packet.  */
706             header_length =  (search_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * (ULONG)sizeof(ULONG);
707 
708             search_end_sequence = search_begin_sequence + search_ptr -> nx_packet_length - header_length;
709 
710             /****************************************************************************************
711              *  (1)              PPPPPPPP                                                           *
712              *        SSSSSSSS                                                                      *
713              *        In this configuration, the incoming packet is completely to the right of      *
714              *        search_ptr.  Move to the next search packet.                                  *
715              *                                                                                      *
716              ****************************************************************************************/
717             /* packet_ptr is to the right of search_ptr */
718             if (((INT)(packet_begin_sequence - search_end_sequence)) >= 0)
719             {
720                 /* Move on to the next packet. */
721                 previous_ptr = search_ptr;
722 
723                 search_ptr = search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next;
724 
725                 /* Continue the search */
726                 continue;
727             }
728 
729             /****************************************************************************************
730              *  (2)   PPPPPP                                                                        *
731              *              SSSSSSSSS                                                               *
732              *        In this configuration, the incoming packet is completely to the left of       *
733              *        search_ptr.  Incoming packet needs to be inserted in front of search ptr.     *
734              *                                                                                      *
735              ****************************************************************************************/
736             if (((INT)(search_begin_sequence - packet_end_sequence)) >= 0)
737             {
738                 /* packet_ptr is to the left of search_ptr. We are done. Break out of the while loop.*/
739                 break;
740             }
741 
742             /* At this point search_ptr and packet_ptr overlapps. */
743             /****************************************************************************************
744              * There are four cases:(P - packet_ptr, S - search_ptr)                                *
745              ****************************************************************************************/
746 
747 
748             /****************************************************************************************
749              *  (3)        PPPPPPPPPPPPPP                                                           *
750              *        SSSSSSSSSSSSSSSSSSSSSSSS                                                      *
751              *        In this configuration, the incoming packet is the same as the existing one,   *
752              *        or is a subset of the existing one.  Remove the incoming packet.  No need     *
753              *        to search for contigous data, therefore no need to wake up user thread.       *
754              *        Howerver may need to send out ACK if new packet is to the right of the seq    *
755              *        number.                                                                       *
756              *                                                                                      *
757              ****************************************************************************************/
758             if ((((INT)(packet_begin_sequence - search_begin_sequence)) >= 0) &&
759                 (((INT)(search_end_sequence - packet_end_sequence)) >= 0))
760             {
761 
762                 /* Send an immediate ACK.  */
763                 _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
764 
765                 /* Since packet is not queued, return NX_FALSE so the caller releases the packet. */
766                 return(NX_FALSE);
767             }
768 
769             /****************************************************************************************
770              *  (4)    PPPPPPPPPPPPPPPPPP                                                           *
771              *          SSSSSSSSSSSSSSSS                                                            *
772              *         In this configuration, New packet is a super-set of an existing packet.      *
773              *         Release existing packet, and insert new packet, then check for the next      *
774              *         packet on the chain.  The next search may yield case (5).  Need to check     *
775              *         for contingous data, may need to send ACK.                                   *
776              *                                                                                      *
777             ****************************************************************************************/
778             if ((((INT)(search_begin_sequence - packet_begin_sequence)) >= 0) &&
779                 (((INT)(packet_end_sequence - search_end_sequence) >= 0)))
780             {
781             NX_PACKET *tmp_ptr;
782                 /* Release the search_ptr, and move to the next packet on the chain. */
783                 tmp_ptr = search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next;
784 
785                 /* Mark the packet as no longer being part of the TCP queue. */
786                 /*lint -e{923} suppress cast of ULONG to pointer.  */
787                 search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED;
788 
789                 /* Decrease the packet queue count */
790                 socket_ptr -> nx_tcp_socket_receive_queue_count--;
791 
792                 /* Adjust the receive window. */
793 
794                 /* Release the search packet. */
795                 _nx_packet_release(search_ptr);
796 
797 #ifndef NX_DISABLE_TCP_INFO
798                 /* The new packet has been admitted to the receive queue. */
799 
800                 /* Increment the TCP packet receive count and bytes received count.  */
801                 ip_ptr -> nx_ip_tcp_packets_received--;
802                 ip_ptr -> nx_ip_tcp_bytes_received -= (search_end_sequence - search_begin_sequence);
803 
804                 /* Increment the TCP packet receive count and bytes received count for the socket.  */
805                 socket_ptr -> nx_tcp_socket_packets_received--;
806                 socket_ptr -> nx_tcp_socket_bytes_received -= (search_end_sequence - search_begin_sequence);
807 
808 #endif /* NX_DISABLE_TCP_INFO */
809 
810                 /* Move to the next packet.  (note: no need to update previous_ptr. */
811                 search_ptr = tmp_ptr;
812 
813                 /* Continue the search. */
814                 continue;
815             }
816 
817 
818             /****************************************************************************************
819              *  (5)    PPPPPPPPPPPPPPPPPP                                                           *
820              *                   SSSSSSSSSSSS                                                       *
821              *        In this configuration, remove data from the back of the new packet,  insert   *
822              *        packet into the chain, and terminate the search.  Need to search for          *
823              *        contigous data, may need to send out ACK.                                     *
824              ****************************************************************************************/
825             if (((INT)(search_begin_sequence - packet_begin_sequence)) >= 0)
826             {
827 
828                 _nx_tcp_socket_state_data_trim(packet_ptr, (packet_end_sequence - search_begin_sequence));
829 
830                 /* Update packet_data_length. */
831                 packet_data_length -= (packet_end_sequence - search_begin_sequence);
832 
833                 /* Now the packet should be chained before search_ptr. */
834 
835                 break;
836             }
837 
838             /****************************************************************************************
839              *                                                                                      *
840              *  (6)        PPPPPPPPPPPPPP                                                           *
841              *        SSSSSSSS                                                                      *
842              *        In this configuration, remove data from the beginning of the search_ptr,      *
843              *        insert the packet after the search packet and continue the search.  This may  *
844              *        lead to case (2) and (3).                                                     *
845              *                                                                                      *
846              *                                                                                      *
847              ***************************************************************************************/
848             _nx_tcp_socket_state_data_trim(search_ptr, (ULONG)(search_end_sequence - packet_begin_sequence));
849 
850 #ifndef NX_DISABLE_TCP_INFO
851             /* The new packet has been admitted to the receive queue. */
852 
853             /* Reduce the TCP bytes received count.  */
854             ip_ptr -> nx_ip_tcp_bytes_received -= (search_end_sequence - packet_begin_sequence);
855 
856             /* Reduce the TCP bytes received count for the socket.  */
857             socket_ptr -> nx_tcp_socket_bytes_received -= (search_end_sequence - packet_begin_sequence);
858 
859 #endif /* NX_DISABLE_TCP_INFO */
860 
861             /* Move to the next packet and continue; */
862             previous_ptr = search_ptr;
863             search_ptr = search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next;
864         }   /* End of while (search_ptr) */
865 
866         /* At this point, the logic (within the while loop) finds a location where this packet should be inserted. */
867         if (previous_ptr == NX_NULL)
868         {
869 
870             /* The packet needs to be inserted at the beginning of the queue. */
871             socket_ptr -> nx_tcp_socket_receive_queue_head = packet_ptr;
872         }
873         else
874         {
875 
876             /* The packet needs to be inserted after previous_ptr. */
877             previous_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next = packet_ptr;
878         }
879 
880         if (search_ptr == NX_NULL)
881         {
882 
883             /* This packet is on the last one on the queue. */
884             socket_ptr -> nx_tcp_socket_receive_queue_tail = packet_ptr;
885 
886             /* Set the next pointer to indicate the packet is part of a TCP queue.  */
887             /*lint -e{923} suppress cast of ULONG to pointer.  */
888             packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ENQUEUED;
889         }
890         else
891         {
892 
893             /* Chain search_ptr onto packet_ptr. */
894             packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next = search_ptr;
895         }
896 
897         /* Add debug information. */
898         NX_PACKET_DEBUG(NX_PACKET_TCP_RECEIVE_QUEUE, __LINE__, packet_ptr);
899 
900         /* Increment the receive TCP packet count.  */
901         socket_ptr -> nx_tcp_socket_receive_queue_count++;
902 
903         /* End of the out-of-order search.  At this point, the packet has been inserted. */
904 
905         /* Now we need to figure out how much, if any, we can ACK.  */
906         search_ptr =    socket_ptr -> nx_tcp_socket_receive_queue_head;
907 
908         /* Get the sequence number expected by the TCP receive socket. */
909         expected_sequence =  socket_ptr -> nx_tcp_socket_rx_sequence;
910 
911         /* Loop to see how much data is contiguous in the queued packets.  */
912         do
913         {
914 
915             /* Setup a pointer to header of this packet in the sent list.  */
916             /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
917             search_header_ptr =  (NX_TCP_HEADER *)search_ptr -> nx_packet_prepend_ptr;
918 
919 
920             /* Calculate the header size for this packet.  */
921             header_length =  (search_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * (ULONG)sizeof(ULONG);
922 
923             search_begin_sequence = search_header_ptr -> nx_tcp_sequence_number;
924 
925             search_end_sequence = search_begin_sequence + search_ptr -> nx_packet_length - header_length;
926 
927             if ((INT)(expected_sequence - search_begin_sequence) >= 0)
928             {
929 
930                 /* Increment the acked packet count.  */
931                 acked_packets++;
932 
933                 if ((INT)(search_end_sequence - expected_sequence) > 0)
934                 {
935                     /* Sequence number is within this packet.  Advance sequence number. */
936                     expected_sequence = search_end_sequence;
937 
938                     socket_ptr -> nx_tcp_socket_rx_sequence = expected_sequence;
939 
940                     /* Mark this packet as ready for retrieval.  */
941                     /*lint -e{923} suppress cast of ULONG to pointer.  */
942                     search_ptr -> nx_packet_queue_next =  (NX_PACKET *)NX_PACKET_READY;
943                 }
944             }
945             else
946             {
947 
948                 /* Expected number is to the left of search_ptr.   Get out of the do-while loop!  */
949                 break;
950             }
951 
952             /* Move the search pointer to the next queued receive packet.  */
953             search_ptr =  search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next;
954 
955             /* Determine if we are at the end of the queue.  */
956             /*lint -e{923} suppress cast of ULONG to pointer.  */
957             if (search_ptr == ((NX_PACKET *)NX_PACKET_ENQUEUED))
958             {
959 
960                 /* At the end, set the search pointer to NULL.  */
961                 search_ptr =  NX_NULL;
962             }
963 
964 #ifdef NX_ENABLE_LOW_WATERMARK
965             /* Do not calculate sequence for packet that is to be dropped. */
966             if (drop_packet && (acked_packets >= (ULONG)socket_ptr -> nx_tcp_socket_receive_queue_maximum))
967             {
968 
969                 /* Get out of the loop!  */
970                 break;
971             }
972 #endif /* NX_ENABLE_LOW_WATERMARK */
973         } while (search_ptr);
974 
975         /* If there are no packet crosses the rx_sequence, the TCP stream in the receive queue contains
976            missing pieces. */
977 
978 #ifdef NX_ENABLE_LOW_WATERMARK
979         /* Does the number of queued packets exceed the maximum rx queue length, or the number of
980          * available packets in the default packet pool reaches low watermark? */
981         if (drop_packet)
982         {
983 
984             /* Yes it is. Remove the last packet in queue. */
985             socket_ptr -> nx_tcp_socket_receive_queue_tail -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED;
986             if (socket_ptr -> nx_tcp_socket_receive_queue_count > 1)
987             {
988 
989                 /* Find the previous packet of tail. */
990                 search_ptr = socket_ptr -> nx_tcp_socket_receive_queue_head;
991                 while (search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next != socket_ptr -> nx_tcp_socket_receive_queue_tail)
992                 {
993                     search_ptr = search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next;
994                 }
995 
996                 /* Release the tail. */
997                 _nx_packet_release(socket_ptr -> nx_tcp_socket_receive_queue_tail);
998 
999                 /* Setup the tail packet. */
1000                 socket_ptr -> nx_tcp_socket_receive_queue_tail = search_ptr;
1001 
1002                 search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ENQUEUED;
1003 
1004                 /* Calculate the ending sequence number for the last packet.  */
1005                 search_header_ptr =  (NX_TCP_HEADER *)search_ptr -> nx_packet_prepend_ptr;
1006                 header_length = (search_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * sizeof(ULONG);
1007 
1008                 /* Decrease window size. */
1009                 socket_ptr -> nx_tcp_socket_rx_window_current = search_header_ptr -> nx_tcp_sequence_number +
1010                     (search_ptr -> nx_packet_length - header_length) -
1011                     socket_ptr -> nx_tcp_socket_rx_sequence;
1012                 socket_ptr -> nx_tcp_socket_rx_window_last_sent = socket_ptr -> nx_tcp_socket_rx_window_current;
1013             }
1014             else
1015             {
1016 
1017                 /* Release the tail. */
1018                 _nx_packet_release(socket_ptr -> nx_tcp_socket_receive_queue_tail);
1019 
1020                 /* Clear the head and tail packets. */
1021                 socket_ptr -> nx_tcp_socket_receive_queue_head = NX_NULL;
1022                 socket_ptr -> nx_tcp_socket_receive_queue_tail = NX_NULL;
1023 
1024                 /* No packets can be received. */
1025                 socket_ptr -> nx_tcp_socket_rx_window_current = 0;
1026                 socket_ptr -> nx_tcp_socket_rx_window_last_sent = 0;
1027             }
1028 
1029             /* Decrease receive queue count. */
1030             socket_ptr -> nx_tcp_socket_receive_queue_count--;
1031         }
1032 #endif /* NX_ENABLE_LOW_WATERMARK */
1033     }   /* End of out-of-order insertion. */
1034 
1035 
1036 #ifndef NX_DISABLE_TCP_INFO
1037     /* The new packet has been admitted to the receive queue. */
1038 
1039     /* Increment the TCP packet receive count and bytes received count.  */
1040     ip_ptr -> nx_ip_tcp_packets_received++;
1041     ip_ptr -> nx_ip_tcp_bytes_received += packet_data_length;
1042 
1043     /* Increment the TCP packet receive count and bytes received count for the socket.  */
1044     socket_ptr -> nx_tcp_socket_packets_received++;
1045     socket_ptr -> nx_tcp_socket_bytes_received += packet_data_length;
1046 #endif
1047 
1048     /* Check if the rx sequence number has been updated.  */
1049     if (original_rx_sequence != socket_ptr -> nx_tcp_socket_rx_sequence)
1050     {
1051 
1052         /* Decrease the receive window size since rx_sequence is updated.  */
1053         socket_ptr -> nx_tcp_socket_rx_window_current -= (socket_ptr -> nx_tcp_socket_rx_sequence - original_rx_sequence);
1054 
1055         /* Update the rx_window_last_sent for SWS avoidance algorithm.
1056            RFC1122, Section4.2.3.3, Page97-98.  */
1057         socket_ptr -> nx_tcp_socket_rx_window_last_sent -= (socket_ptr -> nx_tcp_socket_rx_sequence - original_rx_sequence);
1058     }
1059 
1060 #ifdef NX_TCP_MAX_OUT_OF_ORDER_PACKETS
1061     /* Does the count of out of order packets exceed the defined value? */
1062     if ((socket_ptr -> nx_tcp_socket_receive_queue_count - acked_packets) >
1063         NX_TCP_MAX_OUT_OF_ORDER_PACKETS)
1064     {
1065 
1066         /* Yes it is. Remove the last packet in queue. */
1067         socket_ptr -> nx_tcp_socket_receive_queue_tail -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED;
1068         if (socket_ptr -> nx_tcp_socket_receive_queue_count > 1)
1069         {
1070 
1071             /* Find the previous packet of tail. */
1072             search_ptr = socket_ptr -> nx_tcp_socket_receive_queue_head;
1073             while (search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next != socket_ptr -> nx_tcp_socket_receive_queue_tail)
1074             {
1075                 search_ptr = search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next;
1076             }
1077 
1078             /* Release the tail. */
1079             _nx_packet_release(socket_ptr -> nx_tcp_socket_receive_queue_tail);
1080 
1081             /* Setup the tail packet. */
1082             socket_ptr -> nx_tcp_socket_receive_queue_tail = search_ptr;
1083 
1084             search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ENQUEUED;
1085         }
1086         else
1087         {
1088 
1089             /* Release the tail. */
1090             _nx_packet_release(socket_ptr -> nx_tcp_socket_receive_queue_tail);
1091 
1092             /* Clear the head and tail packets. */
1093             socket_ptr -> nx_tcp_socket_receive_queue_head = NX_NULL;
1094             socket_ptr -> nx_tcp_socket_receive_queue_tail = NX_NULL;
1095         }
1096 
1097         /* Decrease receive queue count. */
1098         socket_ptr -> nx_tcp_socket_receive_queue_count--;
1099     }
1100 #endif /* NX_TCP_MAX_OUT_OF_ORDER_PACKETS */
1101 
1102     /* At this point, we can use the packet TCP header pointers since the received
1103        packet is already queued.  */
1104 
1105     /* Any packets for receiving? */
1106     while (acked_packets && socket_ptr -> nx_tcp_socket_receive_suspension_list
1107 #ifdef NX_ENABLE_HTTP_PROXY
1108            && (socket_ptr -> nx_tcp_socket_http_proxy_state != NX_HTTP_PROXY_STATE_CONNECTING)
1109 #endif /* NX_ENABLE_HTTP_PROXY */
1110           )
1111     {
1112 
1113         /* Setup a pointer to the first queued packet.  */
1114         packet_ptr =  socket_ptr -> nx_tcp_socket_receive_queue_head;
1115         /* Remove it from the queue.  */
1116 
1117         /* Simply update the head pointer of the queue.  */
1118         socket_ptr -> nx_tcp_socket_receive_queue_head =  packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next;
1119 
1120         /* Mark the packet as no longer being part of the TCP queue.  */
1121         /*lint -e{923} suppress cast of ULONG to pointer.  */
1122         packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next =  (NX_PACKET *)NX_PACKET_ALLOCATED;
1123 
1124         /* Clear the queue next pointer.  */
1125         packet_ptr -> nx_packet_queue_next =  NX_NULL;
1126 
1127         /* Decrease the number of received packets.  */
1128         socket_ptr -> nx_tcp_socket_receive_queue_count--;
1129 
1130         /* Adjust the packet for delivery to the suspended thread.  */
1131 
1132         /* Setup a pointer to the TCP header of this packet.  */
1133         /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
1134         tcp_header_ptr =  (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
1135 
1136         /* Calculate the header size for this packet.  */
1137         header_length =  (tcp_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * (ULONG)sizeof(ULONG);
1138 
1139         /* Adjust the packet prepend pointer and length to position past the TCP header.  */
1140         packet_ptr -> nx_packet_prepend_ptr =  packet_ptr -> nx_packet_prepend_ptr + header_length;
1141         packet_ptr -> nx_packet_length =       packet_ptr -> nx_packet_length - header_length;
1142 
1143         /* Setup a pointer to the first thread suspended on the receive queue.  */
1144         thread_ptr =  socket_ptr -> nx_tcp_socket_receive_suspension_list;
1145 
1146         /* Place the packet pointer in the return pointer.  */
1147         *((NX_PACKET **)thread_ptr -> tx_thread_additional_suspend_info) =  packet_ptr;
1148 
1149         /* Increase the receive window size.  */
1150         socket_ptr -> nx_tcp_socket_rx_window_current += packet_ptr -> nx_packet_length;
1151 
1152         /* Remove the suspended thread from the list.  */
1153 
1154         /* Decrement the suspension count.  */
1155         socket_ptr -> nx_tcp_socket_receive_suspended_count--;
1156 
1157         /* Decrement the acked_packets count. */
1158         acked_packets--;
1159 
1160         /* Resume thread.  */
1161         _nx_tcp_socket_thread_resume(&(socket_ptr -> nx_tcp_socket_receive_suspension_list), NX_SUCCESS);
1162     }
1163 
1164     /* Is the queue empty?.  */
1165     if (socket_ptr -> nx_tcp_socket_receive_queue_count == 0)
1166     {
1167 
1168         /* Yes. Set both head and tail pointers to NULL.  */
1169         socket_ptr -> nx_tcp_socket_receive_queue_head =  NX_NULL;
1170         socket_ptr -> nx_tcp_socket_receive_queue_tail =  NX_NULL;
1171     }
1172 
1173     /* Determine if an ACK should be forced out for window update, SWS avoidance algorithm.
1174        RFC1122, Section4.2.3.3, Page97-98. */
1175     if ((socket_ptr -> nx_tcp_socket_rx_window_current - socket_ptr -> nx_tcp_socket_rx_window_last_sent) >= (socket_ptr -> nx_tcp_socket_rx_window_default / 2))
1176     {
1177 
1178         /* Need to send ACK for window update.  */
1179         need_ack = NX_TRUE;
1180     }
1181 
1182     /* If the incoming packet caused the sequence number to move forward,
1183        indicating the new piece of data is in order, in sequence, and valid for receiving. */
1184     if ((original_rx_sequence != socket_ptr -> nx_tcp_socket_rx_sequence)
1185 #ifdef NX_ENABLE_TCPIP_OFFLOAD
1186         || tcpip_offload
1187 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
1188        )
1189     {
1190 
1191 #ifdef NX_ENABLE_HTTP_PROXY
1192 
1193         /* If HTTP Proxy is connecting, the data is the response from HTTP Proxy server, don't need to notify application.  */
1194         if (socket_ptr -> nx_tcp_socket_http_proxy_state != NX_HTTP_PROXY_STATE_CONNECTING)
1195 #endif /* NX_ENABLE_HTTP_PROXY */
1196         {
1197 
1198             /* Determine if there is a socket receive notification function specified.  */
1199             if (socket_ptr -> nx_tcp_receive_callback)
1200             {
1201 
1202                 /* Yes, notification is requested.  Call the application's receive notification
1203                    function for this socket.  */
1204                 (socket_ptr -> nx_tcp_receive_callback)(socket_ptr);
1205             }
1206         }
1207 
1208 #ifdef NX_TCP_ACK_EVERY_N_PACKETS
1209         /* Determine if we need to ACK up to the current sequence number.  */
1210 
1211         /* If we are still in an ESTABLISHED state, a FIN isn't present and we can
1212            allocate a packet for the ACK message, send an ACK message.  */
1213         if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED) &&
1214             ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_FIN_BIT) == 0))
1215         {
1216             if (socket_ptr -> nx_tcp_socket_ack_n_packet_counter >= NX_TCP_ACK_EVERY_N_PACKETS)
1217             {
1218                 socket_ptr -> nx_tcp_socket_ack_n_packet_counter = 1;
1219 
1220                 /* Need to send an immediate ACK.  */
1221                 need_ack = NX_TRUE;
1222             }
1223             else
1224             {
1225                 socket_ptr -> nx_tcp_socket_ack_n_packet_counter++;
1226             }
1227         }
1228 #endif
1229     }
1230 
1231     if (need_ack == NX_TRUE)
1232     {
1233 
1234         /* Need to send ACK.  */
1235         _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
1236     }
1237 
1238     /* Return true since the packet was queued.  */
1239     return(NX_TRUE);
1240 }
1241 
1242