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