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