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