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_packet.h"
30 
31 #ifdef NX_IPSEC_ENABLE
32 #include "nx_ipsec.h"
33 #endif /* NX_IPSEC_ENABLE */
34 
35 #ifndef NX_DISABLE_IPV4
36 /**************************************************************************/
37 /*                                                                        */
38 /*  FUNCTION                                               RELEASE        */
39 /*                                                                        */
40 /*    _nx_ip_packet_send                                  PORTABLE C      */
41 /*                                                           6.1.8        */
42 /*  AUTHOR                                                                */
43 /*                                                                        */
44 /*    Yuxin Zhou, Microsoft Corporation                                   */
45 /*                                                                        */
46 /*  DESCRIPTION                                                           */
47 /*                                                                        */
48 /*    This function prepends an IP header and sends an IP packet to the   */
49 /*    appropriate link driver.                                            */
50 /*                                                                        */
51 /*  INPUT                                                                 */
52 /*                                                                        */
53 /*    ip_ptr                                Pointer to IP control block   */
54 /*    packet_ptr                            Pointer to packet to send     */
55 /*    destination_ip                        Destination IP address        */
56 /*    type_of_service                       Type of service for packet    */
57 /*    time_to_live                          Time to live value for packet */
58 /*    protocol                              Protocol being encapsulated   */
59 /*    fragment                              Don't fragment bit            */
60 /*    next_hop_address                      Next Hop address              */
61 /*                                                                        */
62 /*  OUTPUT                                                                */
63 /*                                                                        */
64 /*    None                                                                */
65 /*                                                                        */
66 /*  CALLS                                                                 */
67 /*                                                                        */
68 /*    _nx_ip_checksum_compute               Compute IP checksum           */
69 /*    _nx_ip_header_add                     Add the IP header             */
70 /*    _nx_ip_route_find                     Find suitable outgoing        */
71 /*    _nx_ip_driver_packet_send             Send the IP packet            */
72 /*    _nx_packet_transmit_release           Release transmit packet       */
73 /*                                                                        */
74 /*  CALLED BY                                                             */
75 /*                                                                        */
76 /*    NetX Source Code                                                    */
77 /*                                                                        */
78 /*  RELEASE HISTORY                                                       */
79 /*                                                                        */
80 /*    DATE              NAME                      DESCRIPTION             */
81 /*                                                                        */
82 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
83 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
84 /*                                            resulting in version 6.1    */
85 /*  08-02-2021     Yuxin Zhou               Modified comment(s), and      */
86 /*                                            supported TCP/IP offload,   */
87 /*                                            added new ip filter,        */
88 /*                                            resulting in version 6.1.8  */
89 /*                                                                        */
90 /**************************************************************************/
_nx_ip_packet_send(NX_IP * ip_ptr,NX_PACKET * packet_ptr,ULONG destination_ip,ULONG type_of_service,ULONG time_to_live,ULONG protocol,ULONG fragment,ULONG next_hop_address)91 VOID  _nx_ip_packet_send(NX_IP *ip_ptr, NX_PACKET *packet_ptr,
92                          ULONG destination_ip, ULONG type_of_service, ULONG time_to_live,
93                          ULONG protocol, ULONG fragment, ULONG next_hop_address)
94 {
95 
96 #ifdef NX_IPSEC_ENABLE
97 UINT            status = 0;
98 ULONG           payload_size;
99 USHORT          value;
100 UCHAR           is_hw_processed = NX_FALSE;
101 NX_IPV4_HEADER *ip_header_ptr;
102 ULONG           checksum;
103 ULONG           val;
104 #endif /* NX_IPSEC_ENABLE */
105 
106 
107     /* Add debug information. */
108     NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
109 
110 #ifndef NX_DISABLE_IP_INFO
111 
112     /* Increment the total send requests counter.  */
113     ip_ptr -> nx_ip_total_packet_send_requests++;
114 #endif
115 
116     /* Make sure the packet interface is set. */
117     if (packet_ptr -> nx_packet_address.nx_packet_interface_ptr == NX_NULL)
118     {
119 
120 #ifndef NX_DISABLE_IP_INFO
121 
122         /* Increment the IP invalid packet error.  */
123         ip_ptr -> nx_ip_invalid_transmit_packets++;
124 #endif /* !NX_DISABLE_IP_INFO */
125 
126         /* Prepend the IP header to the packet.  First, make room for the IP header.  */
127         packet_ptr -> nx_packet_prepend_ptr =  packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IPV4_HEADER);
128 
129         /* Increase the packet length.  */
130         packet_ptr -> nx_packet_length =  packet_ptr -> nx_packet_length + (ULONG)sizeof(NX_IPV4_HEADER);
131 
132         /* Release the packet.  */
133         _nx_packet_transmit_release(packet_ptr);
134 
135         /* Return... nothing more can be done!  */
136         return;
137     }
138 
139 #ifdef NX_ENABLE_TCPIP_OFFLOAD
140     if (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag &
141         NX_INTERFACE_CAPABILITY_TCPIP_OFFLOAD)
142     {
143 #ifndef NX_DISABLE_IP_INFO
144 
145         /* Increment the IP invalid packet error.  */
146         ip_ptr -> nx_ip_invalid_transmit_packets++;
147 #endif
148 
149         /* Ignore sending all packets for TCP/IP offload. Release the packet.  */
150         _nx_packet_transmit_release(packet_ptr);
151 
152         /* Return... nothing more can be done!  */
153         return;
154     }
155 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
156 
157 #ifdef NX_IPSEC_ENABLE
158     /* Check if this packet is continued after HW crypto engine. */
159     if (packet_ptr -> nx_packet_ipsec_sa_ptr &&
160         ((NX_IPSEC_SA *)(packet_ptr -> nx_packet_ipsec_sa_ptr)) -> nx_ipsec_sa_mode == NX_IPSEC_TRANSPORT_MODE &&
161         (packet_ptr -> nx_packet_ipsec_state == NX_IPSEC_AH_PACKET ||
162          packet_ptr -> nx_packet_ipsec_state == NX_IPSEC_ESP_PACKET))
163     {
164         is_hw_processed = NX_TRUE;
165     }
166 
167     /* Process this packet in IPsec transport mode? */
168     if (packet_ptr -> nx_packet_ipsec_sa_ptr &&
169         packet_ptr -> nx_packet_ipsec_state != NX_IPSEC_ESP_PACKET &&
170         packet_ptr -> nx_packet_ipsec_state != NX_IPSEC_AH_PACKET &&
171         ((NX_IPSEC_SA *)(packet_ptr -> nx_packet_ipsec_sa_ptr)) -> nx_ipsec_sa_mode == NX_IPSEC_TRANSPORT_MODE)
172     {
173 
174         /* Perform IPSec processing and insert IPsec headers before the IP header. */
175         /* Notice that for TCP transmission, a new packet is used to store the encrypted data, while the
176            original TCP packet is put back on to the transmitted queue. */
177         payload_size = packet_ptr -> nx_packet_length;
178         status = _nx_ipsec_ip_output_packet_process(ip_ptr, &packet_ptr, (protocol >> 16), payload_size, &payload_size);
179 
180         if ((status != NX_SUCCESS) &&
181             (status != NX_IPSEC_HW_PENDING))
182         {
183 
184             /* Install an area for the IP header.  This is required by the nx_packet_transmit_release. */
185             packet_ptr -> nx_packet_prepend_ptr =  packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IPV4_HEADER);
186 
187             /* Increase the packet length for the IP header.  */
188             packet_ptr -> nx_packet_length =  packet_ptr -> nx_packet_length + sizeof(NX_IPV4_HEADER);
189 
190             /* IPsec output packet process failed. */
191 
192             /* Release the packet.  */
193             _nx_packet_transmit_release(packet_ptr);
194 
195             return;
196         }
197 
198         /* Now set the IPSec protocol. */
199         protocol = (ULONG)((((NX_IPSEC_SA *)packet_ptr -> nx_packet_ipsec_sa_ptr) -> nx_ipsec_sa_protocol) << 16);
200 
201         /* Set the DF bit.
202            Transport mode SAs have been defined to not carry fragments (IPv4 or IPv6),RFC 4301 page 66&88..*/
203         fragment = NX_DONT_FRAGMENT;
204     }
205 #endif /* NX_IPSEC_ENABLE  */
206 
207 
208     /* If the packet is processed by HW crypto engine, do not add IP header. */
209 #ifdef NX_IPSEC_ENABLE
210     if (!is_hw_processed)
211 #endif /* NX_IPSEC_ENABLE  */
212     {
213 
214         /* Add the IP Header to the packet.  */
215         _nx_ip_header_add(ip_ptr, packet_ptr, packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address,
216                           destination_ip, type_of_service, time_to_live, protocol, fragment);
217 
218 #ifdef NX_ENABLE_IP_PACKET_FILTER
219         /* Check if the IP packet filter is set. */
220         if (ip_ptr -> nx_ip_packet_filter)
221         {
222 
223             /* Yes, call the IP packet filter routine. */
224             if (ip_ptr -> nx_ip_packet_filter((VOID *)(packet_ptr -> nx_packet_prepend_ptr),
225                                               NX_IP_PACKET_OUT) != NX_SUCCESS)
226             {
227 
228                 /* Drop the packet. */
229                 _nx_packet_transmit_release(packet_ptr);
230                 return;
231             }
232         }
233 
234         /* Check if the IP packet filter extended is set. */
235         if (ip_ptr -> nx_ip_packet_filter_extended)
236         {
237 
238             /* Yes, call the IP packet filter extended routine. */
239             if (ip_ptr -> nx_ip_packet_filter_extended(ip_ptr, packet_ptr, NX_IP_PACKET_OUT) != NX_SUCCESS)
240             {
241 
242                 /* Drop the packet. */
243                 _nx_packet_transmit_release(packet_ptr);
244                 return;
245             }
246         }
247 #endif /* NX_ENABLE_IP_PACKET_FILTER */
248     }
249 
250     /* If trace is enabled, insert this event into the trace buffer.  */
251     NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IP_SEND, ip_ptr, destination_ip, packet_ptr, packet_ptr -> nx_packet_length, NX_TRACE_INTERNAL_EVENTS, 0, 0);
252 
253 
254 #ifdef NX_IPSEC_ENABLE
255 
256     if (is_hw_processed)
257     {
258 
259         /* Destination IP is unknow after HW crypto engine process.  */
260         /* Get destination IP from IP header.  */
261         /* Setup the IP header pointer.  */
262         ip_header_ptr =  (NX_IPV4_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
263 
264         /* Fix payload size.  */
265         value = (USHORT)(packet_ptr -> nx_packet_length);
266         NX_CHANGE_USHORT_ENDIAN(value);
267 
268         /* First clear payload_size field.  */
269         ip_header_ptr -> nx_ip_header_word_0 &= 0xFFFF;
270 
271         /* Fill payload_size field.  */
272         ip_header_ptr -> nx_ip_header_word_0 |= (ULONG)(value << NX_SHIFT_BY_16) & 0xFFFF0000;
273 
274 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
275         if (!(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM))
276 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
277         {
278 
279             /* Clear checksum in the IP header.  */
280             ip_header_ptr -> nx_ip_header_word_2 =  ip_header_ptr -> nx_ip_header_word_2 & 0xFFFF;
281 
282             checksum = _nx_ip_checksum_compute(packet_ptr, NX_IP_VERSION_V4,
283                                                /* Length is the size of IP header, including options */
284                                                20,
285                                                /* IPv4 header checksum does not use src/dest addresses */
286                                                NULL, NULL);
287 
288             val = (ULONG)(~checksum);
289             val = val & NX_LOWER_16_MASK;
290 
291             /* Convert to network byte order. */
292             NX_CHANGE_ULONG_ENDIAN(val);
293 
294             /* Now store the checksum in the IP header.  */
295             ip_header_ptr -> nx_ip_header_word_2 =  ip_header_ptr -> nx_ip_header_word_2 | val;
296         }
297 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
298         else
299         {
300             packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM;
301         }
302 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
303     }
304 
305     /* Process this packet in IPsec tunnel mode? */
306     if (packet_ptr -> nx_packet_ipsec_sa_ptr &&
307         packet_ptr -> nx_packet_ipsec_state != NX_IPSEC_ESP_PACKET &&
308         packet_ptr -> nx_packet_ipsec_state != NX_IPSEC_AH_PACKET &&
309         ((NX_IPSEC_SA *)(packet_ptr -> nx_packet_ipsec_sa_ptr)) -> nx_ipsec_sa_mode == NX_IPSEC_TUNNEL_MODE)
310     {
311 
312 
313         /* Perform IPSec processing for tunneling. Insert IPsec headers and encapsulating the IP header. */
314         payload_size = packet_ptr -> nx_packet_length;
315         status = _nx_ipsec_ip_output_packet_process(ip_ptr, &packet_ptr, NX_PROTOCOL_IPV4, payload_size, &payload_size);
316 
317         if ((status != NX_SUCCESS) &&
318             (status != NX_IPSEC_HW_PENDING))
319         {
320             /* IPsec output packet process failed. */
321 
322             /* Release the packet.  */
323             _nx_packet_transmit_release(packet_ptr);
324         }
325 
326         /* Tunnel consume the packet. */
327         return;
328     }
329 
330     /* Process IPSec on packet requiring AH processing. */
331     if (packet_ptr -> nx_packet_ipsec_sa_ptr &&
332         packet_ptr -> nx_packet_ipsec_state == NX_IPSEC_AH_PACKET)
333     {
334 
335         status = ip_ptr -> nx_ip_ipsec_authentication_header_transmit(ip_ptr, &packet_ptr, protocol, 1);
336 
337         if ((status != NX_SUCCESS) &&
338             (status != NX_IPSEC_HW_PENDING))
339         {
340             /* Release the packet.  */
341             _nx_packet_transmit_release(packet_ptr);
342 
343             return;
344         }
345     }
346 
347     /* HW crypto driver is processing packet. */
348     if (status == NX_IPSEC_HW_PENDING)
349     {
350 
351 #ifndef NX_DISABLE_IP_INFO
352 
353         /* Decrement the total send requests counter.  */
354         ip_ptr -> nx_ip_total_packet_send_requests--;
355 #endif
356         return;
357     }
358 
359 #endif
360 
361     /* If the next hop address is null, indicates the specified interface is unreached.  */
362     if (next_hop_address == 0)
363     {
364 
365         /* Check whether the forward feature is enabled.  */
366         if (ip_ptr -> nx_ip_forward_packet_process)
367         {
368 
369             /* Initialize the interface.  */
370             packet_ptr -> nx_packet_address.nx_packet_interface_ptr = NX_NULL;
371 
372             /* Figure out the best interface to send the packet on. */
373             _nx_ip_route_find(ip_ptr, destination_ip, &packet_ptr -> nx_packet_address.nx_packet_interface_ptr, &next_hop_address);
374         }
375 
376         /* Make sure the packet interface and next hop address are set. */
377         /*lint -e{644} suppress variable might not be initialized, since "next_hop_address" was initialized in _nx_ip_route_find. */
378         if ((packet_ptr -> nx_packet_address.nx_packet_interface_ptr == NX_NULL) || (next_hop_address == 0))
379         {
380 
381 #ifndef NX_DISABLE_IP_INFO
382 
383             /* Increment the IP invalid packet error.  */
384             ip_ptr -> nx_ip_invalid_transmit_packets++;
385 #endif /* !NX_DISABLE_IP_INFO */
386 
387             /* Release the packet.  */
388             _nx_packet_transmit_release(packet_ptr);
389 
390             /* Return... nothing more can be done!  */
391             return;
392         }
393     }
394 
395     /* Directly send the packet.  */
396     _nx_ip_driver_packet_send(ip_ptr, packet_ptr, destination_ip, fragment, next_hop_address);
397 }
398 
399 #endif /* NX_DISABLE_IPV4 */
400 
401