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_ip.h"
29 #include "nx_tcp.h"
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _nx_tcp_socket_create PORTABLE C */
36 /* 6.4.0 */
37 /* AUTHOR */
38 /* */
39 /* Yuxin Zhou, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function creates a TCP socket for the specified IP instance. */
44 /* Both client and server sockets are created by this service. */
45 /* */
46 /* INPUT */
47 /* */
48 /* ip_ptr IP instance pointer */
49 /* socket_ptr Pointer to new TCP socket */
50 /* name Name of new TCP socket */
51 /* type_of_service Type of service for this TCP */
52 /* socket */
53 /* fragment Flag to enable IP fragmenting */
54 /* time_to_live Time to live value for socket */
55 /* window_size Size of socket's receive */
56 /* window */
57 /* tcp_urgent_data_callback Routine to call when urgent */
58 /* data is received */
59 /* tcp_disconnect_callback Routine to call when a */
60 /* disconnect occurs */
61 /* */
62 /* OUTPUT */
63 /* */
64 /* status Completion status */
65 /* */
66 /* CALLS */
67 /* */
68 /* tx_mutex_get Obtain protection */
69 /* tx_mutex_put Release protection */
70 /* */
71 /* CALLED BY */
72 /* */
73 /* Application Code */
74 /* */
75 /* RELEASE HISTORY */
76 /* */
77 /* DATE NAME DESCRIPTION */
78 /* */
79 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
80 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
81 /* resulting in version 6.1 */
82 /* 12-31-2023 Yajun Xia Modified comment(s), */
83 /* supported VLAN, */
84 /* resulting in version 6.4.0 */
85 /* */
86 /**************************************************************************/
_nx_tcp_socket_create(NX_IP * ip_ptr,NX_TCP_SOCKET * socket_ptr,CHAR * name,ULONG type_of_service,ULONG fragment,UINT time_to_live,ULONG window_size,VOID (* tcp_urgent_data_callback)(NX_TCP_SOCKET * socket_ptr),VOID (* tcp_disconnect_callback)(NX_TCP_SOCKET * socket_ptr))87 UINT _nx_tcp_socket_create(NX_IP *ip_ptr, NX_TCP_SOCKET *socket_ptr, CHAR *name,
88 ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG window_size,
89 VOID (*tcp_urgent_data_callback)(NX_TCP_SOCKET *socket_ptr),
90 VOID (*tcp_disconnect_callback)(NX_TCP_SOCKET *socket_ptr))
91 {
92 TX_INTERRUPT_SAVE_AREA
93
94 NX_TCP_SOCKET *tail_ptr;
95
96
97 /* Initialize the TCP control block to zero. */
98 memset((void *)socket_ptr, 0, sizeof(NX_TCP_SOCKET));
99
100 /* Fill in the basic information in the new TCP socket structure. */
101
102 /* Remember the associated IP structure. */
103 socket_ptr -> nx_tcp_socket_ip_ptr = ip_ptr;
104
105 /* By default, indicate the socket is a client socket. */
106 socket_ptr -> nx_tcp_socket_client_type = NX_TRUE;
107
108 /* Save the TCP socket's name. */
109 socket_ptr -> nx_tcp_socket_name = name;
110
111 /* Setup the counter for duplicated ACK packet. */
112 socket_ptr -> nx_tcp_socket_duplicated_ack_received = 0;
113
114 /* Setup this socket's maximum segment size (mss). */
115 socket_ptr -> nx_tcp_socket_mss = 0;
116
117 /* Setup the default receiver's maximum segment size. */
118 socket_ptr -> nx_tcp_socket_connect_mss = NX_TCP_MSS_SIZE;
119
120 /* Save the type of service input parameter. */
121 socket_ptr -> nx_tcp_socket_type_of_service = type_of_service;
122
123 /* Save the fragment input parameter. */
124 socket_ptr -> nx_tcp_socket_fragment_enable = fragment & NX_DONT_FRAGMENT;
125
126 /* Save the time-to-live input parameter. */
127 socket_ptr -> nx_tcp_socket_time_to_live = time_to_live;
128
129 /* Clear the socket bind in progress flag. */
130 socket_ptr -> nx_tcp_socket_bind_in_progress = NX_FALSE;
131
132 /* Setup the delayed ACK timeout periodic rate. */
133 socket_ptr -> nx_tcp_socket_delayed_ack_timeout = _nx_tcp_ack_timer_rate;
134
135 /* Setup the default transmit timeout. */
136 socket_ptr -> nx_tcp_socket_timeout_rate = _nx_tcp_transmit_timer_rate;
137 socket_ptr -> nx_tcp_socket_timeout_max_retries = NX_TCP_MAXIMUM_RETRIES;
138 socket_ptr -> nx_tcp_socket_timeout_shift = NX_TCP_RETRY_SHIFT;
139
140 /* Setup the default maximum transmit queue depth. */
141 socket_ptr -> nx_tcp_socket_transmit_queue_maximum_default = NX_TCP_MAXIMUM_TX_QUEUE;
142 socket_ptr -> nx_tcp_socket_transmit_queue_maximum = NX_TCP_MAXIMUM_TX_QUEUE;
143
144 #ifdef NX_ENABLE_LOW_WATERMARK
145 /* Setup the default maximum receive queue depth. */
146 socket_ptr -> nx_tcp_socket_receive_queue_maximum = NX_TCP_MAXIMUM_RX_QUEUE;
147 #endif /* NX_ENABLE_LOW_WATERMARK */
148
149 #ifdef NX_ENABLE_TCP_WINDOW_SCALING
150
151 /* Window scaling feature is enabled. Record this user-specified window size. */
152 socket_ptr -> nx_tcp_socket_rx_window_maximum = window_size;
153 #endif /* NX_ENABLE_TCP_WINDOW_SCALING */
154
155 /* Setup the sliding window information. */
156 socket_ptr -> nx_tcp_socket_rx_window_default = window_size;
157 socket_ptr -> nx_tcp_socket_rx_window_current = window_size;
158 socket_ptr -> nx_tcp_socket_tx_outstanding_bytes = 0;
159 socket_ptr -> nx_tcp_socket_tx_window_advertised = 0;
160 socket_ptr -> nx_tcp_socket_tx_window_congestion = 0;
161
162
163 /* Initialize the ack_n_packet counter. */
164 socket_ptr -> nx_tcp_socket_ack_n_packet_counter = 1;
165
166 /* Save the application callback routines. */
167 socket_ptr -> nx_tcp_urgent_data_callback = tcp_urgent_data_callback;
168 socket_ptr -> nx_tcp_disconnect_callback = tcp_disconnect_callback;
169
170 /* Clear the receive notify function pointer. */
171 socket_ptr -> nx_tcp_receive_callback = NX_NULL;
172
173 #ifdef NX_ENABLE_TCP_KEEPALIVE
174 /* If the Keep alive feature is enabled in NetX, enable it
175 on all TCP sockets. */
176 socket_ptr -> nx_tcp_socket_keepalive_enabled = NX_TRUE;
177
178 #endif
179
180 /* If trace is enabled, insert this event into the trace buffer. */
181 NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSED, NX_TRACE_INTERNAL_EVENTS, 0, 0);
182
183 /* Setup the initial TCP socket state. */
184 socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED;
185
186 #ifdef NX_ENABLE_VLAN
187 /* Initialize the tcp socket vlan priority. */
188 socket_ptr -> nx_tcp_socket_vlan_priority = NX_VLAN_PRIORITY_INVALID;
189 #endif /* NX_ENABLE_VLAN */
190
191 /* If trace is enabled, register this object. */
192 NX_TRACE_OBJECT_REGISTER(NX_TRACE_OBJECT_TYPE_TCP_SOCKET, socket_ptr, name, type_of_service, window_size);
193
194 /* If trace is enabled, insert this event into the trace buffer. */
195 NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SOCKET_CREATE, ip_ptr, socket_ptr, type_of_service, window_size, NX_TRACE_TCP_EVENTS, 0, 0);
196
197 /* Get protection while we insert the TCP socket into the created list. */
198 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
199
200 /* Disable interrupts while we link the new TCP socket to the IP structure. */
201 TX_DISABLE
202
203 /* Load the TCP ID field in the TCP control block. */
204 socket_ptr -> nx_tcp_socket_id = NX_TCP_ID;
205
206 /* Place the new TCP control block on the list of created TCP sockets for this IP. First,
207 check for an empty list. */
208 if (ip_ptr -> nx_ip_tcp_created_sockets_ptr)
209 {
210
211 /* Pickup tail pointer. */
212 tail_ptr = (ip_ptr -> nx_ip_tcp_created_sockets_ptr) -> nx_tcp_socket_created_previous;
213
214 /* Place the new TCP socket control block in the list. */
215 (ip_ptr -> nx_ip_tcp_created_sockets_ptr) -> nx_tcp_socket_created_previous = socket_ptr;
216 tail_ptr -> nx_tcp_socket_created_next = socket_ptr;
217
218 /* Setup this TCP socket's created links. */
219 socket_ptr -> nx_tcp_socket_created_previous = tail_ptr;
220 socket_ptr -> nx_tcp_socket_created_next = ip_ptr -> nx_ip_tcp_created_sockets_ptr;
221 }
222 else
223 {
224
225 /* The created TCP socket list is empty. Add TCP socket control block to empty list. */
226 ip_ptr -> nx_ip_tcp_created_sockets_ptr = socket_ptr;
227 socket_ptr -> nx_tcp_socket_created_previous = socket_ptr;
228 socket_ptr -> nx_tcp_socket_created_next = socket_ptr;
229 }
230
231 /* Increment the created TCP socket counter. */
232 ip_ptr -> nx_ip_tcp_created_sockets_count++;
233
234 #ifdef FEATURE_NX_IPV6
235 socket_ptr -> nx_tcp_socket_ipv6_addr = NX_NULL;
236 #endif /* FEATURE_NX_IPV6 */
237
238
239 #ifdef NX_IPSEC_ENABLE
240 socket_ptr -> nx_tcp_socket_egress_sa = NX_NULL;
241 socket_ptr -> nx_tcp_socket_egress_sa_data_offset = 0;
242 #endif /* NX_IPSEC_ENABLE */
243 /* Restore previous interrupt posture. */
244 TX_RESTORE
245
246 /* Release protection. */
247 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
248
249 /* Return successful completion. */
250 return(NX_SUCCESS);
251 }
252
253