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 Control Message Protocol (ICMP)                            */
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_packet.h"
30 #include "nx_ip.h"
31 #include "nx_icmp.h"
32 
33 #ifdef NX_IPSEC_ENABLE
34 #include "nx_ipsec.h"
35 #endif /* NX_IPSEC_ENABLE */
36 
37 #ifndef NX_DISABLE_IPV4
38 /**************************************************************************/
39 /*                                                                        */
40 /*  FUNCTION                                               RELEASE        */
41 /*                                                                        */
42 /*    _nx_icmpv4_process_echo_request                     PORTABLE C      */
43 /*                                                           6.1          */
44 /*  AUTHOR                                                                */
45 /*                                                                        */
46 /*    Yuxin Zhou, Microsoft Corporation                                   */
47 /*                                                                        */
48 /*  DESCRIPTION                                                           */
49 /*                                                                        */
50 /*    This internal function processes incoming echo request message.     */
51 /*    It validates the echo request and sends an echo reply back to the   */
52 /*    sender.                                                             */
53 /*                                                                        */
54 /*  INPUT                                                                 */
55 /*                                                                        */
56 /*    ip_ptr                                Pointer to IP control block   */
57 /*    packet_ptr                            ICMP packet pointer           */
58 /*                                                                        */
59 /*  OUTPUT                                                                */
60 /*                                                                        */
61 /*    None                                                                */
62 /*                                                                        */
63 /*  CALLS                                                                 */
64 /*                                                                        */
65 /*    _nx_ip_route_find                     Find a suitable outgoing      */
66 /*                                            interface.                  */
67 /*    _nx_ip_packet_send                    Send ICMP packet out          */
68 /*    _nx_packet_release                    Release packet to packet pool */
69 /*                                                                        */
70 /*  CALLED BY                                                             */
71 /*                                                                        */
72 /*    _nx_icmpv4_packet_process             Main ICMP packet pocess       */
73 /*                                                                        */
74 /*  RELEASE HISTORY                                                       */
75 /*                                                                        */
76 /*    DATE              NAME                      DESCRIPTION             */
77 /*                                                                        */
78 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
79 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
80 /*                                            resulting in version 6.1    */
81 /*                                                                        */
82 /**************************************************************************/
_nx_icmpv4_process_echo_request(NX_IP * ip_ptr,NX_PACKET * packet_ptr)83 VOID  _nx_icmpv4_process_echo_request(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
84 {
85 
86 NX_ICMPV4_HEADER *header_ptr;
87 ULONG             checksum;
88 ULONG             old_m;
89 #if defined(NX_DISABLE_ICMPV4_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE)
90 ULONG             compute_checksum = 1;
91 #endif /* defined(NX_DISABLE_ICMPV4_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) */
92 NX_IPV4_HEADER   *ipv4_header;
93 ULONG             next_hop_address = NX_NULL;
94 #ifdef NX_IPSEC_ENABLE
95 ULONG             data_offset;
96 VOID             *sa = NX_NULL;
97 NXD_ADDRESS       src_addr;
98 NXD_ADDRESS       dest_addr;
99 UINT              ret;
100 #endif /* NX_IPSEC_ENABLE */
101 
102 
103     /* Add debug information. */
104     NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
105 
106 
107     /* Point to the ICMP message header.  */
108     /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
109     header_ptr =  (NX_ICMPV4_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
110 
111     /* Pickup the return IP address.  */
112     /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
113     ipv4_header = (NX_IPV4_HEADER *)packet_ptr -> nx_packet_ip_header;
114 
115 #ifndef NX_DISABLE_ICMP_INFO
116     /* Increment the ICMP pings received count.  */
117     ip_ptr -> nx_ip_pings_received++;
118 #endif
119 
120     /* Change the type to Echo Reply and send back the message to the caller.  */
121     header_ptr -> nx_icmpv4_header_type = NX_ICMP_ECHO_REPLY_TYPE;
122 
123 #ifdef NX_IPSEC_ENABLE
124 
125     src_addr.nxd_ip_version = NX_IP_VERSION_V4;
126     src_addr.nxd_ip_address.v4 = packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_address;
127 
128     dest_addr.nxd_ip_version = NX_IP_VERSION_V4;
129     dest_addr.nxd_ip_address.v4 = ipv4_header -> nx_ip_header_source_ip;
130 
131     /* Check if IPsec is enabled. */
132     if (ip_ptr -> nx_ip_packet_egress_sa_lookup != NX_NULL)
133     {
134 
135         /* Check for possible SA match. */
136         ret = ip_ptr -> nx_ip_packet_egress_sa_lookup(ip_ptr,                                    /* IP ptr */
137                                                       &src_addr,                                 /* src_addr */
138                                                       &dest_addr,                                /* dest_addr */
139                                                       NX_PROTOCOL_ICMP,                          /* protocol */
140                                                       0,                                         /* port, not used. */
141                                                       0,                                         /* port, not used. */
142                                                       &data_offset, &sa, (NX_ICMP_ECHO_REPLY_TYPE << 8));
143 
144         /* Do the IPSec SA rules permit this packet to be sent? */
145         if (ret == NX_IPSEC_TRAFFIC_PROTECT)
146         {
147 
148             /* Yes; make sure the outgoing packet has enough space for IPsec header info. */
149             if ((ULONG)(packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start) <
150                 (NX_IPv4_PACKET + data_offset))
151             {
152 
153                 /* Not enough space.   Release the packet and return. */
154                 _nx_packet_release(packet_ptr);
155 
156                 return;
157             }
158 
159             /* Save the SA to the packet. */
160             packet_ptr -> nx_packet_ipsec_sa_ptr = sa;
161         }
162         else if (ret == NX_IPSEC_TRAFFIC_DROP || ret == NX_IPSEC_TRAFFIC_PENDING_IKEV2)
163         {
164 
165             /* No; Drop the packet and return. */
166             _nx_packet_release(packet_ptr);
167 
168             return;
169         }
170         else
171         {
172             /* SA rules indicate to bypass IPSec processing. Zero out the
173                SA information. */
174             packet_ptr -> nx_packet_ipsec_sa_ptr = NX_NULL;
175         }
176     }
177 #endif /* NX_IPSEC_ENABLE */
178 
179 #ifdef NX_DISABLE_ICMPV4_TX_CHECKSUM
180     compute_checksum = 0;
181 #endif /* NX_DISABLE_ICMPV4_TX_CHECKSUM */
182 
183 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
184     if (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM)
185     {
186         compute_checksum = 0;
187     }
188 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
189 
190 #ifdef NX_IPSEC_ENABLE
191     if ((sa != NX_NULL) && (((NX_IPSEC_SA *)sa) -> nx_ipsec_sa_encryption_method != NX_CRYPTO_NONE))
192     {
193         compute_checksum = 1;
194     }
195 #endif /* NX_IPSEC_ENABLE */
196 
197 #if defined(NX_DISABLE_ICMPV4_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE)
198     if (compute_checksum)
199 #endif /* defined(NX_DISABLE_ICMPV4_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) */
200     {
201 
202         /* Update the checksum, according to the RFC1624 page2, Eqn.3.
203            HC  - old checksum in header
204            HC' - new checksum in header
205            m   - old value of a 16-bit field
206            m'  - new value of a 16-bit field
207            HC' = ~(C + (-m) + m')
208            = ~(~HC + ~m + m') */
209 
210         /* Endian swapping logic.  */
211         NX_CHANGE_USHORT_ENDIAN(header_ptr -> nx_icmpv4_header_checksum);
212 
213         /* Get the old checksum (HC) in header. */
214         checksum = header_ptr -> nx_icmpv4_header_checksum;
215 
216         /* Get the old type(m). */
217         old_m = (ULONG)(NX_ICMP_ECHO_REQUEST_TYPE << 8);
218 
219         /* Update the checksum, get the new checksum(HC'). */
220         /* The m' is value of echo reply type. It is zero so can be ignored. */
221         checksum = ((~checksum) & 0xFFFF) + ((~old_m) & 0xFFFF);
222 
223         /* Fold a 4-byte value into a two byte value */
224         checksum = (checksum >> 16) + (checksum & 0xFFFF);
225 
226         /* Do it again in case previous operation generates an overflow */
227         checksum = (checksum >> 16) + (checksum & 0xFFFF);
228 
229         /* Store the checksum.  */
230         header_ptr -> nx_icmpv4_header_checksum = (~checksum & NX_LOWER_16_MASK);
231 
232         /* If NX_LITTLE_ENDIAN is defined, the header need to be swapped back
233            for output (network byte order).  */
234         NX_CHANGE_USHORT_ENDIAN(header_ptr -> nx_icmpv4_header_checksum);
235     }
236 #if defined(NX_DISABLE_ICMPV4_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY)
237     else
238     {
239 
240         /* Clear the checksum.  */
241         header_ptr -> nx_icmpv4_header_checksum = 0;
242 
243 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
244         packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM;
245 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
246     }
247 #endif
248 
249     /* Figure out the best interface to send the ICMP packet on. */
250     _nx_ip_route_find(ip_ptr, ipv4_header -> nx_ip_header_source_ip,
251                       &packet_ptr -> nx_packet_address.nx_packet_interface_ptr,
252                       &next_hop_address);
253 
254     /* If trace is enabled, insert this event into the trace buffer.  */
255     NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_ICMP_RECEIVE, ip_ptr, ipv4_header -> nx_ip_header_source_ip, packet_ptr, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
256 
257 #ifndef NX_DISABLE_ICMP_INFO
258     /* Increment the ICMP pings responded to count.  */
259     ip_ptr -> nx_ip_pings_responded_to++;
260 #endif
261 
262     /* Send the ICMP packet to the IP component.  */
263     /*lint -e{644} suppress variable might not be initialized, since "next_hop_address" was initialized in _nx_ip_route_find. */
264     _nx_ip_packet_send(ip_ptr, packet_ptr, ipv4_header -> nx_ip_header_source_ip,
265                        NX_IP_NORMAL, NX_IP_TIME_TO_LIVE, NX_IP_ICMP, NX_FRAGMENT_OKAY, next_hop_address);
266 }
267 #endif /* !NX_DISABLE_IPV4  */
268 
269