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