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 /** Internet Protocol (IP) */
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_ipv6.h"
30 #include "nx_packet.h"
31 #include "nx_icmpv6.h"
32
33 #ifdef NX_IPSEC_ENABLE
34 #include "nx_ipsec.h"
35 #endif /* NX_IPSEC_ENABLE */
36
37 #ifdef FEATURE_NX_IPV6
38
39
40 /**************************************************************************/
41 /* */
42 /* FUNCTION RELEASE */
43 /* */
44 /* _nx_ipv6_header_add PORTABLE C */
45 /* 6.1.8 */
46 /* AUTHOR */
47 /* */
48 /* Yuxin Zhou, Microsoft Corporation */
49 /* */
50 /* DESCRIPTION */
51 /* */
52 /* This function prepends an IPv6 header. */
53 /* */
54 /* INPUT */
55 /* */
56 /* ip_ptr Pointer to IP control block */
57 /* packet_pptr Pointer to packet to send */
58 /* protocol Protocol being encapsulated */
59 /* payload_size Size of the payload */
60 /* hop_limit Hop limit value to set in IP */
61 /* header. */
62 /* src_address Source address */
63 /* dest_address Destination address */
64 /* fragment Fragmentable or not */
65 /* */
66 /* OUTPUT */
67 /* */
68 /* None */
69 /* */
70 /* CALLS */
71 /* */
72 /* _nx_packet_transmit_release Release transmit packet */
73 /* */
74 /* CALLED BY */
75 /* */
76 /* _nx_ipv6_packet_send IPv6 packet transmit process */
77 /* _nx_icmpv6_send_ns Send NS packet */
78 /* */
79 /* RELEASE HISTORY */
80 /* */
81 /* DATE NAME DESCRIPTION */
82 /* */
83 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
84 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
85 /* resulting in version 6.1 */
86 /* 08-02-2021 Yuxin Zhou Modified comment(s), and */
87 /* supported TCP/IP offload, */
88 /* resulting in version 6.1.8 */
89 /* */
90 /**************************************************************************/
_nx_ipv6_header_add(NX_IP * ip_ptr,NX_PACKET ** packet_pptr,ULONG protocol,ULONG payload_size,ULONG hop_limit,ULONG * src_address,ULONG * dest_address,ULONG * fragment)91 UINT _nx_ipv6_header_add(NX_IP *ip_ptr, NX_PACKET **packet_pptr,
92 ULONG protocol, ULONG payload_size, ULONG hop_limit,
93 ULONG *src_address, ULONG *dest_address, ULONG *fragment)
94 {
95
96 NX_IPV6_HEADER *ip_header_ptr;
97 NX_PACKET *packet_ptr = *packet_pptr;
98 #ifdef NX_IPSEC_ENABLE
99 UINT status = NX_SUCCESS;
100 UCHAR is_hw_processed = NX_FALSE;
101 USHORT short_val;
102 #endif /* NX_IPSEC_ENABLE */
103
104 #if defined(NX_DISABLE_IP_INFO) && !defined(NX_IPSEC_ENABLE) && !defined(NX_ENABLE_IP_PACKET_FILTER)
105 NX_PARAMETER_NOT_USED(ip_ptr);
106 #endif
107
108 /* Add debug information. */
109 NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
110
111 if (fragment)
112 {
113 #ifndef NX_DISABLE_FRAGMENTATION
114 /* By default, it is fragmentable. */
115 *fragment = NX_TRUE;
116 #else
117 /* By default, it is not fragmentable. */
118 *fragment = NX_FALSE;
119 #endif /* NX_DISABLE_FRAGMENTATION */
120 }
121
122 #ifndef NX_DISABLE_IP_INFO
123
124 /* Increment the total send requests counter. */
125 ip_ptr -> nx_ip_total_packet_send_requests++;
126 #endif
127
128 /* Initialize the IP header incase this function returns fail. */
129 packet_ptr -> nx_packet_ip_header = packet_ptr -> nx_packet_prepend_ptr;
130
131 #ifdef NX_IPSEC_ENABLE
132 /* Check if this packet is continued after HW crypto engine. */
133 if (packet_ptr -> nx_packet_ipsec_sa_ptr &&
134 ((NX_IPSEC_SA *)(packet_ptr -> nx_packet_ipsec_sa_ptr)) -> nx_ipsec_sa_mode == NX_IPSEC_TRANSPORT_MODE &&
135 (packet_ptr -> nx_packet_ipsec_state == NX_IPSEC_AH_PACKET ||
136 packet_ptr -> nx_packet_ipsec_state == NX_IPSEC_ESP_PACKET))
137 {
138 is_hw_processed = NX_TRUE;
139 }
140
141 /* IPsec transport mode enabled? */
142 if (packet_ptr -> nx_packet_ipsec_sa_ptr &&
143 packet_ptr -> nx_packet_ipsec_state != NX_IPSEC_ESP_PACKET &&
144 packet_ptr -> nx_packet_ipsec_state != NX_IPSEC_AH_PACKET &&
145 ((NX_IPSEC_SA *)(packet_ptr -> nx_packet_ipsec_sa_ptr)) -> nx_ipsec_sa_mode == NX_IPSEC_TRANSPORT_MODE)
146 {
147
148 /* Yes, process the packet */
149 status = _nx_ipsec_ip_output_packet_process(ip_ptr, &packet_ptr, protocol, payload_size, (&payload_size));
150
151 /* Check for errors. */
152 if ((status != NX_SUCCESS) &&
153 (status != NX_IPSEC_HW_PENDING))
154 {
155
156 /* IPsec output packet process failed. */
157
158 /* Release the packet. */
159 _nx_packet_transmit_release(packet_ptr);
160
161 return(status);
162 }
163
164 /* Update the packet pointer. */
165 *packet_pptr = packet_ptr;
166
167 /* Change protocol to ESP or AH. */
168 protocol = (((NX_IPSEC_SA *)packet_ptr -> nx_packet_ipsec_sa_ptr) -> nx_ipsec_sa_protocol);
169
170 #ifndef NX_DISABLE_FRAGMENTATION
171 /* Set the fragment flag to false. Transport mode SAs have been defined to not carry fragments (IPv4 or IPv6), RFC 4301 page 66 and page 88.*/
172 if (fragment)
173 {
174 *fragment = NX_FALSE;
175 }
176 #endif /* NX_DISABLE_FRAGMENTATION */
177 }
178 #endif /* NX_IPSEC_ENABLE */
179
180 #ifdef NX_IPSEC_ENABLE
181 if (!is_hw_processed)
182 {
183 #endif /* NX_IPSEC_ENABLE */
184 /* Prepend the IP header to the packet. First, make room for the IP header. */
185 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IPV6_HEADER);
186
187 /* Increase the packet length. */
188 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + (ULONG)sizeof(NX_IPV6_HEADER);
189
190 /* Increase header length. */
191 packet_ptr -> nx_packet_ip_header_length = (UCHAR)(packet_ptr -> nx_packet_ip_header_length +
192 sizeof(NX_IPV6_HEADER));
193
194
195 /* If the interface IP address is not valid (in DAD state), only ICMP is allowed */
196 if (packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_state != NX_IPV6_ADDR_STATE_VALID)
197 {
198
199 #ifndef NX_DISABLE_IPV6_DAD
200 NX_ICMPV6_HEADER *icmpv6_header = (NX_ICMPV6_HEADER *)(packet_ptr -> nx_packet_prepend_ptr +
201 packet_ptr -> nx_packet_ip_header_length);
202
203 /* Interface IP address is invalid. Before dropping the outgoing packet,
204 check whether the interface address is in tentative state and the protocol
205 is ICMPv6-DAD. */
206
207 /* This check is needed only if DAD is not disabled.
208 If DAD is disabled, we drop the packet. */
209 if (!((protocol == NX_PROTOCOL_ICMPV6) &&
210 (packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_state == NX_IPV6_ADDR_STATE_TENTATIVE) &&
211 (icmpv6_header -> nx_icmpv6_header_type == NX_ICMPV6_NEIGHBOR_SOLICITATION_TYPE)))
212 #endif /* NX_DISABLE_IPV6_DAD */
213 {
214 #ifndef NX_DISABLE_IP_INFO
215
216 /* Increment the IP invalid packet error. */
217 ip_ptr -> nx_ip_invalid_transmit_packets++;
218 #endif
219
220 /* Release the packet. */
221 _nx_packet_transmit_release(packet_ptr);
222
223 /* Return... nothing more can be done! */
224 return(NX_NO_INTERFACE_ADDRESS);
225 }
226 }
227
228 /* If the IP header won't fit, return an error. */
229 /*lint -e{946} suppress pointer subtraction, since it is necessary. */
230 NX_ASSERT(packet_ptr -> nx_packet_prepend_ptr >= packet_ptr -> nx_packet_data_start);
231
232 /* Build the IP header. */
233 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
234 ip_header_ptr = (NX_IPV6_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
235 packet_ptr -> nx_packet_ip_header = packet_ptr -> nx_packet_prepend_ptr;
236
237 /* bits 31-28: IP version. Bits 27-20: Traffic Class. Bits 19-00: Flow Lable */
238 ip_header_ptr -> nx_ip_header_word_0 = (ULONG)(6 << 28);
239 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_0);
240
241 /* bits 31-16: payload size. Bits 15-8: Next Header. Bits 7-0 Hop limit */
242 /* ip_header_ptr -> nx_ip_header_word_1 = (payload_size << 16) | (protocol << 8) | (ip_ptr -> nx_ipv6_hop_limit);*/
243 ip_header_ptr -> nx_ip_header_word_1 = (payload_size << 16) | (protocol << 8) | (hop_limit);
244 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_1);
245
246
247 /* Fill in local IPv6 address as sender's address*/
248 COPY_IPV6_ADDRESS(src_address, ip_header_ptr -> nx_ip_header_source_ip);
249
250 COPY_IPV6_ADDRESS(dest_address, ip_header_ptr -> nx_ip_header_destination_ip);
251
252 /* Fix endianness */
253 NX_IPV6_ADDRESS_CHANGE_ENDIAN(ip_header_ptr -> nx_ip_header_destination_ip);
254 NX_IPV6_ADDRESS_CHANGE_ENDIAN(ip_header_ptr -> nx_ip_header_source_ip);
255
256 #ifdef NX_IPSEC_ENABLE
257 }
258 else
259 {
260
261 /* Fix payload size. */
262 /* Build the IP header. */
263 ip_header_ptr = (NX_IPV6_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
264
265 payload_size -= sizeof(NX_IPV6_HEADER);
266 short_val = (USHORT)payload_size;
267 NX_CHANGE_USHORT_ENDIAN(short_val);
268 payload_size = short_val;
269
270 /* First clear payload_size field. */
271 ip_header_ptr -> nx_ip_header_word_1 &= 0xFFFF0000;
272
273 /* Fill payload_size field. */
274 ip_header_ptr -> nx_ip_header_word_1 |= short_val;
275 }
276
277 /* IPsec tunnel mode. */
278 if (packet_ptr -> nx_packet_ipsec_sa_ptr &&
279 packet_ptr -> nx_packet_ipsec_state != NX_IPSEC_ESP_PACKET &&
280 packet_ptr -> nx_packet_ipsec_state != NX_IPSEC_AH_PACKET &&
281 ((NX_IPSEC_SA *)(packet_ptr -> nx_packet_ipsec_sa_ptr)) -> nx_ipsec_sa_mode == NX_IPSEC_TUNNEL_MODE)
282 {
283 status = _nx_ipsec_ip_output_packet_process(ip_ptr, &packet_ptr, NX_PROTOCOL_IPV6, (ULONG)payload_size, (ULONG *)(&payload_size));
284
285 if ((status != NX_SUCCESS) &&
286 (status != NX_IPSEC_HW_PENDING))
287 {
288 /* IPsec output packet process failed. */
289
290 /* Release the packet. */
291 _nx_packet_transmit_release(packet_ptr);
292
293 return(status);
294 }
295
296 /* Update the packet pointer. */
297 *packet_pptr = packet_ptr;
298
299 /* Tunnel consume the packet. */
300 return(NX_IPSEC_PKT_CONT);
301 }
302
303 /* ICV calculation before the packet sent over the wire if packet went through AH processing. */
304 if (packet_ptr -> nx_packet_ipsec_sa_ptr &&
305 packet_ptr -> nx_packet_ipsec_state == NX_IPSEC_AH_PACKET)
306 {
307 status = ip_ptr -> nx_ip_ipsec_authentication_header_transmit(ip_ptr, &packet_ptr, protocol, 1);
308
309 if ((status != NX_SUCCESS) &&
310 (status != NX_IPSEC_HW_PENDING))
311 {
312 /* Release the packet. */
313 _nx_packet_transmit_release(packet_ptr);
314
315 return(status);
316 }
317
318 /* Update the packet pointer. */
319 *packet_pptr = packet_ptr;
320 }
321
322 /* HW crypto driver is processing packet. */
323 if (status == NX_IPSEC_HW_PENDING)
324 {
325
326 #ifndef NX_DISABLE_IP_INFO
327
328 /* Decrement the total send requests counter. */
329 ip_ptr -> nx_ip_total_packet_send_requests--;
330 #endif
331 return(status);
332 }
333
334 #endif /* NX_IPSEC_ENABLE */
335
336 return(NX_SUCCESS);
337 }
338
339 #endif /* FEATURE_NX_IPV6 */
340
341