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