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