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