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_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_reply PORTABLE C */
43 /* 6.1 */
44 /* AUTHOR */
45 /* */
46 /* Yuxin Zhou, Microsoft Corporation */
47 /* */
48 /* DESCRIPTION */
49 /* */
50 /* This function processes incoming echo reply message. It matches */
51 /* the thread that has pending echo request, and unblocks the thread. */
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_packet_release Release packet back to pool */
65 /* _tx_thread_system_resume Resume the specified thread */
66 /* _tx_thread_system_preempt_check Check for preemption */
67 /* */
68 /* CALLED BY */
69 /* */
70 /* _nx_icmpv4_packet_process Main ICMP packet pocess */
71 /* */
72 /* RELEASE HISTORY */
73 /* */
74 /* DATE NAME DESCRIPTION */
75 /* */
76 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
77 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
78 /* resulting in version 6.1 */
79 /* */
80 /**************************************************************************/
_nx_icmpv4_process_echo_reply(NX_IP * ip_ptr,NX_PACKET * packet_ptr)81 VOID _nx_icmpv4_process_echo_reply(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
82 {
83
84 TX_INTERRUPT_SAVE_AREA
85
86 TX_THREAD *thread_ptr;
87 ULONG suspended;
88 USHORT sequence_num;
89 NX_ICMPV4_ECHO *echo_ptr;
90
91
92 /* Add debug information. */
93 NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
94
95
96 /* Point to the ICMP message header. */
97 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
98 echo_ptr = (NX_ICMPV4_ECHO *)packet_ptr -> nx_packet_prepend_ptr;
99
100 #ifndef NX_DISABLE_ICMP_INFO
101
102 /* Increment the ICMP responses received count. */
103 ip_ptr -> nx_ip_ping_responses_received++;
104 #endif
105
106 /* Pickup sequence number. */
107 sequence_num = echo_ptr -> nx_icmpv4_echo_sequence_num;
108
109 /* Convert to host byte order, if little endian taget. */
110 NX_CHANGE_USHORT_ENDIAN(sequence_num);
111
112 /* Disable interrupts. */
113 TX_DISABLE
114
115 /* Pickup the head pointer and the suspended count. */
116 thread_ptr = ip_ptr -> nx_ip_icmp_ping_suspension_list;
117 suspended = ip_ptr -> nx_ip_icmp_ping_suspended_count;
118
119 /* Temporarily disable preemption. */
120 _tx_thread_preempt_disable++;
121
122 /* Restore interrupts. */
123 TX_RESTORE
124
125 /* Search through the suspended threads waiting for a ECHO (ping) response
126 in an attempt to find a matching sequence number. */
127 while (suspended--)
128 {
129
130 /* Determine if the sequence number matches a suspended thread. */
131 if ((USHORT)(thread_ptr -> tx_thread_suspend_info) == sequence_num)
132 {
133
134 /* Disable interrupts. */
135 TX_DISABLE
136
137 /* See if this is the only suspended thread on the list. */
138 if (thread_ptr == thread_ptr -> tx_thread_suspended_next)
139 {
140
141 /* Yes, the only suspended thread. */
142
143 /* Update the head pointer. */
144 ip_ptr -> nx_ip_icmp_ping_suspension_list = NX_NULL;
145 }
146 else
147 {
148
149 /* At least one more thread is on the same expiration list. */
150
151 /* Update the list head pointer. */
152 if (ip_ptr -> nx_ip_icmp_ping_suspension_list == thread_ptr)
153 {
154 ip_ptr -> nx_ip_icmp_ping_suspension_list = thread_ptr -> tx_thread_suspended_next;
155 }
156
157 /* Update the links of the adjacent threads. */
158 (thread_ptr -> tx_thread_suspended_next) -> tx_thread_suspended_previous =
159 thread_ptr -> tx_thread_suspended_previous;
160 (thread_ptr -> tx_thread_suspended_previous) -> tx_thread_suspended_next =
161 thread_ptr -> tx_thread_suspended_next;
162 }
163
164 /* Decrement the suspension count. */
165 ip_ptr -> nx_ip_icmp_ping_suspended_count--;
166
167 /* Prepare for resumption of the first thread. */
168
169 /* Clear cleanup routine to avoid timeout. */
170 thread_ptr -> tx_thread_suspend_cleanup = TX_NULL;
171
172 /* Temporarily disable preemption. */
173 _tx_thread_preempt_disable++;
174
175 /* Restore interrupts. */
176 TX_RESTORE
177
178 /* Adjust this packet to remove the ICMP header that is still in front of
179 the response message. */
180 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - (ULONG)sizeof(NX_ICMPV4_ECHO);
181 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_ICMPV4_ECHO);
182
183 /* Return this block pointer to the suspended thread waiting for
184 a block. */
185 *((NX_PACKET **)thread_ptr -> tx_thread_additional_suspend_info) = packet_ptr;
186
187 /* Clear packet pointer so we don't try to release it below. */
188 packet_ptr = NX_NULL;
189
190 /* Put return status into the thread control block. */
191 thread_ptr -> tx_thread_suspend_status = NX_SUCCESS;
192
193 /* Resume thread. */
194 _tx_thread_system_resume(thread_ptr);
195
196 /* Get out of the loop. */
197 break;
198 }
199 else
200 {
201 /* Just move to the next suspended thread. */
202 thread_ptr = thread_ptr -> tx_thread_suspended_next;
203 }
204 }
205
206 /* Determine if no match was made and we just have to release the packet. */
207 if (packet_ptr)
208 {
209
210 #ifndef NX_DISABLE_ICMP_INFO
211
212 /* Increment the ICMP invalid packet error. */
213 ip_ptr -> nx_ip_icmp_invalid_packets++;
214 #endif /* NX_DISABLE_ICMP_INFO */
215
216 /* Yes, just release the packet. */
217 _nx_packet_release(packet_ptr);
218 }
219
220 /* Disable interrupts. */
221 TX_DISABLE
222
223 /* Release preemption disable. */
224 _tx_thread_preempt_disable--;
225
226 /* Restore interrupts. */
227 TX_RESTORE
228
229 /* Check for preemption. */
230 _tx_thread_system_preempt_check();
231 }
232 #endif /* !NX_DISABLE_IPV4 */
233
234