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 
24 
25 /* Include necessary system files.  */
26 
27 #include "nx_api.h"
28 #include "nx_tcp.h"
29 #include "nx_packet.h"
30 #include "nx_ip.h"
31 
32 #ifdef FEATURE_NX_IPV6
33 #include "nx_ipv6.h"
34 #endif /* FEATURE_NX_IPV6 */
35 
36 #ifdef NX_IPSEC_ENABLE
37 #include "nx_ipsec.h"
38 #endif /* NX_IPSEC_ENABLE */
39 
40 
41 /**************************************************************************/
42 /*                                                                        */
43 /*  FUNCTION                                               RELEASE        */
44 /*                                                                        */
45 /*    _nx_tcp_packet_process                              PORTABLE C      */
46 /*                                                           6.3.0        */
47 /*  AUTHOR                                                                */
48 /*                                                                        */
49 /*    Yuxin Zhou, Microsoft Corporation                                   */
50 /*                                                                        */
51 /*  DESCRIPTION                                                           */
52 /*                                                                        */
53 /*    This function processes an incoming TCP packet, which includes      */
54 /*    matching the packet to an existing connection and dispatching to    */
55 /*    the socket specific processing routine.  If no connection is        */
56 /*    found, this routine checks for a new connection request and if      */
57 /*    found, processes it accordingly. If a reset packet is received, it  */
58 /*    checks the queue for a previous connection request which needs to be*/
59 /*    removed.                                                            */
60 /*                                                                        */
61 /*  INPUT                                                                 */
62 /*                                                                        */
63 /*    ip_ptr                                Pointer to IP control block   */
64 /*    packet_ptr                            Pointer to packet to send     */
65 /*                                                                        */
66 /*  OUTPUT                                                                */
67 /*                                                                        */
68 /*    None                                                                */
69 /*                                                                        */
70 /*  CALLS                                                                 */
71 /*                                                                        */
72 /*    _nx_packet_release                    Packet release function       */
73 /*    _nx_ip_checksum_compute               Calculate TCP packet checksum */
74 /*    _nx_tcp_mss_option_get                Get peer MSS option           */
75 /*    _nx_tcp_no_connection_reset           Reset on no connection        */
76 /*    _nx_tcp_packet_send_syn               Send SYN message              */
77 /*    _nx_tcp_socket_packet_process         Socket specific packet        */
78 /*                                            processing routine          */
79 /*    (nx_tcp_listen_callback)              Application listen callback   */
80 /*                                            function                    */
81 /*                                                                        */
82 /*  CALLED BY                                                             */
83 /*                                                                        */
84 /*    _nx_tcp_queue_process                 Process TCP packet queue      */
85 /*    _nx_tcp_packet_receive                Receive packet processing     */
86 /*                                                                        */
87 /*  RELEASE HISTORY                                                       */
88 /*                                                                        */
89 /*    DATE              NAME                      DESCRIPTION             */
90 /*                                                                        */
91 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
92 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
93 /*                                            resulting in version 6.1    */
94 /*  10-31-2023     Tiejun Zhou              Modified comment(s),          */
95 /*                                            validated TCP header buffer,*/
96 /*                                            resulting in version 6.3.0  */
97 /*                                                                        */
98 /**************************************************************************/
_nx_tcp_packet_process(NX_IP * ip_ptr,NX_PACKET * packet_ptr)99 VOID  _nx_tcp_packet_process(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
100 {
101 
102 UINT                         index;
103 UINT                         port;
104 ULONG                       *source_ip = NX_NULL;
105 ULONG                       *dest_ip = NX_NULL;
106 UINT                         source_port;
107 NX_TCP_SOCKET               *socket_ptr;
108 NX_TCP_HEADER               *tcp_header_ptr;
109 struct NX_TCP_LISTEN_STRUCT *listen_ptr;
110 VOID                         (*listen_callback)(NX_TCP_SOCKET *socket_ptr, UINT port);
111 ULONG                        option_words;
112 ULONG                        mss = 0;
113 ULONG                        checksum;
114 NX_INTERFACE                *interface_ptr = NX_NULL;
115 #if defined(NX_DISABLE_TCP_RX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE)
116 UINT                         compute_checksum = 1;
117 #endif /* defined(NX_DISABLE_TCP_RX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) */
118 ULONG                        queued_count;
119 NX_PACKET                   *queued_ptr;
120 NX_PACKET                   *queued_prev_ptr;
121 ULONG                       *queued_source_ip;
122 UINT                         queued_source_port;
123 UINT                         is_a_RST_request;
124 UINT                         is_valid_option_flag = NX_TRUE;
125 UINT                         status;
126 #ifdef NX_ENABLE_TCP_WINDOW_SCALING
127 ULONG                        rwin_scale = 0xFF;
128 #endif /* NX_ENABLE_TCP_WINDOW_SCALING */
129 
130 #ifdef NX_DISABLE_TCP_RX_CHECKSUM
131     compute_checksum = 0;
132 #endif /* NX_DISABLE_TCP_RX_CHECKSUM */
133 
134     /* Add debug information. */
135     NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
136 
137     /* Pickup the source IP address.  */
138 #ifndef NX_DISABLE_IPV4
139     if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4)
140     {
141 
142     NX_IPV4_HEADER *ip_header_ptr;
143 
144         /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
145         ip_header_ptr = (NX_IPV4_HEADER *)packet_ptr -> nx_packet_ip_header;
146 
147         source_ip = &ip_header_ptr -> nx_ip_header_source_ip;
148 
149         dest_ip = &ip_header_ptr -> nx_ip_header_destination_ip;
150 
151         mss = 536;
152 
153         interface_ptr = packet_ptr -> nx_packet_address.nx_packet_interface_ptr;
154     }
155 #endif /* !NX_DISABLE_IPV4  */
156 
157 #ifdef FEATURE_NX_IPV6
158     if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6)
159     {
160 
161     /* IPv6 */
162     NX_IPV6_HEADER *ipv6_header;
163 
164         /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
165         ipv6_header = (NX_IPV6_HEADER *)packet_ptr -> nx_packet_ip_header;
166 
167         source_ip = &ipv6_header -> nx_ip_header_source_ip[0];
168 
169         dest_ip = &ipv6_header -> nx_ip_header_destination_ip[0];
170 
171         mss = 1220;
172 
173         interface_ptr = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_attached;
174     }
175 #endif /* FEATURE_NX_IPV6 */
176 
177 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
178     if (interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_TCP_RX_CHECKSUM)
179     {
180         compute_checksum = 0;
181     }
182 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
183 
184 #ifdef NX_IPSEC_ENABLE
185     if ((packet_ptr -> nx_packet_ipsec_sa_ptr != NX_NULL) && (((NX_IPSEC_SA *)(packet_ptr -> nx_packet_ipsec_sa_ptr)) -> nx_ipsec_sa_encryption_method != NX_CRYPTO_NONE))
186     {
187         compute_checksum = 1;
188     }
189 #endif /* NX_IPSEC_ENABLE */
190 
191 #if defined(NX_DISABLE_TCP_RX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE)
192     if (compute_checksum)
193 #endif /* defined(NX_DISABLE_TCP_RX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) */
194     {
195         checksum = _nx_ip_checksum_compute(packet_ptr, NX_PROTOCOL_TCP,
196                                            (UINT)packet_ptr -> nx_packet_length,
197                                            source_ip, dest_ip);
198 
199         checksum = NX_LOWER_16_MASK & ~checksum;
200 
201         /* Calculate the checksum.  */
202         if (checksum != 0)
203         {
204 
205 #ifndef NX_DISABLE_TCP_INFO
206 
207             /* Increment the TCP invalid packet error count.  */
208             ip_ptr -> nx_ip_tcp_invalid_packets++;
209 
210             /* Increment the TCP packet checksum error count.  */
211             ip_ptr -> nx_ip_tcp_checksum_errors++;
212 #endif
213 
214             /* Checksum error, just release the packet.  */
215             _nx_packet_release(packet_ptr);
216             return;
217         }
218     }
219 
220 #ifndef NX_DISABLE_RX_SIZE_CHECKING
221     /* Make sure the TCP header is in the first packet.  */
222     if ((UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) < sizeof(NX_TCP_HEADER))
223     {
224 
225 #ifndef NX_DISABLE_TCP_INFO
226         /* Increment the TCP invalid packet error.  */
227         ip_ptr -> nx_ip_tcp_invalid_packets++;
228 #endif
229 
230         /* Not supported.  */
231         _nx_packet_release(packet_ptr);
232         return;
233     }
234 #endif /* NX_DISABLE_RX_SIZE_CHECKING */
235 
236     /* Pickup the pointer to the head of the TCP packet.  */
237     /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
238     tcp_header_ptr =  (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
239 
240     /* Endian swapping logic.  If NX_LITTLE_ENDIAN is specified, these macros will
241        swap the endian of the TCP header.  */
242     NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_0);
243     NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_sequence_number);
244     NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_acknowledgment_number);
245     NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3);
246     NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4);
247 
248     /* Determine if there are any option words...  Note there are always 5 words in a TCP header.  */
249     option_words =  (tcp_header_ptr -> nx_tcp_header_word_3 >> 28) - 5;
250 
251 #ifndef NX_DISABLE_RX_SIZE_CHECKING
252     /* Check for valid packet length.  */
253     if (((INT)option_words < 0) ||
254         ((UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) <
255          (sizeof(NX_TCP_HEADER) + (option_words << 2))))
256     {
257 
258 #ifndef NX_DISABLE_TCP_INFO
259         /* Increment the TCP invalid packet error.  */
260         ip_ptr -> nx_ip_tcp_invalid_packets++;
261 #endif
262 
263         /* Invalid packet length, just release it.  */
264         _nx_packet_release(packet_ptr);
265 
266         /* The function is complete, just return!  */
267         return;
268     }
269 #endif
270 
271     if (option_words)
272     {
273 
274         /* Yes, there are one or more option words.  */
275 
276         /* Derive the Maximum Segment Size (MSS) in the option words.  */
277         status = _nx_tcp_mss_option_get((packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_TCP_HEADER)), option_words * (ULONG)sizeof(ULONG), &mss);
278 
279         /* Check the status. if status is NX_FALSE, means Option Length is invalid.  */
280         if (status == NX_FALSE)
281         {
282 
283             /* The option is invalid.  */
284             is_valid_option_flag = NX_FALSE;
285         }
286         else
287         {
288 
289             /* Set the default MSS if the MSS value was not found.  */
290             /*lint -e{644} suppress variable might not be initialized, since "mss" was initialized in _nx_tcp_mss_option_get. */
291             if (mss == 0)
292             {
293 #ifndef NX_DISABLE_IPV4
294                 if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4)
295                 {
296                     mss = 536;
297                 }
298 #endif /* !NX_DISABLE_IPV4  */
299 
300 #ifdef FEATURE_NX_IPV6
301                 if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6)
302                 {
303                     mss = 1220;
304                 }
305 #endif /* FEATURE_NX_IPV6 */
306             }
307         }
308 
309 #ifdef NX_ENABLE_TCP_WINDOW_SCALING
310         status = _nx_tcp_window_scaling_option_get((packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_TCP_HEADER)), option_words * (ULONG)sizeof(ULONG), &rwin_scale);
311 
312         /* Check the status. if status is NX_FALSE, means Option Length is invalid.  */
313         if (status == NX_FALSE)
314         {
315             is_valid_option_flag = NX_FALSE;
316         }
317 #endif /* NX_ENABLE_TCP_WINDOW_SCALING */
318     }
319 
320     /* Pickup the destination TCP port.  */
321     port =  (UINT)(tcp_header_ptr -> nx_tcp_header_word_0 & NX_LOWER_16_MASK);
322 
323     /* Pickup the source TCP port.  */
324     source_port =  (UINT)(tcp_header_ptr -> nx_tcp_header_word_0 >> NX_SHIFT_BY_16);
325 
326     /* Calculate the hash index in the TCP port array of the associated IP instance.  */
327     index =  (UINT)((port + (port >> 8)) & NX_TCP_PORT_TABLE_MASK);
328 
329     /* Search the bound sockets in this index for the particular port.  */
330     socket_ptr =  ip_ptr -> nx_ip_tcp_port_table[index];
331 
332     /* Determine if there are any sockets bound on this port index.  */
333     if (socket_ptr)
334     {
335 
336     INT find_a_match;
337 
338         /*  Yes, loop to examine the list of bound ports on this index.  */
339         do
340         {
341 
342             find_a_match = 0;
343 
344             /* Determine if the port has been found.  */
345             if ((socket_ptr -> nx_tcp_socket_port == port) &&
346                 (socket_ptr -> nx_tcp_socket_connect_port == source_port))
347             {
348 
349                 /* Make sure they are the same IP protocol */
350                 if (socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version == packet_ptr -> nx_packet_ip_version)
351                 {
352 
353 #ifndef NX_DISABLE_IPV4
354                     if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4)
355                     {
356 
357                         if (socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_address.v4 == *source_ip)
358                         {
359                             find_a_match = 1;
360                         }
361                     }
362 #endif /* !NX_DISABLE_IPV4  */
363 
364 #ifdef FEATURE_NX_IPV6
365                     if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6)
366                     {
367                         if (CHECK_IPV6_ADDRESSES_SAME(socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_address.v6, source_ip))
368                         {
369                             find_a_match = 1;
370                         }
371                     }
372 #endif /* FEATURE_NX_IPV6 */
373                 }
374 
375                 if (find_a_match)
376                 {
377 
378                     /* Yes, we have a match!  */
379 
380                     /* Determine if we need to update the tcp port head pointer.  This should
381                        only be done if the found socket pointer is not the head pointer and
382                        the mutex for this IP instance is available.  */
383 
384                     /* Move the port head pointer to this socket.  */
385                     ip_ptr -> nx_ip_tcp_port_table[index] = socket_ptr;
386 
387                     /* If this packet contains SYN */
388                     if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT)
389                     {
390 
391                         /* Record the MSS value if it is present and the   Otherwise use 536, as
392                            outlined in RFC 1122 section 4.2.2.6. */
393                         socket_ptr -> nx_tcp_socket_peer_mss = mss;
394 
395                         if ((mss > socket_ptr -> nx_tcp_socket_mss) && socket_ptr -> nx_tcp_socket_mss)
396                         {
397                             socket_ptr -> nx_tcp_socket_connect_mss  = socket_ptr -> nx_tcp_socket_mss;
398                         }
399                         else if ((socket_ptr -> nx_tcp_socket_state != NX_TCP_SYN_SENT) ||
400                                  (socket_ptr -> nx_tcp_socket_connect_mss > mss))
401                         {
402                             socket_ptr -> nx_tcp_socket_connect_mss  = mss;
403                         }
404 
405                         /* Compute the SMSS * SMSS value, so later TCP module doesn't need to redo the multiplication. */
406                         socket_ptr -> nx_tcp_socket_connect_mss2 =
407                             socket_ptr -> nx_tcp_socket_connect_mss * socket_ptr -> nx_tcp_socket_connect_mss;
408 #ifdef NX_ENABLE_TCP_WINDOW_SCALING
409                         /*
410                            Simply record the peer's window scale value. When we move to the
411                            ESTABLISHED state, we will set the peer window scale to 0 if the
412                            peer does not support this feature.
413                          */
414                         socket_ptr -> nx_tcp_snd_win_scale_value = rwin_scale;
415 #endif /* NX_ENABLE_TCP_WINDOW_SCALING */
416                     }
417 
418                     /* Process the packet within an existing TCP connection.  */
419                     _nx_tcp_socket_packet_process(socket_ptr, packet_ptr);
420 
421                     /* Get out of the search loop and this function!  */
422                     return;
423                 }
424             }
425 
426             /* Move to the next entry in the bound index.  */
427             socket_ptr =  socket_ptr -> nx_tcp_socket_bound_next;
428         } while (socket_ptr != ip_ptr -> nx_ip_tcp_port_table[index]);
429     }
430 
431     /* At this point, we know there is not an existing TCP connection.  */
432 
433     /* If this packet contains the valid option.  */
434     if (is_valid_option_flag == NX_FALSE)
435     {
436 
437         /* Send RST message.
438            TCP MUST be prepared to handle an illegal option length (e.g., zero) without crashing;
439            a suggested procedure is to reset the connection and log the reason, outlined in RFC 1122, Section 4.2.2.5, Page85. */
440         _nx_tcp_no_connection_reset(ip_ptr, packet_ptr, tcp_header_ptr);
441 
442 #ifndef NX_DISABLE_TCP_INFO
443         /* Increment the TCP invalid packet error count.  */
444         ip_ptr -> nx_ip_tcp_invalid_packets++;
445 #endif /* NX_DISABLE_TCP_INFO */
446 
447         /* Not a connection request, just release the packet.  */
448         _nx_packet_release(packet_ptr);
449 
450         return;
451     }
452 
453 #ifdef NX_ENABLE_TCP_MSS_CHECK
454     /* Optionally check for a user specified minimum MSS. The user application may choose to
455        define a minimum MSS value, and reject a TCP connection if peer MSS value does not
456        meet the minimum. */
457     if (mss < NX_TCP_MSS_MINIMUM)
458     {
459 
460         /* Send RST message.  */
461         _nx_tcp_no_connection_reset(ip_ptr, packet_ptr, tcp_header_ptr);
462 
463 #ifndef NX_DISABLE_TCP_INFO
464         /* Increment the TCP invalid packet error count.  */
465         ip_ptr -> nx_ip_tcp_invalid_packets++;
466 #endif /* NX_DISABLE_TCP_INFO */
467 
468         /* Handle this as an invalid connection request. */
469         _nx_packet_release(packet_ptr);
470 
471         return;
472     }
473 #endif
474 
475     /* Handle new connection requests without ACK bit in NX_TCP_SYN_RECEIVED state.
476        NX_TCP_SYN_RECEIVED state is equal of LISTEN state of RFC.
477        RFC793, Section3.9, Page65. */
478     if ((!(tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT)) &&
479         (ip_ptr -> nx_ip_tcp_active_listen_requests))
480     {
481 
482 #ifndef NX_DISABLE_IPV4
483         if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4)
484         {
485 
486             /* Check for LAND attack packet. This is an incoming packet with matching
487                Source and Destination IP address, and matching source and destination port. */
488             if ((*source_ip == *dest_ip) && (source_port == port))
489             {
490 
491                 /* Bogus packet. Drop it! */
492 
493 #ifndef NX_DISABLE_TCP_INFO
494                 /* Increment the TCP invalid packet error count.  */
495                 ip_ptr -> nx_ip_tcp_invalid_packets++;
496 #endif /* NX_DISABLE_TCP_INFO */
497 
498                 /* Release the packet we will not process any further.  */
499                 _nx_packet_release(packet_ptr);
500                 return;
501             }
502 
503             /* It shall not make connections if the source IP address
504                is broadcast or multicast.   */
505             if (
506                 /* Check for Multicast address */
507                 ((*source_ip & NX_IP_CLASS_D_MASK) == NX_IP_CLASS_D_TYPE) ||
508                 /* Check for subnet-directed broadcast */
509                 (((*source_ip & interface_ptr -> nx_interface_ip_network_mask) == interface_ptr -> nx_interface_ip_network) &&
510                  ((*source_ip & ~(interface_ptr -> nx_interface_ip_network_mask)) == ~(interface_ptr -> nx_interface_ip_network_mask))) ||
511                 /* Check for local subnet address */
512                 (*source_ip == interface_ptr -> nx_interface_ip_network)  ||
513                 /* Check for limited broadcast */
514                 (*source_ip == NX_IP_LIMITED_BROADCAST)
515                )
516             {
517 
518 #ifndef NX_DISABLE_TCP_INFO
519                 /* Increment the TCP invalid packet error count.  */
520                 ip_ptr -> nx_ip_tcp_invalid_packets++;
521 #endif /* NX_DISABLE_TCP_INFO */
522 
523                 /* Release the packet.  */
524                 _nx_packet_release(packet_ptr);
525 
526                 /* Finished processing, simply return!  */
527                 return;
528             }
529         }
530 #endif /* !NX_DISABLE_IPV4  */
531 
532 #ifdef FEATURE_NX_IPV6
533         if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6)
534         {
535 
536             /* Check for LAND attack packet. This is an incoming packet with matching
537                Source and Destination IP address, and matching source and destination port. */
538             if ((CHECK_IPV6_ADDRESSES_SAME(source_ip, dest_ip)) && (source_port == port))
539             {
540 
541                 /* Bogus packet. Drop it! */
542 
543 #ifndef NX_DISABLE_TCP_INFO
544                 /* Increment the TCP invalid packet error count.  */
545                 ip_ptr -> nx_ip_tcp_invalid_packets++;
546 #endif /* NX_DISABLE_TCP_INFO */
547 
548                 /* Release the packet we will not process any further.  */
549                 _nx_packet_release(packet_ptr);
550                 return;
551             }
552 
553             /* It shall not make connections if the source IP address
554                is broadcast or multicast.   */
555             if (IPv6_Address_Type(source_ip) & IPV6_ADDRESS_MULTICAST)
556             {
557 
558 #ifndef NX_DISABLE_TCP_INFO
559                 /* Increment the TCP invalid packet error count.  */
560                 ip_ptr -> nx_ip_tcp_invalid_packets++;
561 #endif /* NX_DISABLE_TCP_INFO */
562 
563                 /* Release the packet.  */
564                 _nx_packet_release(packet_ptr);
565 
566                 /* Finished processing, simply return!  */
567                 return;
568             }
569         }
570 #endif /* FEATURE_NX_IPV6*/
571 
572         /* Search all ports in listen mode for a match. */
573         listen_ptr =  ip_ptr -> nx_ip_tcp_active_listen_requests;
574         do
575         {
576 
577             /* Determine if this port is in a listen mode.  */
578             if (listen_ptr -> nx_tcp_listen_port == port)
579             {
580 
581                 /* Determine if the packet is an initial connection request.
582                    The incoming SYN packet is a connection request.
583                    The incoming RST packet is related to a previous connection request.
584                    Fourth other text or control. RFC793, Section3.9, Page66. */
585                 if ((!(tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT)) &&
586                     (!(tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_RST_BIT)))
587                 {
588 
589 #ifndef NX_DISABLE_TCP_INFO
590                     /* This is a duplicate connection request. Increment the TCP dropped packet count.  */
591                     ip_ptr -> nx_ip_tcp_receive_packets_dropped++;
592 #endif /* NX_DISABLE_TCP_INFO */
593 
594                     /* Release the packet.  */
595                     _nx_packet_release(packet_ptr);
596 
597                     return;
598                 }
599 
600 #ifndef NX_DISABLE_TCP_INFO
601 
602                 /* Check for a SYN bit set.  */
603                 if ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT))
604                 {
605 
606                     /* Increment the passive TCP connections count.  */
607                     ip_ptr -> nx_ip_tcp_passive_connections++;
608 
609                     /* Increment the TCP connections count.  */
610                     ip_ptr -> nx_ip_tcp_connections++;
611                 }
612 #endif
613 
614                 /* Okay, this port is in a listen mode.  We now need to see if
615                    there is an available socket for the new connection request
616                    present.  */
617                 if ((listen_ptr -> nx_tcp_listen_socket_ptr) &&
618                     ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_RST_BIT) == NX_NULL))
619                 {
620 
621                     /* Yes there is indeed a socket present.  We now need to
622                        fill in the appropriate info and call the server callback
623                        routine.  */
624 
625                     /* Allocate the supplied server socket.  */
626                     socket_ptr = listen_ptr -> nx_tcp_listen_socket_ptr;
627 
628 #ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT
629                     /* If extended notify is enabled, call the syn_received notify function.
630                        This user-supplied function decides whether or not this SYN request
631                        should be accepted. */
632                     if (socket_ptr -> nx_tcp_socket_syn_received_notify)
633                     {
634 
635                         /* Add debug information. */
636                         NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
637 
638                         if ((socket_ptr -> nx_tcp_socket_syn_received_notify)(socket_ptr, packet_ptr) != NX_TRUE)
639                         {
640 
641                             /* Release the packet.  */
642                             _nx_packet_release(packet_ptr);
643 
644                             /* Finished processing, simply return!  */
645                             return;
646                         }
647                     }
648 #endif /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */
649 
650                     /* If trace is enabled, insert this event into the trace buffer.  */
651                     NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_SYN_RECEIVE, ip_ptr, socket_ptr, packet_ptr, tcp_header_ptr -> nx_tcp_sequence_number, NX_TRACE_INTERNAL_EVENTS, 0, 0);
652 
653                     /* Clear the server socket pointer in the listen request.  If the
654                        application wishes to honor more server connections on this port,
655                        the application must call relisten with a new server socket
656                        pointer.  */
657                     listen_ptr -> nx_tcp_listen_socket_ptr =  NX_NULL;
658 
659                     /* Fill the socket in with the appropriate information.  */
660 
661 
662 #ifndef NX_DISABLE_IPV4
663                     if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4)
664                     {
665 
666                         /* Assume the interface that receives the incoming packet is the best interface
667                            for sending responses. */
668                         socket_ptr -> nx_tcp_socket_connect_interface = interface_ptr;
669                         socket_ptr -> nx_tcp_socket_next_hop_address = NX_NULL;
670 
671                         /* Set the next hop address.  */
672                         _nx_ip_route_find(ip_ptr, *source_ip, &socket_ptr -> nx_tcp_socket_connect_interface,
673                                           &socket_ptr -> nx_tcp_socket_next_hop_address);
674 
675                         socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version =  NX_IP_VERSION_V4;
676                         socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_address.v4 = *source_ip;
677                     }
678 #endif /* !NX_DISABLE_IPV4  */
679 
680 #ifdef FEATURE_NX_IPV6
681                     if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6)
682                     {
683 
684                         socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version = NX_IP_VERSION_V6;
685                         COPY_IPV6_ADDRESS(source_ip, socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_address.v6);
686 
687                         /* Also record the outgoing interface information. */
688                         socket_ptr -> nx_tcp_socket_ipv6_addr = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr;
689                         socket_ptr -> nx_tcp_socket_connect_interface = interface_ptr;
690                     }
691 #endif /* FEATURE_NX_IPV6 */
692 
693                     socket_ptr -> nx_tcp_socket_connect_port = source_port;
694                     socket_ptr -> nx_tcp_socket_rx_sequence =  tcp_header_ptr -> nx_tcp_sequence_number;
695 
696 
697                     /* Yes, MSS was found, so store it!  */
698                     socket_ptr -> nx_tcp_socket_peer_mss = mss;
699 
700 #ifdef NX_ENABLE_TCP_WINDOW_SCALING
701                     /*
702                        Simply record the peer's window scale value. When we move to the
703                        ESTABLISHED state, we will set the peer window scale to 0 if the
704                        peer does not support this feature.
705                      */
706                     socket_ptr -> nx_tcp_snd_win_scale_value = rwin_scale;
707 #endif /* NX_ENABLE_TCP_WINDOW_SCALING */
708 
709                     /* Set the initial slow start threshold to be the advertised window size. */
710                     socket_ptr -> nx_tcp_socket_tx_slow_start_threshold = socket_ptr -> nx_tcp_socket_tx_window_advertised;
711 
712                     /* Slow start:  setup initial window (IW) to be MSS,  RFC 2581, 3.1 */
713                     socket_ptr -> nx_tcp_socket_tx_window_congestion = mss;
714 
715                     /* Initialize the transmit outstanding byte count to zero. */
716                     socket_ptr -> nx_tcp_socket_tx_outstanding_bytes = 0;
717 
718                     /* Calculate the hash index in the TCP port array of the associated IP instance.  */
719                     index = (UINT)((port + (port >> 8)) & NX_TCP_PORT_TABLE_MASK);
720 
721                     /* Determine if the list is NULL.  */
722                     if (ip_ptr -> nx_ip_tcp_port_table[index])
723                     {
724 
725                         /* There are already sockets on this list... just add this one
726                            to the end.  */
727                         socket_ptr -> nx_tcp_socket_bound_next =
728                             ip_ptr -> nx_ip_tcp_port_table[index];
729                         socket_ptr -> nx_tcp_socket_bound_previous =
730                             (ip_ptr -> nx_ip_tcp_port_table[index]) -> nx_tcp_socket_bound_previous;
731                         ((ip_ptr -> nx_ip_tcp_port_table[index]) -> nx_tcp_socket_bound_previous) -> nx_tcp_socket_bound_next =
732                             socket_ptr;
733                         (ip_ptr -> nx_ip_tcp_port_table[index]) -> nx_tcp_socket_bound_previous = socket_ptr;
734                     }
735                     else
736                     {
737 
738                         /* Nothing is on the TCP port list.  Add this TCP socket to an
739                            empty list.  */
740                         socket_ptr -> nx_tcp_socket_bound_next =      socket_ptr;
741                         socket_ptr -> nx_tcp_socket_bound_previous =  socket_ptr;
742                         ip_ptr -> nx_ip_tcp_port_table[index] =       socket_ptr;
743                     }
744 
745                     /* Pickup the listen callback function.  */
746                     listen_callback = listen_ptr -> nx_tcp_listen_callback;
747 
748                     /* Release the incoming packet.  */
749                     _nx_packet_release(packet_ptr);
750 
751                     /* Determine if an accept call with suspension has already been made
752                        for this socket.  If so, the SYN message needs to be sent from
753                        here.  */
754                     if (socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_RECEIVED)
755                     {
756 
757 
758                         /* If trace is enabled, insert this event into the trace buffer.  */
759                         NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, socket_ptr -> nx_tcp_socket_state, NX_TRACE_INTERNAL_EVENTS, 0, 0);
760 
761 
762                         /* The application is suspended on an accept call for this socket.
763                            Simply send the SYN now and keep the thread suspended until the
764                            other side completes the connection.  */
765 
766                         /* Send the SYN message, but increment the ACK first.  */
767                         socket_ptr -> nx_tcp_socket_rx_sequence++;
768 
769                         /* Increment the sequence number for the SYN message.  */
770                         socket_ptr -> nx_tcp_socket_tx_sequence++;
771 
772                         /* Setup a timeout so the connection attempt can be sent again.  */
773                         socket_ptr -> nx_tcp_socket_timeout =          socket_ptr -> nx_tcp_socket_timeout_rate;
774                         socket_ptr -> nx_tcp_socket_timeout_retries =  0;
775 
776                         /* Send the SYN+ACK message.  */
777                         _nx_tcp_packet_send_syn(socket_ptr, (socket_ptr -> nx_tcp_socket_tx_sequence - 1));
778                     }
779 
780                     /* Determine if there is a listen callback function.  */
781                     if (listen_callback)
782                     {
783                         /* Call the user's listen callback function.  */
784                         (listen_callback)(socket_ptr, port);
785                     }
786                 }
787                 else
788                 {
789 
790                     /* There is no server socket available for the new connection.  */
791 
792                     /* The application needs to call relisten with a new server request to process this queued
793                        connection.  */
794 
795                     /* Check for a RST (reset) bit set.  */
796                     if (!(tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_RST_BIT))
797                     {
798 
799                         /* If trace is enabled, insert this event into the trace buffer.  */
800                         NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_SYN_RECEIVE, ip_ptr, NX_NULL, packet_ptr, tcp_header_ptr -> nx_tcp_sequence_number, NX_TRACE_INTERNAL_EVENTS, 0, 0);
801                     }
802 
803                     /* Check for the same connection request already in the queue.  */
804                     queued_count = listen_ptr -> nx_tcp_listen_queue_current;
805                     queued_ptr = listen_ptr -> nx_tcp_listen_queue_head;
806                     queued_prev_ptr = queued_ptr;
807 
808                     /* Initialize the check for queued request to false.*/
809                     is_a_RST_request = NX_FALSE;
810 
811                     /* Loop through the queued list in order to search for duplicate request.  */
812                     while (queued_count--)
813                     {
814 
815                         /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
816                         queued_source_port = (UINT)(*((ULONG *)queued_ptr -> nx_packet_prepend_ptr) >> NX_SHIFT_BY_16);
817 
818 #ifndef NX_DISABLE_IPV4
819                         /* Pickup the queued source port and source IP address for comparison.  */
820                         if (queued_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4)
821                         {
822 
823                             /*lint -e{929} -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
824                             queued_source_ip = (ULONG *)(((ULONG *)queued_ptr -> nx_packet_prepend_ptr) - 2);
825 
826                             /* Determine if this matches the current connection request.  */
827                             if ((*queued_source_ip == *source_ip) && (queued_source_port == source_port))
828                             {
829 
830                                 /* Possible duplicate connection request to one that is already queued.  */
831 
832                                 /* Check for a RST (reset) bit set.  */
833                                 if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_RST_BIT)
834                                 {
835 
836                                     /* RST packet matches a previously queued connection request. */
837                                     is_a_RST_request = NX_TRUE;
838                                 }
839                                 else
840                                 {
841 #ifndef NX_DISABLE_TCP_INFO
842                                     /* This is a duplicate connection request. Increment the TCP dropped packet count.  */
843                                     ip_ptr -> nx_ip_tcp_receive_packets_dropped++;
844 #endif
845                                     /* Simply release the packet and return.  */
846                                     _nx_packet_release(packet_ptr);
847 
848                                     /* Return!  */
849                                     return;
850                                 }
851                             }
852                         }
853 #endif /* !NX_DISABLE_IPV4  */
854 
855 #ifdef FEATURE_NX_IPV6
856                         if (queued_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6)
857                         {
858 
859                             /*lint -e{929} -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
860                             queued_source_ip = (ULONG *)(((ULONG *)queued_ptr -> nx_packet_prepend_ptr) - 8);
861 
862                             /* Determine if this matches the current connection request.  */
863                             if ((CHECK_IPV6_ADDRESSES_SAME(queued_source_ip, source_ip)) && (queued_source_port == source_port))
864                             {
865 
866                                 /* Possible duplicate connection request to one that is already queued.  */
867 
868                                 /* Check for a RST (reset) bit set.  */
869                                 if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_RST_BIT)
870                                 {
871 
872                                     /* RST packet matches a previously queued connection request. */
873                                     is_a_RST_request = NX_TRUE;
874                                 }
875                                 else
876                                 {
877 #ifndef NX_DISABLE_TCP_INFO
878                                     /* This is a duplicate connection request. Increment the TCP dropped packet count.  */
879                                     ip_ptr -> nx_ip_tcp_receive_packets_dropped++;
880 #endif
881                                     /* Simply release the packet and return.  */
882                                     _nx_packet_release(packet_ptr);
883 
884                                     /* Return!  */
885                                     return;
886                                 }
887                             }
888                         }
889 #endif /* FEATURE_NX_IPV6  */
890 
891                         /* Handle the case of the RST packet which cancels a previously received
892                            connection request. */
893                         if (is_a_RST_request)
894                         {
895 
896                             /* A previous connection request needs to be removed from the listen queue. */
897                             if (queued_ptr == listen_ptr -> nx_tcp_listen_queue_head)
898                             {
899 
900                                 /* Reset the front (oldest) of the queue to the next request. */
901                                 listen_ptr -> nx_tcp_listen_queue_head = queued_ptr -> nx_packet_queue_next;
902                             }
903                             else
904                             {
905 
906                                 /* Link around the request we are removing. */
907                                 /*lint -e{613} suppress possible use of null pointer, since 'queued_prev_ptr' must not be NULL.  */
908                                 queued_prev_ptr -> nx_packet_queue_next = queued_ptr -> nx_packet_queue_next;
909                             }
910 
911                             /* Is the request being removed the tail (most recent connection?)   */
912                             if (queued_ptr == listen_ptr -> nx_tcp_listen_queue_tail)
913                             {
914 
915                                 /* Yes, set the previous connection request as the tail. */
916                                 listen_ptr -> nx_tcp_listen_queue_tail = queued_prev_ptr;
917                             }
918 
919                             /* Release the connection request packet.  */
920                             _nx_packet_release(queued_ptr);
921 
922                             /* Update the listen queue. */
923                             listen_ptr -> nx_tcp_listen_queue_current--;
924 
925 #ifndef NX_DISABLE_TCP_INFO
926                             /* Increment the TCP dropped packet count.  */
927                             ip_ptr -> nx_ip_tcp_receive_packets_dropped++;
928 #endif
929 
930                             /* Simply release the packet and return.  */
931                             _nx_packet_release(packet_ptr);
932 
933                             /* Return!  */
934                             return;
935                         }
936 
937                         /* Move to next item in the queue.  */
938                         queued_prev_ptr = queued_ptr;
939                         queued_ptr = queued_ptr -> nx_packet_queue_next;
940                     }
941 
942                     /* Not a duplicate connection request, place this request on the listen queue.  */
943 
944                     /* Is this a RST packet? */
945                     if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_RST_BIT)
946                     {
947 
948                         /* Yes, so not a connection request. Do not place on the listen queue. */
949 #ifndef NX_DISABLE_TCP_INFO
950                         /* Increment the TCP dropped packet count.  */
951                         ip_ptr -> nx_ip_tcp_receive_packets_dropped++;
952 #endif
953 
954                         /* Release the packet.  */
955                         _nx_packet_release(packet_ptr);
956 
957                         /* Return!  */
958                         return;
959                     }
960 
961                     /* Set the next pointer of the packet to NULL.  */
962                     packet_ptr -> nx_packet_queue_next = NX_NULL;
963 
964                     /* Queue the new connection request.  */
965                     if (listen_ptr -> nx_tcp_listen_queue_head)
966                     {
967 
968                         /* There is a connection request already queued, just link packet to tail.  */
969                         (listen_ptr -> nx_tcp_listen_queue_tail) -> nx_packet_queue_next = packet_ptr;
970                     }
971                     else
972                     {
973 
974                         /* The queue is empty.  Setup head pointer to the new packet.  */
975                         listen_ptr -> nx_tcp_listen_queue_head = packet_ptr;
976                     }
977 
978                     /* Setup the tail pointer to the new packet and increment the queue count.  */
979                     listen_ptr -> nx_tcp_listen_queue_tail =  packet_ptr;
980                     listen_ptr -> nx_tcp_listen_queue_current++;
981 
982                     /* Add debug information. */
983                     NX_PACKET_DEBUG(NX_PACKET_TCP_LISTEN_QUEUE, __LINE__, packet_ptr);
984 
985                     /* Determine if the queue depth has been exceeded.  */
986                     if (listen_ptr -> nx_tcp_listen_queue_current > listen_ptr -> nx_tcp_listen_queue_maximum)
987                     {
988 
989 #ifndef NX_DISABLE_TCP_INFO
990 
991                         /* Increment the TCP connections dropped count.  */
992                         ip_ptr -> nx_ip_tcp_connections_dropped++;
993                         ip_ptr -> nx_ip_tcp_connections--;
994 
995                         /* Increment the TCP dropped packet count.  */
996                         ip_ptr -> nx_ip_tcp_receive_packets_dropped++;
997 #endif
998 
999                         /* Save the head packet pointer, since this will be released below.  */
1000                         packet_ptr = listen_ptr -> nx_tcp_listen_queue_head;
1001 
1002                         /* Remove the oldest packet from the queue.  */
1003                         listen_ptr -> nx_tcp_listen_queue_head = (listen_ptr -> nx_tcp_listen_queue_head) -> nx_packet_queue_next;
1004 
1005                         /* Decrement the number of packets in the queue.  */
1006                         listen_ptr -> nx_tcp_listen_queue_current--;
1007 
1008                         /* We have exceeded the number of connections that can be
1009                            queued for this port.  */
1010 
1011                         /* Release the packet.  */
1012                         _nx_packet_release(packet_ptr);
1013                     }
1014                 }
1015 
1016                 /* Finished processing, just return.  */
1017                 return;
1018             }
1019 
1020             /* Move to the next listen request.  */
1021             listen_ptr = listen_ptr -> nx_tcp_listen_next;
1022         } while (listen_ptr != ip_ptr -> nx_ip_tcp_active_listen_requests);
1023     }
1024 
1025 #ifndef NX_DISABLE_TCP_INFO
1026 
1027     /* Determine if a connection request is present.  */
1028     if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT)
1029     {
1030 
1031         /* Yes, increment the TCP connections dropped count.  */
1032         ip_ptr -> nx_ip_tcp_connections_dropped++;
1033     }
1034 
1035     /* Increment the TCP dropped packet count.  */
1036     ip_ptr -> nx_ip_tcp_receive_packets_dropped++;
1037 #endif /* NX_DISABLE_TCP_INFO  */
1038 
1039     /* Determine if a RST is present. If so, don't send a RST in response.  */
1040     if (!(tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_RST_BIT))
1041     {
1042 
1043         /* Non RST is present, send reset when no connection is present.  */
1044         _nx_tcp_no_connection_reset(ip_ptr, packet_ptr, tcp_header_ptr);
1045     }
1046 
1047     /* Not a connection request, just release the packet.  */
1048     _nx_packet_release(packet_ptr);
1049 
1050     return;
1051 }
1052 
1053