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