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