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