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 "tx_thread.h"
31 #include "nx_ip.h"
32 #ifdef FEATURE_NX_IPV6
33 #include "nx_ipv6.h"
34 #endif /* FEATURE_NX_IPV6 */
35 
36 #ifdef NX_ENABLE_TCPIP_OFFLOAD
37 /**************************************************************************/
38 /*                                                                        */
39 /*  FUNCTION                                               RELEASE        */
40 /*                                                                        */
41 /*    _nx_tcp_socket_driver_establish                     PORTABLE C      */
42 /*                                                           6.1.8        */
43 /*  AUTHOR                                                                */
44 /*                                                                        */
45 /*    Yuxin Zhou, Microsoft Corporation                                   */
46 /*                                                                        */
47 /*  DESCRIPTION                                                           */
48 /*                                                                        */
49 /*    This function is invoked when a TCP connection is established.      */
50 /*                                                                        */
51 /*  INPUT                                                                 */
52 /*                                                                        */
53 /*    socket_ptr                            Pointer to owning socket      */
54 /*    interface_ptr                         Pointer to IP interface       */
55 /*    remote_port                           Pointer to remote UDP port    */
56 /*                                                                        */
57 /*  OUTPUT                                                                */
58 /*                                                                        */
59 /*    Status                                                              */
60 /*                                                                        */
61 /*  CALLS                                                                 */
62 /*                                                                        */
63 /*    tx_mutex_get                          Obtain protection mutex       */
64 /*    tx_mutex_put                          Release protection mutex      */
65 /*    _nx_ip_packet_deferred_receive        Defer IP packet receive       */
66 /*                                                                        */
67 /*  CALLED BY                                                             */
68 /*                                                                        */
69 /*    Driver                                                              */
70 /*                                                                        */
71 /*  RELEASE HISTORY                                                       */
72 /*                                                                        */
73 /*    DATE              NAME                      DESCRIPTION             */
74 /*                                                                        */
75 /*  08-02-2021     Yuxin Zhou               Initial Version 6.1.8         */
76 /*                                                                        */
77 /**************************************************************************/
_nx_tcp_socket_driver_establish(NX_TCP_SOCKET * socket_ptr,NX_INTERFACE * interface_ptr,UINT remote_port)78 UINT _nx_tcp_socket_driver_establish(NX_TCP_SOCKET *socket_ptr, NX_INTERFACE *interface_ptr, UINT remote_port)
79 {
80 NX_IP *ip_ptr;
81 NXD_ADDRESS ip_address;
82 UINT status;
83 UINT index;
84 UINT port;
85 struct NX_TCP_LISTEN_STRUCT *listen_ptr;
86 
87     /* Setup the IP pointer.  */
88     ip_ptr =  socket_ptr -> nx_tcp_socket_ip_ptr;
89 
90     /* Obtain the IP internal mutex before processing the IP event.  */
91     tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
92 
93     /* Check socket state first.  */
94     if ((socket_ptr -> nx_tcp_socket_state != NX_TCP_SYN_SENT) &&
95         (socket_ptr -> nx_tcp_socket_state != NX_TCP_LISTEN_STATE)&&
96         (socket_ptr -> nx_tcp_socket_state != NX_TCP_SYN_RECEIVED))
97     {
98 
99         /* Just ignore socket not in connecting state.  */
100         /* Release the IP internal mutex.  */
101         tx_mutex_put(&(ip_ptr -> nx_ip_protection));
102         return(NX_NOT_SUCCESSFUL);
103     }
104 
105     if (socket_ptr -> nx_tcp_socket_client_type == NX_FALSE)
106     {
107         if (socket_ptr -> nx_tcp_socket_bound_next)
108         {
109 
110             /* TCP socket is connecting on other interface.  */
111             /* Release the IP internal mutex.  */
112             tx_mutex_put(&(ip_ptr -> nx_ip_protection));
113             return(NX_NOT_SUCCESSFUL);
114         }
115 
116         /* For TCP server socket, the connection is not established yet.  */
117         port = socket_ptr -> nx_tcp_socket_port;
118         status = interface_ptr -> nx_interface_tcpip_offload_handler(ip_ptr, interface_ptr, socket_ptr,
119                                                                      NX_TCPIP_OFFLOAD_TCP_SERVER_SOCKET_ACCEPT,
120                                                                      NX_NULL, NX_NULL, &ip_address, port,
121                                                                      &remote_port, NX_NO_WAIT);
122 
123         if (status)
124         {
125 
126             /* This should not happen as a connection is pendding. */
127             /* Release the IP internal mutex.  */
128             tx_mutex_put(&(ip_ptr -> nx_ip_protection));
129             return(NX_TCPIP_OFFLOAD_ERROR);
130         }
131 
132         /* Setup connection parameters.  */
133         socket_ptr -> nx_tcp_socket_connect_interface = interface_ptr;
134 
135         /* Save the server port and server IP address.  */
136         socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version = ip_address.nxd_ip_version;
137 #ifndef NX_DISABLE_IPV4
138         if (ip_address.nxd_ip_version == NX_IP_VERSION_V4)
139         {
140             socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_address.v4 = ip_address.nxd_ip_address.v4;
141             socket_ptr -> nx_tcp_socket_mss =
142                 (ULONG)((interface_ptr -> nx_interface_ip_mtu_size - sizeof(NX_IPV4_HEADER)) - sizeof(NX_TCP_HEADER));
143         }
144 #endif /* !NX_DISABLE_IPV4  */
145 
146 #ifdef FEATURE_NX_IPV6
147         if (ip_address.nxd_ip_version == NX_IP_VERSION_V6)
148         {
149             COPY_IPV6_ADDRESS(ip_address.nxd_ip_address.v6,
150                               socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_address.v6);
151             socket_ptr -> nx_tcp_socket_mss =
152                 (ULONG)((interface_ptr -> nx_interface_ip_mtu_size - sizeof(NX_IPV6_HEADER)) - sizeof(NX_TCP_HEADER));
153         }
154 #endif /* FEATURE_NX_IPV6 */
155 
156         socket_ptr -> nx_tcp_socket_connect_port = remote_port;
157 
158         /* Find listen callback function.  */
159         listen_ptr =  ip_ptr -> nx_ip_tcp_active_listen_requests;
160         if (listen_ptr)
161         {
162             do
163             {
164                 if (listen_ptr -> nx_tcp_listen_port == port)
165                 {
166                     if (listen_ptr -> nx_tcp_listen_callback)
167                     {
168 
169                         /* Clear the server socket pointer in the listen request.  If the
170                            application wishes to honor more server connections on this port,
171                            the application must call relisten with a new server socket
172                            pointer.  */
173                         listen_ptr->nx_tcp_listen_socket_ptr = NX_NULL;
174 
175                         /* Call the user's listen callback function.  */
176                         (listen_ptr ->nx_tcp_listen_callback)(socket_ptr, listen_ptr -> nx_tcp_listen_port);
177                         break;
178                     }
179                 }
180 
181                 /* Move to the next listen request.  */
182                 listen_ptr =  listen_ptr -> nx_tcp_listen_next;
183             } while (listen_ptr != ip_ptr -> nx_ip_tcp_active_listen_requests);
184         }
185 
186         /* Calculate the hash index in the TCP port array of the associated IP instance.  */
187         index = (UINT)((port + (port >> 8)) & NX_TCP_PORT_TABLE_MASK);
188 
189         /* Determine if the list is NULL.  */
190         if (ip_ptr -> nx_ip_tcp_port_table[index])
191         {
192 
193             /* There are already sockets on this list... just add this one
194                 to the end.  */
195             socket_ptr -> nx_tcp_socket_bound_next =
196                 ip_ptr -> nx_ip_tcp_port_table[index];
197             socket_ptr -> nx_tcp_socket_bound_previous =
198                 (ip_ptr -> nx_ip_tcp_port_table[index]) -> nx_tcp_socket_bound_previous;
199             ((ip_ptr -> nx_ip_tcp_port_table[index]) -> nx_tcp_socket_bound_previous) -> nx_tcp_socket_bound_next =
200                 socket_ptr;
201             (ip_ptr -> nx_ip_tcp_port_table[index]) -> nx_tcp_socket_bound_previous = socket_ptr;
202         }
203         else
204         {
205 
206             /* Nothing is on the TCP port list.  Add this TCP socket to an
207                 empty list.  */
208             socket_ptr -> nx_tcp_socket_bound_next =      socket_ptr;
209             socket_ptr -> nx_tcp_socket_bound_previous =  socket_ptr;
210             ip_ptr -> nx_ip_tcp_port_table[index] =       socket_ptr;
211         }
212     }
213 
214     /* Update socket state.  */
215     socket_ptr -> nx_tcp_socket_state =  NX_TCP_ESTABLISHED;
216 
217 #ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT
218 
219     /* Is a connection completion callback registered with the TCP socket?  */
220     if (socket_ptr -> nx_tcp_establish_notify)
221     {
222 
223         /* Call the application's establish callback function.    */
224         (socket_ptr -> nx_tcp_establish_notify)(socket_ptr);
225     }
226 #endif
227 
228     /* Determine if we need to wake a thread suspended on the connection.  */
229     if (socket_ptr -> nx_tcp_socket_connect_suspended_thread)
230     {
231 
232         /* Resume the suspended thread.  */
233         _nx_tcp_socket_thread_resume(&(socket_ptr -> nx_tcp_socket_connect_suspended_thread), NX_SUCCESS);
234     }
235 
236     /* Release the IP internal mutex.  */
237     tx_mutex_put(&(ip_ptr -> nx_ip_protection));
238 
239     return(NX_SUCCESS);
240 }
241 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
242 
243