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 /**   Packet Pool Mangement (Packet)                                      */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define NX_SOURCE_CODE
23 
24 
25 /* Include necessary system files.  */
26 #include "nx_api.h"
27 #include "nx_ip.h"
28 
29 #ifdef NX_IPSEC_ENABLE
30 #include "nx_ipsec.h"
31 #include "nx_icmp.h"
32 #endif /* NX_IPSEC_ENABLE */
33 
34 #ifdef FEATURE_NX_IPV6
35 #include "nx_ipv6.h"
36 #endif /* FEATURE_NX_IPV6  */
37 
38 
39 /**************************************************************************/
40 /*                                                                        */
41 /*  FUNCTION                                               RELEASE        */
42 /*                                                                        */
43 /*    _nx_ip_max_payload_size_find                        PORTABLE C      */
44 /*                                                           6.1          */
45 /*  AUTHOR                                                                */
46 /*                                                                        */
47 /*    Yuxin Zhou, Microsoft Corporation                                   */
48 /*                                                                        */
49 /*  DESCRIPTION                                                           */
50 /*                                                                        */
51 /*    This function finds the maximum payload size at application level   */
52 /*    that would not cause IPv4 or IPv6 fragmentation.  It takes the      */
53 /*    layer 4 protocol (TCP vs. UDP), layer 3 protocol (IPv4 vs. IPv6)    */
54 /*    and IPsec into consideration, and reports back to values:           */
55 /*    (1) start_offset_ptr: This is the location where enough space       */
56 /*        for protocol header is reserved for TCP/UDP/IP/IPsec headers;   */
57 /*    (2) payload_length_ptr: the amount of data application may          */
58 /*        transfer without exceeding MTU.                                 */
59 /*                                                                        */
60 /*  INPUT                                                                 */
61 /*                                                                        */
62 /*    ip_ptr                                Pointer to IP instance        */
63 /*    dest_address                          Packet Destination Address    */
64 /*    if_index                              Interface index for ipv4,     */
65 /*                                          address index for ipv6.       */
66 /*    src_port                              Source port number, in host   */
67 /*                                            byte order.                 */
68 /*    dest_port                             Destination port number,      */
69 /*                                            in host byte order.         */
70 /*    protocol                              Protocol type                 */
71 /*    start_offset_ptr                      Pointer to the start of data  */
72 /*                                            for maximum packet payload. */
73 /*    payload_length_ptr                    Pointer to the computed       */
74 /*                                            payload size that would not */
75 /*                                            cause IP fragmentation.     */
76 /*                                                                        */
77 /*  OUTPUT                                                                */
78 /*                                                                        */
79 /*    status                                Completion Code.              */
80 /*                                                                        */
81 /*  CALLS                                                                 */
82 /*                                                                        */
83 /*    _nx_ipsec_sa_egress_lookup            The acutal function that      */
84 /*                                            performs the SA lookup      */
85 /*                                            (if IPsec is enable)        */
86 /*                                                                        */
87 /*  CALLED BY                                                             */
88 /*                                                                        */
89 /*    Application                                                         */
90 /*                                                                        */
91 /*  RELEASE HISTORY                                                       */
92 /*                                                                        */
93 /*    DATE              NAME                      DESCRIPTION             */
94 /*                                                                        */
95 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
96 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
97 /*                                            resulting in version 6.1    */
98 /*                                                                        */
99 /**************************************************************************/
_nx_ip_max_payload_size_find(NX_IP * ip_ptr,NXD_ADDRESS * dest_address,UINT if_index,UINT src_port,UINT dest_port,ULONG protocol,ULONG * start_offset_ptr,ULONG * payload_length_ptr)100 UINT _nx_ip_max_payload_size_find(NX_IP *ip_ptr,
101                                   NXD_ADDRESS *dest_address,
102                                   UINT if_index,
103                                   UINT src_port,
104                                   UINT dest_port,
105                                   ULONG protocol,
106                                   ULONG *start_offset_ptr,
107                                   ULONG *payload_length_ptr)
108 
109 {
110 
111 ULONG        payload_length = 0;
112 ULONG        start_offset = 0;
113 
114 #if defined(NX_IPSEC_ENABLE) || defined(TX_ENABLE_EVENT_TRACE)
115 NXD_ADDRESS  src_address = {0};
116 #endif /* (NX_IPSEC_ENABLE) || defined(TX_ENABLE_EVENT_TRACE) */
117 
118 #ifdef NX_IPSEC_ENABLE
119 UINT         block_size;
120 NX_IPSEC_SA *sa = NX_NULL;
121 UINT         ret;
122 ULONG        data_offset;
123 #endif /* NX_IPSEC_ENABLE */
124 
125 #ifdef TX_ENABLE_EVENT_TRACE
126 ULONG        src_address_lsw = 0, dst_address_lsw = 0;
127 #endif /* TX_ENABLE_EVENT_TRACE */
128 
129 #ifndef NX_DISABLE_IPV4
130     /* First check the version. */
131     if (dest_address -> nxd_ip_version == NX_IP_VERSION_V4)
132     {
133 
134         /* Computer header space needed for physical layer and IP layer.  */
135         start_offset = NX_IPv4_PACKET;
136 
137         /* In this case, if_index indicate the interface_index.  */
138 
139         /* Check the validity of the if_index.  */
140         if ((if_index >= NX_MAX_PHYSICAL_INTERFACES) || (!ip_ptr -> nx_ip_interface[if_index].nx_interface_ip_address))
141         {
142             return(NX_INVALID_INTERFACE);
143         }
144 
145 #if defined(NX_IPSEC_ENABLE) || defined(TX_ENABLE_EVENT_TRACE)
146         /* Record the source address.  */
147         src_address.nxd_ip_address.v4 = ip_ptr -> nx_ip_interface[if_index].nx_interface_ip_address;
148         src_address.nxd_ip_version = NX_IP_VERSION_V4;
149 #endif /* NX_IPSEC_ENABLE */
150 
151         /* Get the mtu size.  */
152         payload_length = ip_ptr -> nx_ip_interface[if_index].nx_interface_ip_mtu_size + NX_PHYSICAL_HEADER;
153     }
154 #endif /* !NX_DISABLE_IPV4  */
155 
156 #ifdef FEATURE_NX_IPV6
157     if (dest_address -> nxd_ip_version == NX_IP_VERSION_V6)
158     {
159 
160         /* Computer header space needed for physical layer and IP layer.  */
161         start_offset = NX_IPv6_PACKET;
162 
163         /* In this case, if_index indicate the address_index.  */
164 
165         /* Check the validity of the if_index.  */
166         if (if_index >= (NX_MAX_IPV6_ADDRESSES + NX_LOOPBACK_IPV6_ENABLED))
167         {
168             return(NX_IP_ADDRESS_ERROR);
169         }
170 
171 #if defined(NX_IPSEC_ENABLE) || defined(TX_ENABLE_EVENT_TRACE)
172         /* Record the source address.  */
173         COPY_IPV6_ADDRESS(ip_ptr -> nx_ipv6_address[if_index].nxd_ipv6_address, src_address.nxd_ip_address.v6);
174         src_address.nxd_ip_version = NX_IP_VERSION_V6;
175 #endif /* NX_IPSEC_ENABLE */
176 
177         /* Get the mtu size.  */
178         payload_length = ip_ptr -> nx_ipv6_address[if_index].nxd_ipv6_address_attached -> nx_interface_ip_mtu_size + NX_PHYSICAL_HEADER;
179     }
180 #endif /* FEATURE_NX_IPV6  */
181 
182     if (protocol == NX_PROTOCOL_TCP)
183     {
184         /* Add TCP header length. */
185         start_offset += 20;
186     }
187     else if (protocol == NX_PROTOCOL_UDP)
188     {
189         /* Add UDP header length. */
190         start_offset += 8;
191     }
192 
193     /* Now compute the max protocol payload size that would not lead to IP fragmentation
194        e.g. keeping payload length at or below the MTU size. */
195     payload_length -= start_offset;
196 
197 #ifdef NX_IPSEC_ENABLE
198     ret = NX_IPSEC_TRAFFIC_BYPASS;
199     if (ip_ptr -> nx_ip_packet_egress_sa_lookup)
200     {
201 #ifdef FEATURE_NX_IPV6
202         if (src_address.nxd_ip_version == NX_IP_VERSION_V4)
203         {
204 #endif /* FEATURE_NX_IPV6  */
205             ret = ip_ptr -> nx_ip_packet_egress_sa_lookup(ip_ptr, &src_address, dest_address,
206                                                           (UCHAR)protocol, src_port, dest_port,
207                                                           &data_offset, (VOID **)&sa, (NX_ICMP_ECHO_REQUEST_TYPE << 8));
208 #ifdef FEATURE_NX_IPV6
209         }
210         else
211         {
212             ret = ip_ptr -> nx_ip_packet_egress_sa_lookup(ip_ptr, &src_address, dest_address,
213                                                           (UCHAR)protocol, src_port, dest_port,
214                                                           &data_offset, (VOID **)&sa, (NX_ICMPV6_ECHO_REQUEST_TYPE << 8));
215         }
216 #endif /* FEATURE_NX_IPV6  */
217     }
218     if (ret == NX_IPSEC_TRAFFIC_PROTECT)
219     {
220         /* Add IPsec protocol header layer. */
221         start_offset += sa -> nx_ipsec_sa_head_encap_size;
222         payload_length -= sa -> nx_ipsec_sa_head_encap_size;
223         /* Align the payload_length to the SA algorithm block size. */
224         if (sa -> nx_ipsec_sa_protocol == NX_PROTOCOL_NEXT_HEADER_ENCAP_SECURITY)
225         {
226             /* The next block computes the authentication trailer block size in the ESP combined mode. */
227             /* Payload length should exclude this trailer size.  */
228             if (sa -> nx_ipsec_sa_integrity_method != NX_NULL)
229             {
230                 block_size = sa -> nx_ipsec_sa_integrity_method -> nx_crypto_block_size_in_bytes;
231                 payload_length -= block_size;
232             }
233 
234             /* Compute the the actual data payload size.  */
235             if ((sa -> nx_ipsec_sa_encryption_method != NX_NULL) &&
236                 (sa -> nx_ipsec_sa_encryption_method -> nx_crypto_algorithm != NX_CRYPTO_NONE))
237             {
238                 /* Assume block size is 4, for ENCRYPTION_NULL algorithm. */
239                 block_size = 4;
240                 if (sa -> nx_ipsec_sa_encryption_method -> nx_crypto_algorithm != NX_CRYPTO_ENCRYPTION_NULL)
241                 {
242                     block_size = sa -> nx_ipsec_sa_encryption_method -> nx_crypto_block_size_in_bytes;
243                 }
244 
245                 /* Round the payload size to multiple of block size. */
246                 payload_length = payload_length / block_size;
247                 payload_length = payload_length * block_size;
248                 payload_length -= NX_IPSEC_ESP_TRAIL_LEN;
249             }
250         }
251         /* No need to update payload_length if sa_protocol is AH. */
252     }
253 #else
254     NX_PARAMETER_NOT_USED(src_port);
255     NX_PARAMETER_NOT_USED(dest_port);
256 #endif /* NX_IPSEC_ENABLE */
257 
258     /* Return payload_length and start_offset values. */
259 
260     if (payload_length_ptr)
261     {
262         *payload_length_ptr = payload_length;
263     }
264 
265     if (start_offset_ptr)
266     {
267         *start_offset_ptr = start_offset;
268     }
269 
270 #ifdef TX_ENABLE_EVENT_TRACE
271 #ifndef NX_DISABLE_IPV4
272     if (dest_address -> nxd_ip_version == NX_IP_VERSION_V4)
273     {
274         src_address_lsw = src_address.nxd_ip_address.v4;
275         dst_address_lsw = dest_address -> nxd_ip_address.v4;
276     }
277 #endif /* NX_DISABLE_IPV4 */
278 #ifdef FEATURE_NX_IPV6
279     if (dest_address -> nxd_ip_version == NX_IP_VERSION_V6)
280     {
281         src_address_lsw = src_address.nxd_ip_address.v6[3];
282         dst_address_lsw = dest_address -> nxd_ip_address.v6[3];
283     }
284 #endif /* FEATURE_NX_IPV6 */
285 
286     /* If trace is enabled, insert this event into the trace buffer.  */
287     NX_TRACE_IN_LINE_INSERT(NXD_TRACE_IP_MAX_PAYLOAD_SIZE_FIND,  src_address_lsw, dst_address_lsw, payload_length, start_offset,  NX_TRACE_PACKET_EVENTS, 0, 0);
288 
289 #endif /* TX_ENABLE_EVENT_TRACE */
290 
291     return(NX_SUCCESS);
292 }
293 
294