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