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_ip.h"
31 #ifdef FEATURE_NX_IPV6
32 #include "nx_ipv6.h"
33 #endif /* FEATURE_NX_IPV6 */
34 #ifdef NX_IPSEC_ENABLE
35 #include "nx_ipsec.h"
36 #endif /* NX_IPSEC_ENABLE */
37
38
39 /**************************************************************************/
40 /* */
41 /* FUNCTION RELEASE */
42 /* */
43 /* _nx_tcp_packet_send_syn PORTABLE C */
44 /* 6.1 */
45 /* AUTHOR */
46 /* */
47 /* Yuxin Zhou, Microsoft Corporation */
48 /* */
49 /* DESCRIPTION */
50 /* */
51 /* This function sends a SYN from the specified socket. */
52 /* */
53 /* INPUT */
54 /* */
55 /* socket_ptr Pointer to socket */
56 /* tx_sequence Transmit sequence number */
57 /* */
58 /* OUTPUT */
59 /* */
60 /* None */
61 /* */
62 /* CALLS */
63 /* */
64 /* _nx_tcp_packet_send_control Send TCP control packet */
65 /* _nx_packet_egress_sa_lookup IPsec process */
66 /* */
67 /* CALLED BY */
68 /* */
69 /* _nx_tcp_client_socket_connect Client connect processing */
70 /* _nx_tcp_periodic_processing Connection retry processing */
71 /* _nx_tcp_packet_process Server connect response */
72 /* processing */
73 /* _nx_tcp_server_socket_accept Server socket accept */
74 /* processing */
75 /* _nx_tcp_socket_state_syn_sent Socket SYN sent processing */
76 /* */
77 /* RELEASE HISTORY */
78 /* */
79 /* DATE NAME DESCRIPTION */
80 /* */
81 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
82 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
83 /* resulting in version 6.1 */
84 /* */
85 /**************************************************************************/
_nx_tcp_packet_send_syn(NX_TCP_SOCKET * socket_ptr,ULONG tx_sequence)86 VOID _nx_tcp_packet_send_syn(NX_TCP_SOCKET *socket_ptr, ULONG tx_sequence)
87 {
88
89 #ifdef NX_IPSEC_ENABLE
90 ULONG data_offset = 0;
91 NXD_ADDRESS src_addr;
92 UINT ret;
93 NX_IPSEC_SA *cur_sa_ptr = NX_NULL;
94 #endif /* NX_IPSEC_ENABLE */
95 ULONG option_word_1;
96 ULONG option_word_2;
97 #ifdef NX_ENABLE_TCP_WINDOW_SCALING
98 UINT include_window_scaling = NX_FALSE;
99 UINT scale_factor;
100 #endif /* NX_ENABLE_TCP_WINDOW_SCALING */
101 ULONG mss = 0;
102
103 #ifdef NX_IPSEC_ENABLE
104 #ifndef NX_DISABLE_IPV4
105 /* Look for egress SA first. */
106 if (socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V4)
107 {
108 src_addr.nxd_ip_version = NX_IP_VERSION_V4;
109 src_addr.nxd_ip_address.v4 = socket_ptr -> nx_tcp_socket_connect_interface -> nx_interface_ip_address;
110 }
111 #endif /* !NX_DISABLE_IPV4 */
112
113 #ifdef FEATURE_NX_IPV6
114 if (socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6)
115 {
116 /* IPv6 case. */
117 src_addr.nxd_ip_version = NX_IP_VERSION_V6;
118 COPY_IPV6_ADDRESS(socket_ptr -> nx_tcp_socket_ipv6_addr -> nxd_ipv6_address, src_addr.nxd_ip_address.v6);
119 }
120 #endif /* FEATURE_NX_IPV6 */
121
122 /* Check for possible SA match. */
123 if (socket_ptr -> nx_tcp_socket_ip_ptr -> nx_ip_packet_egress_sa_lookup != NX_NULL) /* IPsec is enabled. */
124 {
125
126 /* If the SA has not been set. */
127 ret = socket_ptr -> nx_tcp_socket_ip_ptr -> nx_ip_packet_egress_sa_lookup(socket_ptr -> nx_tcp_socket_ip_ptr, /* IP ptr */
128 &src_addr, /* src_addr */
129 &socket_ptr -> nx_tcp_socket_connect_ip, /* dest_addr */
130 NX_PROTOCOL_TCP, /* protocol */
131 socket_ptr -> nx_tcp_socket_port, /* src_port */
132 socket_ptr -> nx_tcp_socket_connect_port, /* dest_port */
133 &data_offset, (VOID *)&cur_sa_ptr, 0);
134 if (ret == NX_IPSEC_TRAFFIC_PROTECT)
135 {
136
137 /* Save the SA to the socket. */
138 socket_ptr -> nx_tcp_socket_egress_sa = cur_sa_ptr;
139 socket_ptr -> nx_tcp_socket_egress_sa_data_offset = data_offset;
140 }
141 else if (ret == NX_IPSEC_TRAFFIC_DROP || ret == NX_IPSEC_TRAFFIC_PENDING_IKEV2)
142 {
143
144 return;
145 }
146 else
147 {
148
149 /* Zero out SA information. */
150 socket_ptr -> nx_tcp_socket_egress_sa = NX_NULL;
151 socket_ptr -> nx_tcp_socket_egress_sa_data_offset = 0;
152 }
153 }
154 else
155 {
156 socket_ptr -> nx_tcp_socket_egress_sa = NX_NULL;
157 }
158 #endif /* NX_IPSEC_ENABLE */
159
160 #ifndef NX_DISABLE_IPV4
161 /* Update the mss value based on IP version type. */
162 if (socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V4)
163 {
164 mss = (ULONG)((socket_ptr -> nx_tcp_socket_connect_interface -> nx_interface_ip_mtu_size - sizeof(NX_IPV4_HEADER)) - sizeof(NX_TCP_HEADER));
165
166 #ifdef NX_IPSEC_ENABLE
167 if (cur_sa_ptr != NX_NULL)
168 {
169
170 /* Update the mss value based on sa mode. */
171 if (cur_sa_ptr -> nx_ipsec_sa_protocol == NX_PROTOCOL_NEXT_HEADER_ENCAP_SECURITY)
172 {
173
174 /* Update the mss value. minus the ESP HEADER's pad length and IV size , */
175 mss = mss - sizeof(NX_IPSEC_ESP_HEADER) -
176 (cur_sa_ptr -> nx_ipsec_sa_encryption_method -> nx_crypto_block_size_in_bytes) -
177 ((cur_sa_ptr -> nx_ipsec_sa_encryption_method -> nx_crypto_IV_size_in_bits) >> 3) -
178 ((cur_sa_ptr -> nx_ipsec_sa_integrity_method -> nx_crypto_ICV_size_in_bits) >> 3);
179 }
180
181 if (cur_sa_ptr -> nx_ipsec_sa_protocol == NX_PROTOCOL_NEXT_HEADER_AUTHENTICATION)
182 {
183
184 /* Update the mss value. minus the ESP HEADER's IV size and ICV size. */
185 mss = mss - sizeof(NX_IPSEC_AUTHENTICATION_HEADER) -
186 (cur_sa_ptr -> nx_ipsec_sa_integrity_method -> nx_crypto_IV_size_in_bits >> 3) -
187 (cur_sa_ptr -> nx_ipsec_sa_integrity_method -> nx_crypto_ICV_size_in_bits >> 3);
188 }
189
190 /* If the sa is tunnel mode, the mss value should minus the IPV4 header size . */
191 if (cur_sa_ptr -> nx_ipsec_sa_mode == NX_IPSEC_TUNNEL_MODE)
192 {
193 mss -= (sizeof(NX_IPV4_HEADER));
194 }
195 }
196 #endif /* NX_IPSEC_ENABLE */
197
198 }
199 #endif /* !NX_DISABLE_IPV4 */
200
201 #ifdef FEATURE_NX_IPV6
202 if (socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6)
203 {
204 mss = (ULONG)((socket_ptr -> nx_tcp_socket_connect_interface -> nx_interface_ip_mtu_size - sizeof(NX_IPV6_HEADER)) - sizeof(NX_TCP_HEADER));
205
206 #ifdef NX_IPSEC_ENABLE
207 if (cur_sa_ptr != NX_NULL)
208 {
209
210 /* Update the mss value based on sa mode. */
211 if (cur_sa_ptr -> nx_ipsec_sa_protocol == NX_PROTOCOL_NEXT_HEADER_ENCAP_SECURITY)
212 {
213
214 /* Update the mss value. minus the ESP header's pad length and IV size , */
215 mss = mss - sizeof(NX_IPSEC_ESP_HEADER) -
216 (cur_sa_ptr -> nx_ipsec_sa_encryption_method -> nx_crypto_block_size_in_bytes) -
217 ((cur_sa_ptr -> nx_ipsec_sa_encryption_method -> nx_crypto_IV_size_in_bits) >> 3) -
218 ((cur_sa_ptr -> nx_ipsec_sa_integrity_method -> nx_crypto_ICV_size_in_bits) >> 3);
219 }
220
221 if (cur_sa_ptr -> nx_ipsec_sa_protocol == NX_PROTOCOL_NEXT_HEADER_AUTHENTICATION)
222 {
223
224 /* Update the mss value. minus the ESP HEADER's IV size and ICV size. */
225 mss = mss - sizeof(NX_IPSEC_AUTHENTICATION_HEADER) -
226 (cur_sa_ptr -> nx_ipsec_sa_integrity_method -> nx_crypto_IV_size_in_bits >> 3) -
227 (cur_sa_ptr -> nx_ipsec_sa_integrity_method -> nx_crypto_ICV_size_in_bits >> 3);
228 }
229
230 /* If the sa mode is tunnel mode,the mss value should minus the IPV6 header size . */
231 if (cur_sa_ptr -> nx_ipsec_sa_mode == NX_IPSEC_TUNNEL_MODE)
232 {
233 mss -= (sizeof(NX_IPV6_HEADER));
234 }
235 }
236 #endif /* NX_IPSEC_ENABLE */
237 }
238 #endif /* FEATURE_NX_IPV6 */
239
240 mss &= 0x0000FFFFUL;
241
242 if ((socket_ptr -> nx_tcp_socket_mss < mss) && socket_ptr -> nx_tcp_socket_mss)
243 {
244
245 /* Use the custom MSS. */
246 mss = socket_ptr -> nx_tcp_socket_mss;
247 }
248
249 if (socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_RECEIVED)
250 {
251
252 /* Update the connect MSS for TCP server socket. */
253 if (mss < socket_ptr -> nx_tcp_socket_peer_mss)
254 {
255 socket_ptr -> nx_tcp_socket_connect_mss = mss;
256 }
257 else
258 {
259 socket_ptr -> nx_tcp_socket_connect_mss = socket_ptr -> nx_tcp_socket_peer_mss;
260 }
261
262 /* Compute the SMSS * SMSS value, so later TCP module doesn't need to redo the multiplication. */
263 socket_ptr -> nx_tcp_socket_connect_mss2 =
264 socket_ptr -> nx_tcp_socket_connect_mss * socket_ptr -> nx_tcp_socket_connect_mss;
265 }
266 else
267 {
268
269 /* Set the MSS. */
270 socket_ptr -> nx_tcp_socket_connect_mss = mss;
271 }
272
273 /* Build the MSS option. */
274 option_word_1 = NX_TCP_MSS_OPTION | mss;
275
276 /* Set default option word2. */
277 option_word_2 = NX_TCP_OPTION_END;
278
279 #ifdef NX_ENABLE_TCP_WINDOW_SCALING
280 /* Include window scaling option if we initiates the SYN, or the peer supports Window Scaling. */
281 if (socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_SENT)
282 {
283 include_window_scaling = NX_TRUE;
284 }
285 else if (socket_ptr -> nx_tcp_snd_win_scale_value != 0xFF)
286 {
287 include_window_scaling = NX_TRUE;
288 }
289
290 if (include_window_scaling)
291 {
292
293 /* Sets the window scaling option. */
294 option_word_2 = NX_TCP_RWIN_OPTION;
295
296 /* Compute the window scaling factor */
297 for (scale_factor = 0; scale_factor < 15; scale_factor++)
298 {
299
300 if ((socket_ptr -> nx_tcp_socket_rx_window_current >> scale_factor) < 65536)
301 {
302 break;
303 }
304 }
305
306 /* Make sure window scale is limited to 14, per RFC 1323 pp.11. */
307 if (scale_factor == 15)
308 {
309 scale_factor = 14;
310 socket_ptr -> nx_tcp_socket_rx_window_default = (1 << 30) - 1;
311 socket_ptr -> nx_tcp_socket_rx_window_current = (1 << 30) - 1;
312 }
313
314 option_word_2 |= scale_factor << 8;
315
316 /* Update the socket with the scale factor. */
317 socket_ptr -> nx_tcp_rcv_win_scale_value = scale_factor;
318 }
319 #endif /* NX_ENABLE_TCP_WINDOW_SCALING */
320
321 /* Send SYN or SYN+ACK packet according to socket state. */
322 if (socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_SENT)
323 {
324 _nx_tcp_packet_send_control(socket_ptr, NX_TCP_SYN_BIT, tx_sequence,
325 0, option_word_1, option_word_2, NX_NULL);
326 }
327 else
328 {
329 _nx_tcp_packet_send_control(socket_ptr, (NX_TCP_SYN_BIT | NX_TCP_ACK_BIT), tx_sequence,
330 socket_ptr -> nx_tcp_socket_rx_sequence, option_word_1, option_word_2, NX_NULL);
331 }
332
333 /* Initialize recover sequence and previous cumulative acknowledgment. */
334 socket_ptr -> nx_tcp_socket_tx_sequence_recover = tx_sequence;
335 socket_ptr -> nx_tcp_socket_previous_highest_ack = tx_sequence;
336 }
337
338