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