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