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 "tx_thread.h"
29 #include "nx_packet.h"
30 #include "nx_ipv6.h"
31 #include "nx_icmpv6.h"
32
33 #ifdef NX_IPSEC_ENABLE
34 #include "nx_ipsec.h"
35 #endif /* NX_IPSEC_ENABLE */
36
37
38 #ifdef FEATURE_NX_IPV6
39
40
41
42 /**************************************************************************/
43 /* */
44 /* FUNCTION RELEASE */
45 /* */
46 /* _nx_icmpv6_process_echo_reply PORTABLE C */
47 /* 6.1 */
48 /* AUTHOR */
49 /* */
50 /* Yuxin Zhou, Microsoft Corporation */
51 /* */
52 /* DESCRIPTION */
53 /* */
54 /* This function processes incoming echo reply message. It matches */
55 /* the thread that has pending echo request, and unblocks the thread. */
56 /* */
57 /* INPUT */
58 /* */
59 /* ip_ptr IP stack instance */
60 /* packet_ptr The echo reply packet */
61 /* */
62 /* OUTPUT */
63 /* */
64 /* None */
65 /* */
66 /* CALLS */
67 /* */
68 /* _nx_packet_release Release packet back to pool */
69 /* _tx_thread_system_resume Resume the specified thread */
70 /* _tx_thread_system_preempt_check Check for preemption */
71 /* */
72 /* CALLED BY */
73 /* */
74 /* _nx_icmpv6_packet_process Main ICMPv6 packet handler */
75 /* */
76 /* RELEASE HISTORY */
77 /* */
78 /* DATE NAME DESCRIPTION */
79 /* */
80 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
81 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
82 /* resulting in version 6.1 */
83 /* */
84 /**************************************************************************/
85
_nx_icmpv6_process_echo_reply(NX_IP * ip_ptr,NX_PACKET * packet_ptr)86 VOID _nx_icmpv6_process_echo_reply(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
87 {
88 TX_INTERRUPT_SAVE_AREA
89
90 NX_IPV6_HEADER *ipv6_header;
91 USHORT sequence_num;
92 ULONG suspended;
93 TX_THREAD *thread_ptr;
94 NX_ICMPV6_ECHO *echo_ptr;
95
96
97 /* Add debug information. */
98 NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
99
100 #ifndef NX_DISABLE_RX_SIZE_CHECKING
101 /* Check packet length. */
102 if (packet_ptr -> nx_packet_length < sizeof(NX_ICMPV6_ECHO))
103 {
104 #ifndef NX_DISABLE_ICMP_INFO
105
106 /* Increment the ICMP invalid message count. */
107 ip_ptr -> nx_ip_icmp_invalid_packets++;
108 #endif
109
110 /* Invalid ICMP message, just release it. */
111 _nx_packet_release(packet_ptr);
112 return;
113 }
114 #endif /* NX_DISABLE_RX_SIZE_CHECKING */
115
116 /* Points to the IPv6 header. */
117 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
118 ipv6_header = (NX_IPV6_HEADER *)packet_ptr -> nx_packet_ip_header;
119
120 /* Points to the ICMP echo reply message body. */
121 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
122 echo_ptr = (NX_ICMPV6_ECHO *)packet_ptr -> nx_packet_prepend_ptr;
123 #ifndef NX_DISABLE_ICMP_INFO
124
125 /* Increment the ICMP responses received count. */
126 ip_ptr -> nx_ip_ping_responses_received++;
127 #endif
128
129 /* Discard the packet if source address is unspecified (::). */
130 if (CHECK_UNSPECIFIED_ADDRESS(ipv6_header -> nx_ip_header_source_ip))
131 {
132
133 #ifndef NX_DISABLE_ICMP_INFO
134
135 /* Increment the ICMP invalid packet error. */
136 ip_ptr -> nx_ip_icmp_invalid_packets++;
137 #endif /* NX_DISABLE_ICMP_INFO */
138
139 /* Free the packet and return. */
140 _nx_packet_release(packet_ptr);
141
142 return;
143 }
144
145 /* For IPv6, if the interface IP address is not valid yet,
146 do not respond to ping. */
147 if (packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_state != NX_IPV6_ADDR_STATE_VALID)
148 {
149
150
151 #ifndef NX_DISABLE_ICMP_INFO
152
153 /* Increment the ICMP invalid packet error. */
154 ip_ptr -> nx_ip_icmp_invalid_packets++;
155 #endif /* NX_DISABLE_ICMP_INFO */
156
157 /* Free the packet and return. */
158 _nx_packet_release(packet_ptr);
159
160 return;
161 }
162
163 /* Pickup sequence number. */
164 sequence_num = echo_ptr -> nx_icmpv6_echo_sequence_num;
165
166 /* Convert to host byte order, if little endian taget. */
167 NX_CHANGE_USHORT_ENDIAN(sequence_num);
168
169 /* Disable interrupts. */
170 TX_DISABLE
171
172 /* Pickup the head pointer and the suspended count. */
173 thread_ptr = ip_ptr -> nx_ip_icmp_ping_suspension_list;
174 suspended = ip_ptr -> nx_ip_icmp_ping_suspended_count;
175
176 /* Temporarily disable preemption. */
177 _tx_thread_preempt_disable++;
178
179 /* Restore interrupts. */
180 TX_RESTORE
181
182 /* Search through the suspended threads waiting for a ECHO (ping) response
183 in an attempt to find a matching sequence number. */
184 while (suspended--)
185 {
186
187 /* Determine if the sequence number matches a suspended thread. */
188 if (thread_ptr -> tx_thread_suspend_info == sequence_num)
189 {
190
191 /* Disable interrupts. */
192 TX_DISABLE
193
194 /* See if this is the only suspended thread on the list. */
195 if (thread_ptr == thread_ptr -> tx_thread_suspended_next)
196 {
197
198 /* Yes, the only suspended thread. */
199
200 /* Update the head pointer. */
201 ip_ptr -> nx_ip_icmp_ping_suspension_list = NX_NULL;
202 }
203 else
204 {
205
206 /* At least one more thread is on the same expiration list. */
207
208 /* Update the list head pointer. */
209 if (ip_ptr -> nx_ip_icmp_ping_suspension_list == thread_ptr)
210 {
211 ip_ptr -> nx_ip_icmp_ping_suspension_list = thread_ptr -> tx_thread_suspended_next;
212 }
213
214 /* Update the links of the adjacent threads. */
215 (thread_ptr -> tx_thread_suspended_next) -> tx_thread_suspended_previous =
216 thread_ptr -> tx_thread_suspended_previous;
217 (thread_ptr -> tx_thread_suspended_previous) -> tx_thread_suspended_next =
218 thread_ptr -> tx_thread_suspended_next;
219 }
220
221 /* Decrement the suspension count. */
222 ip_ptr -> nx_ip_icmp_ping_suspended_count--;
223
224 /* Prepare for resumption of the first thread. */
225
226 /* Clear cleanup routine to avoid timeout. */
227 thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
228
229 /* Temporarily disable preemption. */
230 _tx_thread_preempt_disable++;
231
232 /* Restore interrupts. */
233 TX_RESTORE
234
235 /* Adjust this packet to remove the ICMP header that is still in front of
236 the response message. */
237 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - (ULONG)sizeof(NX_ICMPV6_ECHO);
238 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_ICMPV6_ECHO);
239
240 /* Return this block pointer to the suspended thread waiting for
241 a block. */
242 *((NX_PACKET **)thread_ptr -> tx_thread_additional_suspend_info) = packet_ptr;
243
244 /* Add debug information. */
245 NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
246
247 /* Clear packet pointer so we don't try to release it below. */
248 packet_ptr = NX_NULL;
249
250 /* Put return status into the thread control block. */
251 thread_ptr -> tx_thread_suspend_status = NX_SUCCESS;
252
253 /* Resume thread. */
254 _tx_thread_system_resume(thread_ptr);
255
256 /* Get out of the loop. */
257 break;
258 }
259 else
260 {
261 /* Just move to the next suspended thread. */
262 thread_ptr = thread_ptr -> tx_thread_suspended_next;
263 }
264 }
265
266 /* Determine if no match was made and we just have to release the packet. */
267 if (packet_ptr)
268 {
269
270 #ifndef NX_DISABLE_ICMP_INFO
271
272 /* Increment the ICMP invalid packet error. */
273 ip_ptr -> nx_ip_icmp_invalid_packets++;
274 #endif /* NX_DISABLE_ICMP_INFO */
275
276 /* Yes, just release the packet. */
277 _nx_packet_release(packet_ptr);
278 }
279
280 /* Disable interrupts. */
281 TX_DISABLE
282
283 /* Release preemption disable. */
284 _tx_thread_preempt_disable--;
285
286 /* Restore interrupts. */
287 TX_RESTORE
288
289 /* Check for preemption. */
290 _tx_thread_system_preempt_check();
291 }
292
293
294 #endif /* FEATURE_NX_IPV6 */
295
296