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.2.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 /*                                                                        */
337 /**************************************************************************/
_nx_tcp_socket_state_data_check(NX_TCP_SOCKET * socket_ptr,NX_PACKET * packet_ptr)338 UINT  _nx_tcp_socket_state_data_check(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr)
339 {
340 
341 NX_TCP_HEADER *tcp_header_ptr;
342 NX_TCP_HEADER *search_header_ptr;
343 NX_PACKET     *search_ptr;
344 NX_PACKET     *previous_ptr;
345 ULONG          expected_sequence;
346 ULONG          header_length;
347 ULONG          search_header_length;
348 ULONG          packet_begin_sequence;
349 ULONG          packet_end_sequence;
350 ULONG          packet_data_length;
351 ULONG          search_begin_sequence;
352 ULONG          search_end_sequence;
353 ULONG          original_rx_sequence;
354 ULONG          trim_data_length;
355 TX_THREAD     *thread_ptr;
356 ULONG          acked_packets = 0;
357 UINT           need_ack = NX_FALSE;
358 #ifdef NX_ENABLE_TCPIP_OFFLOAD
359 ULONG          tcpip_offload;
360 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
361 #ifdef NX_ENABLE_LOW_WATERMARK
362 UCHAR          drop_packet = NX_FALSE;
363 #endif /* NX_ENABLE_LOW_WATERMARK */
364 #if ((!defined(NX_DISABLE_TCP_INFO)) || defined(TX_ENABLE_EVENT_TRACE))
365 NX_IP         *ip_ptr;
366 
367     /* Setup the IP pointer.  */
368     ip_ptr =  socket_ptr -> nx_tcp_socket_ip_ptr;
369 #endif
370 
371 #ifdef NX_ENABLE_TCPIP_OFFLOAD
372     tcpip_offload = socket_ptr -> nx_tcp_socket_connect_interface -> nx_interface_capability_flag &
373                     NX_INTERFACE_CAPABILITY_TCPIP_OFFLOAD;
374 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
375 
376     /* Pickup the pointer to the head of the TCP packet.  */
377     /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
378     tcp_header_ptr =  (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
379 
380     /* Determine the size of the TCP header.  */
381     header_length =  (tcp_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * (ULONG)sizeof(ULONG);
382 
383     /* Record the original rx_sequence. */
384     original_rx_sequence = socket_ptr -> nx_tcp_socket_rx_sequence;
385 
386     /* Pickup the begin sequence of this packet. */
387     packet_begin_sequence = tcp_header_ptr -> nx_tcp_sequence_number;
388 
389     /* Calculate the data length in the packet.  */
390     packet_data_length = packet_ptr -> nx_packet_length - header_length;
391 
392     /* Pickup the end sequence of this packet. The end sequence is one byte to the last byte in this packet. */
393     packet_end_sequence =  tcp_header_ptr -> nx_tcp_sequence_number + packet_data_length;
394 
395     /* Trim the data that out of the receive window, make sure all data are in receive window.  */
396     if (packet_data_length
397 #ifdef NX_ENABLE_TCPIP_OFFLOAD
398         && (!tcpip_offload)
399 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
400        )
401     {
402 
403         /* Step1. trim the data on the left side of the receive window.  */
404         if (((INT)(socket_ptr -> nx_tcp_socket_rx_sequence - packet_begin_sequence)) > 0)
405         {
406 
407             /* Calculate the data length that out of window.  */
408             trim_data_length = socket_ptr -> nx_tcp_socket_rx_sequence - packet_begin_sequence;
409 
410             /* Trim the data that exceed the receive window.  */
411             _nx_tcp_socket_state_data_trim_front(packet_ptr, trim_data_length);
412 
413             /* Fix the sequence of this packet. */
414             tcp_header_ptr -> nx_tcp_sequence_number += trim_data_length;
415 
416             /* Update the data length and begin sequence.  */
417             packet_data_length -= trim_data_length;
418             packet_begin_sequence += trim_data_length;
419         }
420 
421         /* Step2. trim the data on the right side of the receive window.  */
422         if (((INT)((packet_end_sequence - socket_ptr -> nx_tcp_socket_rx_sequence) -
423                    socket_ptr -> nx_tcp_socket_rx_window_current)) > 0)
424         {
425 
426             /* Calculate the data length that out of window.  */
427             trim_data_length = packet_end_sequence - (socket_ptr -> nx_tcp_socket_rx_sequence + socket_ptr -> nx_tcp_socket_rx_window_current);
428 
429             /* Trim the data that exceed the receive window.  */
430             _nx_tcp_socket_state_data_trim(packet_ptr, trim_data_length);
431 
432             /* Update the data length and end sequence.  */
433             packet_data_length -= trim_data_length;
434             packet_end_sequence -= trim_data_length;
435         }
436     }
437 
438     /* Determine if the packet has the FIN bit set to signal a disconnect.  */
439     if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_FIN_BIT)
440     {
441 
442         /* Setup the FIN sequence number that we need to look at.  */
443         socket_ptr -> nx_tcp_socket_fin_sequence =  tcp_header_ptr -> nx_tcp_sequence_number + packet_data_length;
444 
445         /* Indicate that the FIN sequence is now valid.  Once the receive chain is complete
446            we will process (ACK) the FIN command which is part of a disconnect started by the
447            other side of the connection.  */
448         socket_ptr -> nx_tcp_socket_fin_received =  NX_TRUE;
449 
450         /* If trace is enabled, insert this event into the trace buffer.  */
451         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);
452     }
453 
454     /* Compute the amount of payload data in this packet. */
455     if (packet_data_length == 0)
456     {
457         /* This packet does not contain TCP data payload.  */
458 
459         /* Check for invalid sequence number.  */
460         if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED) &&
461             (socket_ptr -> nx_tcp_socket_receive_queue_count == 0) &&
462             (socket_ptr -> nx_tcp_socket_rx_sequence != tcp_header_ptr -> nx_tcp_sequence_number) &&
463             ((socket_ptr -> nx_tcp_socket_rx_sequence - 1) != tcp_header_ptr -> nx_tcp_sequence_number))
464         {
465 
466             /* Send an immediate ACK.  */
467             _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
468         }
469 
470         /* This packet does not have data, so return false. */
471         return(NX_FALSE);
472     }
473 
474 
475     /* If trace is enabled, insert this event into the trace buffer.  */
476     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);
477 
478     /* Ensure the next pointer in the packet is set to NULL, which will indicate to the
479        receive logic that it is not yet part of a contiguous stream.  */
480     packet_ptr -> nx_packet_queue_next =  (NX_PACKET *)NX_NULL;
481 
482     /* Otherwise, the packet is within the receive window so continue processing
483        the incoming TCP data.  */
484 
485     /* Pickup the tail pointer of the receive queue.  */
486     search_ptr = socket_ptr -> nx_tcp_socket_receive_queue_tail;
487 
488     /* Check to see if the tail pointer is part of a contiguous stream.  */
489     if (search_ptr)
490     {
491 
492         /* Setup a pointer to header of this packet in the sent list.  */
493         /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
494         search_header_ptr =  (NX_TCP_HEADER *)search_ptr -> nx_packet_prepend_ptr;
495 
496         /* Determine the size of the search TCP header.  */
497         search_header_length =  (search_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * (ULONG)sizeof(ULONG);
498 
499         /* Now see if the current sequence number accounts for the last packet.  */
500         search_end_sequence = search_header_ptr -> nx_tcp_sequence_number  + search_ptr -> nx_packet_length - search_header_length;
501     }
502     else
503     {
504 
505         /* Set the sequence number to the socket's receive sequence if there isn't a receive
506            packet on the queue.  */
507         search_end_sequence =  socket_ptr -> nx_tcp_socket_rx_sequence;
508     }
509 
510     /* Does the number of queued packets exceed the maximum rx queue length, or the number of
511      * available packets in the default packet pool reaches low watermark? */
512 #ifdef NX_ENABLE_LOW_WATERMARK
513     if (((socket_ptr -> nx_tcp_socket_receive_queue_count >=
514           socket_ptr -> nx_tcp_socket_receive_queue_maximum) ||
515          (packet_ptr -> nx_packet_pool_owner -> nx_packet_pool_available <
516           packet_ptr -> nx_packet_pool_owner -> nx_packet_pool_low_watermark))
517 #ifdef NX_ENABLE_TCPIP_OFFLOAD
518          && (!tcpip_offload)
519 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
520        )
521     {
522 
523         /* Yes it is. The last packet in queue should be dropped. */
524         drop_packet = NX_TRUE;
525     }
526 #endif /* NX_ENABLE_LOW_WATERMARK */
527 
528     /* Determine if we have a simple case of TCP data coming in the correct order.  This means
529        the socket's sequence number matches the incoming packet sequence number and the last packet's
530        data on the socket's receive queue (if any) matches the current sequence number.  */
531     if (((tcp_header_ptr -> nx_tcp_sequence_number == socket_ptr -> nx_tcp_socket_rx_sequence) &&
532          (search_end_sequence == socket_ptr -> nx_tcp_socket_rx_sequence))
533 #ifdef NX_ENABLE_TCPIP_OFFLOAD
534          || tcpip_offload
535 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
536        )
537     {
538 
539         /* Yes, this is the simple case of adding receive packets in sequence.  */
540 #ifdef NX_ENABLE_LOW_WATERMARK
541         /* If this packet is to be dropped, do nothing. */
542         if (drop_packet == NX_FALSE)
543         {
544 #endif /* NX_ENABLE_LOW_WATERMARK */
545 
546             /* Mark the packet as ready. This is done to simplify the logic in socket receive.  */
547             /*lint -e{923} suppress cast of ULONG to pointer.  */
548             packet_ptr -> nx_packet_queue_next =  (NX_PACKET *)NX_PACKET_READY;
549 
550             /* Add debug information. */
551             NX_PACKET_DEBUG(NX_PACKET_TCP_RECEIVE_QUEUE, __LINE__, packet_ptr);
552 
553             /* Place the packet on the receive queue.  Search pointer still points to the tail packet on
554                the queue.  */
555             if (search_ptr)
556             {
557 
558                 /* Nonempty receive queue, add packet to the end of the receive queue.  */
559                 search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next =  packet_ptr;
560 
561                 /* Update the tail of the receive queue.  */
562                 socket_ptr -> nx_tcp_socket_receive_queue_tail =  packet_ptr;
563             }
564             else
565             {
566 
567                 /* Empty receive queue.  Set both the head and the tail pointers this packet.  */
568                 socket_ptr -> nx_tcp_socket_receive_queue_head =  packet_ptr;
569                 socket_ptr -> nx_tcp_socket_receive_queue_tail =  packet_ptr;
570 
571                 /* Setup a new delayed ACK timeout.  */
572 #ifdef NX_ENABLE_TCPIP_OFFLOAD
573                 if (!tcpip_offload)
574 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
575                 {
576                     socket_ptr -> nx_tcp_socket_delayed_ack_timeout =  _nx_tcp_ack_timer_rate;
577                 }
578             }
579 
580             /* Increment the receive TCP packet count.  */
581             socket_ptr -> nx_tcp_socket_receive_queue_count++;
582 
583             /* Set the next pointer to indicate the packet is part of a TCP queue.  */
584             /*lint -e{923} suppress cast of ULONG to pointer.  */
585             packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next =  (NX_PACKET *)NX_PACKET_ENQUEUED;
586 
587             /* Calculate the next sequence number.  */
588             socket_ptr -> nx_tcp_socket_rx_sequence =  packet_end_sequence;
589 
590             /* All packets can be acked. */
591             acked_packets = socket_ptr -> nx_tcp_socket_receive_queue_count;
592 #ifdef NX_ENABLE_LOW_WATERMARK
593         }
594         else
595         {
596 
597             /* Release this packet. */
598             _nx_packet_release(packet_ptr);
599 
600             /* Set window to zero. */
601             socket_ptr -> nx_tcp_socket_rx_window_current = 0;
602             socket_ptr -> nx_tcp_socket_rx_window_last_sent = 0;
603 
604             /* Send zero window. */
605             _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
606 
607             /* All packets can be acked. */
608             acked_packets = socket_ptr -> nx_tcp_socket_receive_queue_count;
609         }
610 #endif /* NX_ENABLE_LOW_WATERMARK */
611 
612         /* End of the simple case: add new packet towards the end of the recv queue.
613            All packets in the receive queue are in sequence. */
614     }
615     else if (socket_ptr -> nx_tcp_socket_receive_queue_head == NX_NULL)
616     {
617 
618 #ifdef NX_ENABLE_LOW_WATERMARK
619         /* If this packet is to be dropped, do nothing. */
620         if (drop_packet == NX_FALSE)
621         {
622 #endif /* NX_ENABLE_LOW_WATERMARK */
623 
624             /* Packet data begins to the right of the expected sequence (out of sequence data). Force an ACK. */
625             _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
626 
627             /* Add debug information. */
628             NX_PACKET_DEBUG(NX_PACKET_TCP_RECEIVE_QUEUE, __LINE__, packet_ptr);
629 
630             /* There are no packets chained on the receive queue.  Simply add the
631                new packet to the receive queue. */
632             socket_ptr -> nx_tcp_socket_receive_queue_head = packet_ptr;
633             socket_ptr -> nx_tcp_socket_receive_queue_tail = packet_ptr;
634 
635             /* Increase the receive queue count. */
636             socket_ptr -> nx_tcp_socket_receive_queue_count = 1;
637 
638             /* Setup a new delayed ACK timeout.  */
639             socket_ptr -> nx_tcp_socket_delayed_ack_timeout =  _nx_tcp_ack_timer_rate;
640 
641             /* Mark the packet as being part of a TCP queue.  */
642             /*lint -e{923} suppress cast of ULONG to pointer.  */
643             packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next =  (NX_PACKET *)NX_PACKET_ENQUEUED;
644 #ifdef NX_ENABLE_LOW_WATERMARK
645         }
646         else
647         {
648 
649             /* Release this packet. */
650             _nx_packet_release(packet_ptr);
651 
652             /* Set window to zero. */
653             socket_ptr -> nx_tcp_socket_rx_window_current = 0;
654             socket_ptr -> nx_tcp_socket_rx_window_last_sent = 0;
655 
656             /* Send zero window. */
657             _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
658         }
659 #endif /* NX_ENABLE_LOW_WATERMARK */
660     }
661     else
662     {
663 
664         /* Out of order insertion with packets on the queue. */
665 
666         /* Either this packet is not in order or other out-of-order packets have already been
667            received.  In this case searching the receive list must be done to find the proper
668            place for the new packet.  */
669 
670         /* Go through the received packet chain, and locate the first packet that the
671            packet_begin_sequence is to the right of the end of it. */
672 
673         /* Packet data begins to the right of the expected sequence (out of sequence data). Force an ACK. */
674         if (((INT)(packet_begin_sequence - socket_ptr -> nx_tcp_socket_rx_sequence)) > 0)
675         {
676             _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
677         }
678 
679         /* At this point, it is guaranteed that the receive queue contains packets. */
680         search_ptr = socket_ptr -> nx_tcp_socket_receive_queue_head;
681 
682         previous_ptr = NX_NULL;
683 
684         while (search_ptr)
685         {
686 
687             /*lint -e{923} suppress cast of ULONG to pointer.  */
688             if (search_ptr == (NX_PACKET *)NX_PACKET_ENQUEUED)
689             {
690                 /* We hit the end of the receive queue. */
691                 search_ptr = NX_NULL;
692 
693                 /* Terminate the out-of-order search.  */
694                 break;
695             }
696 
697             /* Setup a pointer to header of this packet in the receive list.  */
698             /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
699             search_header_ptr =  (NX_TCP_HEADER *)search_ptr -> nx_packet_prepend_ptr;
700 
701             search_begin_sequence = search_header_ptr -> nx_tcp_sequence_number;
702 
703             /* Calculate the header size for this packet.  */
704             header_length =  (search_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * (ULONG)sizeof(ULONG);
705 
706             search_end_sequence = search_begin_sequence + search_ptr -> nx_packet_length - header_length;
707 
708             /****************************************************************************************
709              *  (1)              PPPPPPPP                                                           *
710              *        SSSSSSSS                                                                      *
711              *        In this configuration, the incoming packet is completely to the right of      *
712              *        search_ptr.  Move to the next search packet.                                  *
713              *                                                                                      *
714              ****************************************************************************************/
715             /* packet_ptr is to the right of search_ptr */
716             if (((INT)(packet_begin_sequence - search_end_sequence)) >= 0)
717             {
718                 /* Move on to the next packet. */
719                 previous_ptr = search_ptr;
720 
721                 search_ptr = search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next;
722 
723                 /* Continue the search */
724                 continue;
725             }
726 
727             /****************************************************************************************
728              *  (2)   PPPPPP                                                                        *
729              *              SSSSSSSSS                                                               *
730              *        In this configuration, the incoming packet is completely to the left of       *
731              *        search_ptr.  Incoming packet needs to be inserted in front of search ptr.     *
732              *                                                                                      *
733              ****************************************************************************************/
734             if (((INT)(search_begin_sequence - packet_end_sequence)) >= 0)
735             {
736                 /* packet_ptr is to the left of search_ptr. We are done. Break out of the while loop.*/
737                 break;
738             }
739 
740             /* At this point search_ptr and packet_ptr overlapps. */
741             /****************************************************************************************
742              * There are four cases:(P - packet_ptr, S - search_ptr)                                *
743              ****************************************************************************************/
744 
745 
746             /****************************************************************************************
747              *  (3)        PPPPPPPPPPPPPP                                                           *
748              *        SSSSSSSSSSSSSSSSSSSSSSSS                                                      *
749              *        In this configuration, the incoming packet is the same as the existing one,   *
750              *        or is a subset of the existing one.  Remove the incoming packet.  No need     *
751              *        to search for contigous data, therefore no need to wake up user thread.       *
752              *        Howerver may need to send out ACK if new packet is to the right of the seq    *
753              *        number.                                                                       *
754              *                                                                                      *
755              ****************************************************************************************/
756             if ((((INT)(packet_begin_sequence - search_begin_sequence)) >= 0) &&
757                 (((INT)(search_end_sequence - packet_end_sequence)) >= 0))
758             {
759 
760                 /* Send an immediate ACK.  */
761                 _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
762 
763                 /* Since packet is not queued, return NX_FALSE so the caller releases the packet. */
764                 return(NX_FALSE);
765             }
766 
767             /****************************************************************************************
768              *  (4)    PPPPPPPPPPPPPPPPPP                                                           *
769              *          SSSSSSSSSSSSSSSS                                                            *
770              *         In this configuration, New packet is a super-set of an existing packet.      *
771              *         Release existing packet, and insert new packet, then check for the next      *
772              *         packet on the chain.  The next search may yield case (5).  Need to check     *
773              *         for contingous data, may need to send ACK.                                   *
774              *                                                                                      *
775             ****************************************************************************************/
776             if ((((INT)(search_begin_sequence - packet_begin_sequence)) >= 0) &&
777                 (((INT)(packet_end_sequence - search_end_sequence) >= 0)))
778             {
779             NX_PACKET *tmp_ptr;
780                 /* Release the search_ptr, and move to the next packet on the chain. */
781                 tmp_ptr = search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next;
782 
783                 /* Mark the packet as no longer being part of the TCP queue. */
784                 /*lint -e{923} suppress cast of ULONG to pointer.  */
785                 search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED;
786 
787                 /* Decrease the packet queue count */
788                 socket_ptr -> nx_tcp_socket_receive_queue_count--;
789 
790                 /* Adjust the receive window. */
791 
792                 /* Release the search packet. */
793                 _nx_packet_release(search_ptr);
794 
795 #ifndef NX_DISABLE_TCP_INFO
796                 /* The new packet has been admitted to the receive queue. */
797 
798                 /* Increment the TCP packet receive count and bytes received count.  */
799                 ip_ptr -> nx_ip_tcp_packets_received--;
800                 ip_ptr -> nx_ip_tcp_bytes_received -= (search_end_sequence - search_begin_sequence);
801 
802                 /* Increment the TCP packet receive count and bytes received count for the socket.  */
803                 socket_ptr -> nx_tcp_socket_packets_received--;
804                 socket_ptr -> nx_tcp_socket_bytes_received -= (search_end_sequence - search_begin_sequence);
805 
806 #endif /* NX_DISABLE_TCP_INFO */
807 
808                 /* Move to the next packet.  (note: no need to update previous_ptr. */
809                 search_ptr = tmp_ptr;
810 
811                 /* Continue the search. */
812                 continue;
813             }
814 
815 
816             /****************************************************************************************
817              *  (5)    PPPPPPPPPPPPPPPPPP                                                           *
818              *                   SSSSSSSSSSSS                                                       *
819              *        In this configuration, remove data from the back of the new packet,  insert   *
820              *        packet into the chain, and terminate the search.  Need to search for          *
821              *        contigous data, may need to send out ACK.                                     *
822              ****************************************************************************************/
823             if (((INT)(search_begin_sequence - packet_begin_sequence)) >= 0)
824             {
825 
826                 _nx_tcp_socket_state_data_trim(packet_ptr, (packet_end_sequence - search_begin_sequence));
827 
828                 /* Update packet_data_length. */
829                 packet_data_length -= (packet_end_sequence - search_begin_sequence);
830 
831                 /* Now the packet should be chained before search_ptr. */
832 
833                 break;
834             }
835 
836             /****************************************************************************************
837              *                                                                                      *
838              *  (6)        PPPPPPPPPPPPPP                                                           *
839              *        SSSSSSSS                                                                      *
840              *        In this configuration, remove data from the beginning of the search_ptr,      *
841              *        insert the packet after the search packet and continue the search.  This may  *
842              *        lead to case (2) and (3).                                                     *
843              *                                                                                      *
844              *                                                                                      *
845              ***************************************************************************************/
846             _nx_tcp_socket_state_data_trim(search_ptr, (ULONG)(search_end_sequence - packet_begin_sequence));
847 
848 #ifndef NX_DISABLE_TCP_INFO
849             /* The new packet has been admitted to the receive queue. */
850 
851             /* Reduce the TCP bytes received count.  */
852             ip_ptr -> nx_ip_tcp_bytes_received -= (search_end_sequence - packet_begin_sequence);
853 
854             /* Reduce the TCP bytes received count for the socket.  */
855             socket_ptr -> nx_tcp_socket_bytes_received -= (search_end_sequence - packet_begin_sequence);
856 
857 #endif /* NX_DISABLE_TCP_INFO */
858 
859             /* Move to the next packet and continue; */
860             previous_ptr = search_ptr;
861             search_ptr = search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next;
862         }   /* End of while (search_ptr) */
863 
864         /* At this point, the logic (within the while loop) finds a location where this packet should be inserted. */
865         if (previous_ptr == NX_NULL)
866         {
867 
868             /* The packet needs to be inserted at the beginning of the queue. */
869             socket_ptr -> nx_tcp_socket_receive_queue_head = packet_ptr;
870         }
871         else
872         {
873 
874             /* The packet needs to be inserted after previous_ptr. */
875             previous_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next = packet_ptr;
876         }
877 
878         if (search_ptr == NX_NULL)
879         {
880 
881             /* This packet is on the last one on the queue. */
882             socket_ptr -> nx_tcp_socket_receive_queue_tail = packet_ptr;
883 
884             /* Set the next pointer to indicate the packet is part of a TCP queue.  */
885             /*lint -e{923} suppress cast of ULONG to pointer.  */
886             packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ENQUEUED;
887         }
888         else
889         {
890 
891             /* Chain search_ptr onto packet_ptr. */
892             packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next = search_ptr;
893         }
894 
895         /* Add debug information. */
896         NX_PACKET_DEBUG(NX_PACKET_TCP_RECEIVE_QUEUE, __LINE__, packet_ptr);
897 
898         /* Increment the receive TCP packet count.  */
899         socket_ptr -> nx_tcp_socket_receive_queue_count++;
900 
901         /* End of the out-of-order search.  At this point, the packet has been inserted. */
902 
903         /* Now we need to figure out how much, if any, we can ACK.  */
904         search_ptr =    socket_ptr -> nx_tcp_socket_receive_queue_head;
905 
906         /* Get the sequence number expected by the TCP receive socket. */
907         expected_sequence =  socket_ptr -> nx_tcp_socket_rx_sequence;
908 
909         /* Loop to see how much data is contiguous in the queued packets.  */
910         do
911         {
912 
913             /* Setup a pointer to header of this packet in the sent list.  */
914             /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
915             search_header_ptr =  (NX_TCP_HEADER *)search_ptr -> nx_packet_prepend_ptr;
916 
917 
918             /* Calculate the header size for this packet.  */
919             header_length =  (search_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * (ULONG)sizeof(ULONG);
920 
921             search_begin_sequence = search_header_ptr -> nx_tcp_sequence_number;
922 
923             search_end_sequence = search_begin_sequence + search_ptr -> nx_packet_length - header_length;
924 
925             if ((INT)(expected_sequence - search_begin_sequence) >= 0)
926             {
927 
928                 if ((INT)(search_end_sequence - expected_sequence) > 0)
929                 {
930                     /* Sequence number is within this packet.  Advance sequence number. */
931                     expected_sequence = search_end_sequence;
932 
933                     socket_ptr -> nx_tcp_socket_rx_sequence = expected_sequence;
934 
935                     acked_packets++;
936 
937                     /* Mark this packet as ready for retrieval.  */
938                     /*lint -e{923} suppress cast of ULONG to pointer.  */
939                     search_ptr -> nx_packet_queue_next =  (NX_PACKET *)NX_PACKET_READY;
940                 }
941             }
942             else
943             {
944 
945                 /* Expected number is to the left of search_ptr.   Get out of the do-while loop!  */
946                 break;
947             }
948 
949             /* Move the search pointer to the next queued receive packet.  */
950             search_ptr =  search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next;
951 
952             /* Determine if we are at the end of the queue.  */
953             /*lint -e{923} suppress cast of ULONG to pointer.  */
954             if (search_ptr == ((NX_PACKET *)NX_PACKET_ENQUEUED))
955             {
956 
957                 /* At the end, set the search pointer to NULL.  */
958                 search_ptr =  NX_NULL;
959             }
960 
961 #ifdef NX_ENABLE_LOW_WATERMARK
962             /* Do not calculate sequence for packet that is to be dropped. */
963             if (drop_packet && (acked_packets >= (ULONG)socket_ptr -> nx_tcp_socket_receive_queue_maximum))
964             {
965 
966                 /* Get out of the loop!  */
967                 break;
968             }
969 #endif /* NX_ENABLE_LOW_WATERMARK */
970         } while (search_ptr);
971 
972         /* If there are no packet crosses the rx_sequence, the TCP stream in the receive queue contains
973            missing pieces. */
974 
975 #ifdef NX_ENABLE_LOW_WATERMARK
976         /* Does the number of queued packets exceed the maximum rx queue length, or the number of
977          * available packets in the default packet pool reaches low watermark? */
978         if (drop_packet)
979         {
980 
981             /* Yes it is. Remove the last packet in queue. */
982             socket_ptr -> nx_tcp_socket_receive_queue_tail -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED;
983             if (socket_ptr -> nx_tcp_socket_receive_queue_count > 1)
984             {
985 
986                 /* Find the previous packet of tail. */
987                 search_ptr = socket_ptr -> nx_tcp_socket_receive_queue_head;
988                 while (search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next != socket_ptr -> nx_tcp_socket_receive_queue_tail)
989                 {
990                     search_ptr = search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next;
991                 }
992 
993                 /* Release the tail. */
994                 _nx_packet_release(socket_ptr -> nx_tcp_socket_receive_queue_tail);
995 
996                 /* Setup the tail packet. */
997                 socket_ptr -> nx_tcp_socket_receive_queue_tail = search_ptr;
998 
999                 search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ENQUEUED;
1000 
1001                 /* Calculate the ending sequence number for the last packet.  */
1002                 search_header_ptr =  (NX_TCP_HEADER *)search_ptr -> nx_packet_prepend_ptr;
1003                 header_length = (search_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * sizeof(ULONG);
1004 
1005                 /* Decrease window size. */
1006                 socket_ptr -> nx_tcp_socket_rx_window_current = search_header_ptr -> nx_tcp_sequence_number +
1007                     (search_ptr -> nx_packet_length - header_length) -
1008                     socket_ptr -> nx_tcp_socket_rx_sequence;
1009                 socket_ptr -> nx_tcp_socket_rx_window_last_sent = socket_ptr -> nx_tcp_socket_rx_window_current;
1010             }
1011             else
1012             {
1013 
1014                 /* Release the tail. */
1015                 _nx_packet_release(socket_ptr -> nx_tcp_socket_receive_queue_tail);
1016 
1017                 /* Clear the head and tail packets. */
1018                 socket_ptr -> nx_tcp_socket_receive_queue_head = NX_NULL;
1019                 socket_ptr -> nx_tcp_socket_receive_queue_tail = NX_NULL;
1020 
1021                 /* No packets can be received. */
1022                 socket_ptr -> nx_tcp_socket_rx_window_current = 0;
1023                 socket_ptr -> nx_tcp_socket_rx_window_last_sent = 0;
1024             }
1025 
1026             /* Decrease receive queue count. */
1027             socket_ptr -> nx_tcp_socket_receive_queue_count--;
1028         }
1029 #endif /* NX_ENABLE_LOW_WATERMARK */
1030     }   /* End of out-of-order insertion. */
1031 
1032 
1033 #ifndef NX_DISABLE_TCP_INFO
1034     /* The new packet has been admitted to the receive queue. */
1035 
1036     /* Increment the TCP packet receive count and bytes received count.  */
1037     ip_ptr -> nx_ip_tcp_packets_received++;
1038     ip_ptr -> nx_ip_tcp_bytes_received += packet_data_length;
1039 
1040     /* Increment the TCP packet receive count and bytes received count for the socket.  */
1041     socket_ptr -> nx_tcp_socket_packets_received++;
1042     socket_ptr -> nx_tcp_socket_bytes_received += packet_data_length;
1043 #endif
1044 
1045     /* Check if the rx sequence number has been updated.  */
1046     if (original_rx_sequence != socket_ptr -> nx_tcp_socket_rx_sequence)
1047     {
1048 
1049         /* Decrease the receive window size since rx_sequence is updated.  */
1050         socket_ptr -> nx_tcp_socket_rx_window_current -= (socket_ptr -> nx_tcp_socket_rx_sequence - original_rx_sequence);
1051 
1052         /* Update the rx_window_last_sent for SWS avoidance algorithm.
1053            RFC1122, Section4.2.3.3, Page97-98.  */
1054         socket_ptr -> nx_tcp_socket_rx_window_last_sent -= (socket_ptr -> nx_tcp_socket_rx_sequence - original_rx_sequence);
1055     }
1056 
1057 #ifdef NX_TCP_MAX_OUT_OF_ORDER_PACKETS
1058     /* Does the count of out of order packets exceed the defined value? */
1059     if ((socket_ptr -> nx_tcp_socket_receive_queue_count - acked_packets) >
1060         NX_TCP_MAX_OUT_OF_ORDER_PACKETS)
1061     {
1062 
1063         /* Yes it is. Remove the last packet in queue. */
1064         socket_ptr -> nx_tcp_socket_receive_queue_tail -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED;
1065         if (socket_ptr -> nx_tcp_socket_receive_queue_count > 1)
1066         {
1067 
1068             /* Find the previous packet of tail. */
1069             search_ptr = socket_ptr -> nx_tcp_socket_receive_queue_head;
1070             while (search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next != socket_ptr -> nx_tcp_socket_receive_queue_tail)
1071             {
1072                 search_ptr = search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next;
1073             }
1074 
1075             /* Release the tail. */
1076             _nx_packet_release(socket_ptr -> nx_tcp_socket_receive_queue_tail);
1077 
1078             /* Setup the tail packet. */
1079             socket_ptr -> nx_tcp_socket_receive_queue_tail = search_ptr;
1080 
1081             search_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ENQUEUED;
1082         }
1083         else
1084         {
1085 
1086             /* Release the tail. */
1087             _nx_packet_release(socket_ptr -> nx_tcp_socket_receive_queue_tail);
1088 
1089             /* Clear the head and tail packets. */
1090             socket_ptr -> nx_tcp_socket_receive_queue_head = NX_NULL;
1091             socket_ptr -> nx_tcp_socket_receive_queue_tail = NX_NULL;
1092         }
1093 
1094         /* Decrease receive queue count. */
1095         socket_ptr -> nx_tcp_socket_receive_queue_count--;
1096     }
1097 #endif /* NX_TCP_MAX_OUT_OF_ORDER_PACKETS */
1098 
1099     /* At this point, we can use the packet TCP header pointers since the received
1100        packet is already queued.  */
1101 
1102     /* Any packets for receiving? */
1103     while (acked_packets && socket_ptr -> nx_tcp_socket_receive_suspension_list
1104 #ifdef NX_ENABLE_HTTP_PROXY
1105            && (socket_ptr -> nx_tcp_socket_http_proxy_state != NX_HTTP_PROXY_STATE_CONNECTING)
1106 #endif /* NX_ENABLE_HTTP_PROXY */
1107           )
1108     {
1109 
1110         /* Setup a pointer to the first queued packet.  */
1111         packet_ptr =  socket_ptr -> nx_tcp_socket_receive_queue_head;
1112         /* Remove it from the queue.  */
1113 
1114         /* Simply update the head pointer of the queue.  */
1115         socket_ptr -> nx_tcp_socket_receive_queue_head =  packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next;
1116 
1117         /* Mark the packet as no longer being part of the TCP queue.  */
1118         /*lint -e{923} suppress cast of ULONG to pointer.  */
1119         packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next =  (NX_PACKET *)NX_PACKET_ALLOCATED;
1120 
1121         /* Clear the queue next pointer.  */
1122         packet_ptr -> nx_packet_queue_next =  NX_NULL;
1123 
1124         /* Decrease the number of received packets.  */
1125         socket_ptr -> nx_tcp_socket_receive_queue_count--;
1126 
1127         /* Adjust the packet for delivery to the suspended thread.  */
1128 
1129         /* Setup a pointer to the TCP header of this packet.  */
1130         /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
1131         tcp_header_ptr =  (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
1132 
1133         /* Calculate the header size for this packet.  */
1134         header_length =  (tcp_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * (ULONG)sizeof(ULONG);
1135 
1136         /* Adjust the packet prepend pointer and length to position past the TCP header.  */
1137         packet_ptr -> nx_packet_prepend_ptr =  packet_ptr -> nx_packet_prepend_ptr + header_length;
1138         packet_ptr -> nx_packet_length =       packet_ptr -> nx_packet_length - header_length;
1139 
1140         /* Setup a pointer to the first thread suspended on the receive queue.  */
1141         thread_ptr =  socket_ptr -> nx_tcp_socket_receive_suspension_list;
1142 
1143         /* Place the packet pointer in the return pointer.  */
1144         *((NX_PACKET **)thread_ptr -> tx_thread_additional_suspend_info) =  packet_ptr;
1145 
1146         /* Increase the receive window size.  */
1147         socket_ptr -> nx_tcp_socket_rx_window_current += packet_ptr -> nx_packet_length;
1148 
1149         /* Remove the suspended thread from the list.  */
1150 
1151         /* Decrement the suspension count.  */
1152         socket_ptr -> nx_tcp_socket_receive_suspended_count--;
1153 
1154         /* Decrement the acked_packets count. */
1155         acked_packets--;
1156 
1157         /* Resume thread.  */
1158         _nx_tcp_socket_thread_resume(&(socket_ptr -> nx_tcp_socket_receive_suspension_list), NX_SUCCESS);
1159     }
1160 
1161     /* Is the queue empty?.  */
1162     if (socket_ptr -> nx_tcp_socket_receive_queue_count == 0)
1163     {
1164 
1165         /* Yes. Set both head and tail pointers to NULL.  */
1166         socket_ptr -> nx_tcp_socket_receive_queue_head =  NX_NULL;
1167         socket_ptr -> nx_tcp_socket_receive_queue_tail =  NX_NULL;
1168     }
1169 
1170     /* Determine if an ACK should be forced out for window update, SWS avoidance algorithm.
1171        RFC1122, Section4.2.3.3, Page97-98. */
1172     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))
1173     {
1174 
1175         /* Need to send ACK for window update.  */
1176         need_ack = NX_TRUE;
1177     }
1178 
1179     /* If the incoming packet caused the sequence number to move forward,
1180        indicating the new piece of data is in order, in sequence, and valid for receiving. */
1181     if ((original_rx_sequence != socket_ptr -> nx_tcp_socket_rx_sequence)
1182 #ifdef NX_ENABLE_TCPIP_OFFLOAD
1183         || tcpip_offload
1184 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
1185        )
1186     {
1187 
1188 #ifdef NX_ENABLE_HTTP_PROXY
1189 
1190         /* If HTTP Proxy is connecting, the data is the response from HTTP Proxy server, don't need to notify application.  */
1191         if (socket_ptr -> nx_tcp_socket_http_proxy_state != NX_HTTP_PROXY_STATE_CONNECTING)
1192 #endif /* NX_ENABLE_HTTP_PROXY */
1193         {
1194 
1195             /* Determine if there is a socket receive notification function specified.  */
1196             if (socket_ptr -> nx_tcp_receive_callback)
1197             {
1198 
1199                 /* Yes, notification is requested.  Call the application's receive notification
1200                    function for this socket.  */
1201                 (socket_ptr -> nx_tcp_receive_callback)(socket_ptr);
1202             }
1203         }
1204 
1205 #ifdef NX_TCP_ACK_EVERY_N_PACKETS
1206         /* Determine if we need to ACK up to the current sequence number.  */
1207 
1208         /* If we are still in an ESTABLISHED state, a FIN isn't present and we can
1209            allocate a packet for the ACK message, send an ACK message.  */
1210         if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED) &&
1211             ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_FIN_BIT) == 0))
1212         {
1213             if (socket_ptr -> nx_tcp_socket_ack_n_packet_counter >= NX_TCP_ACK_EVERY_N_PACKETS)
1214             {
1215                 socket_ptr -> nx_tcp_socket_ack_n_packet_counter = 1;
1216 
1217                 /* Need to send an immediate ACK.  */
1218                 need_ack = NX_TRUE;
1219             }
1220             else
1221             {
1222                 socket_ptr -> nx_tcp_socket_ack_n_packet_counter++;
1223             }
1224         }
1225 #endif
1226     }
1227 
1228     if (need_ack == NX_TRUE)
1229     {
1230 
1231         /* Need to send ACK.  */
1232         _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
1233     }
1234 
1235     /* Return true since the packet was queued.  */
1236     return(NX_TRUE);
1237 }
1238 
1239