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