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