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