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 Protocol (IP)                                              */
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_ip.h"
29 
30 
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _nx_ip_interface_status_check                       PORTABLE C      */
37 /*                                                           6.2.1        */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Yuxin Zhou, Microsoft Corporation                                   */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function polls the specified interface for the link state using*/
45 /*    thread sleep for the necessary conditions n the IP instance. Where  */
46 /*    the requested status exists only at the IP instance, for example    */
47 /*    NX_IP_INITIALIZE_DONE this service supplies the IP setting for that */
48 /*    status.                                                             */
49 /*                                                                        */
50 /*  INPUT                                                                 */
51 /*                                                                        */
52 /*    ip_ptr                                Pointer to IP instance        */
53 /*    interface_index                       Index to the interface        */
54 /*    needed_status                         Status needed request         */
55 /*    actual_status                         Pointer to return status area */
56 /*    wait_option                           Maximum suspension time       */
57 /*                                                                        */
58 /*  OUTPUT                                                                */
59 /*                                                                        */
60 /*    status                                Completion status             */
61 /*                                                                        */
62 /*  CALLS                                                                 */
63 /*                                                                        */
64 /*    (ip_link_driver)                      User supplied link driver     */
65 /*    tx_mutex_get                          Get protection mutex          */
66 /*    tx_mutex_put                          Put protection mutex          */
67 /*    tx_thread_sleep                       Sleep until events are        */
68 /*                                            satisfied                   */
69 /*                                                                        */
70 /*  CALLED BY                                                             */
71 /*                                                                        */
72 /*    Application                                                         */
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 /*  03-08-2023     Yajun Xia                Modified comment(s),          */
82 /*                                            added driver entry check,   */
83 /*                                            resulting in version 6.2.1  */
84 /*                                                                        */
85 /**************************************************************************/
_nx_ip_interface_status_check(NX_IP * ip_ptr,UINT interface_index,ULONG needed_status,ULONG * actual_status,ULONG wait_option)86 UINT  _nx_ip_interface_status_check(NX_IP *ip_ptr, UINT interface_index, ULONG needed_status,
87                                     ULONG *actual_status, ULONG wait_option)
88 {
89 
90 ULONG                  current_status;
91 NX_IP_DRIVER           driver_request;
92 ULONG                  return_value;
93 
94 #ifdef TX_ENABLE_EVENT_TRACE
95 TX_TRACE_BUFFER_ENTRY *trace_event;
96 ULONG                  trace_timestamp;
97 #endif
98 
99 
100     /* If trace is enabled, insert this event into the trace buffer.  */
101     NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_STATUS_CHECK, ip_ptr, needed_status, 0, wait_option, NX_TRACE_IP_EVENTS, &trace_event, &trace_timestamp);
102 
103     /* Loop to keep checking for the proper status bits.  */
104     for (;;)
105     {
106 
107         /* Clear the current status.  */
108         current_status =  0;
109 
110         /*  Process according to the status option specified.  */
111 
112         if (needed_status & NX_IP_INITIALIZE_DONE)
113         {
114 
115             /* Check for initialization complete.  */
116             if (ip_ptr -> nx_ip_initialize_done)
117             {
118 
119                 /* Yes, set the appropriate bit in the current status.  */
120                 current_status =  current_status | NX_IP_INITIALIZE_DONE;
121             }
122         }
123 
124 #ifndef NX_DISABLE_IPV4
125         if (needed_status & NX_IP_ADDRESS_RESOLVED)
126         {
127 
128             /* Check for a non-zero IP address.  */
129             if (ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_address)
130             {
131 
132                 /* Yes, set the appropriate bit in the current status.  */
133                 current_status =  current_status | NX_IP_ADDRESS_RESOLVED;
134             }
135         }
136 
137         if (needed_status & NX_IP_ARP_ENABLED)
138         {
139 
140             /* Check for ARP being enabled.  */
141             if (ip_ptr -> nx_ip_arp_periodic_update)
142             {
143                 /* Yes, set the appropriate bit in the current status.  */
144                 current_status =  current_status | NX_IP_ARP_ENABLED;
145             }
146         }
147 
148         if (needed_status & NX_IP_RARP_COMPLETE)
149         {
150 
151             /* This is effectively the same as the IP address resolved...  */
152 
153             /* Check for a non-zero IP address.  */
154             if (ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_address)
155             {
156 
157                 /* Yes, set the appropriate bit in the current status.  */
158                 current_status =  current_status | NX_IP_RARP_COMPLETE;
159             }
160         }
161 
162         if (needed_status & NX_IP_IGMP_ENABLED)
163         {
164 
165             /* Check for IGMP being enabled.  */
166             if (ip_ptr -> nx_ip_igmp_packet_receive)
167             {
168                 /* Yes, set the appropriate bit in the current status.  */
169                 current_status =  current_status | NX_IP_IGMP_ENABLED;
170             }
171         }
172 #endif /* !NX_DISABLE_IPV4  */
173 
174         if (needed_status & NX_IP_LINK_ENABLED)
175         {
176 
177             /* Get mutex protection.  */
178             tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
179 
180             /* Build the driver request structure.  */
181             driver_request.nx_ip_driver_ptr =         ip_ptr;
182             driver_request.nx_ip_driver_command =     NX_LINK_GET_STATUS;
183             driver_request.nx_ip_driver_return_ptr =  &return_value;
184             driver_request.nx_ip_driver_interface  =  &(ip_ptr -> nx_ip_interface[interface_index]);
185 
186             /* If trace is enabled, insert this event into the trace buffer.  */
187             NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_GET_STATUS, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
188 
189             /* Call link level driver.  */
190             if(ip_ptr -> nx_ip_interface[interface_index].nx_interface_link_driver_entry == NX_NULL)
191             {
192 
193                 /* Release mutex protection.  */
194                 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
195 
196                 return(NX_NOT_SUCCESSFUL);
197             }
198             (ip_ptr -> nx_ip_interface[interface_index].nx_interface_link_driver_entry)(&driver_request);
199 
200             /* If the driver does not recognize this keyword, we fall back to reading the IP link status.*/
201             /*lint -e{644} suppress variable might not be initialized, since "nx_ip_driver_status" was initialized in nx_interface_link_driver_entry. */
202             if (driver_request.nx_ip_driver_status != NX_SUCCESS)
203             {
204                 if (driver_request.nx_ip_driver_status == NX_UNHANDLED_COMMAND)
205                 {
206                     if (ip_ptr -> nx_ip_interface[interface_index].nx_interface_link_up)
207                     {
208                         current_status = current_status | NX_IP_LINK_ENABLED;
209                     }
210                 }
211             }
212             else
213             {
214 
215                 /* Check for a link up condition.  */
216                 /*lint -e{644} suppress variable might not be initialized, since "return_value" was initialized in nx_interface_link_driver_entry. */
217                 if (return_value == NX_TRUE)
218                 {
219 
220                     /* Yes, set the appropriate bit in the current status.  */
221                     current_status =  current_status | NX_IP_LINK_ENABLED;
222                 }
223             }
224 
225             /* Release mutex protection.  */
226             tx_mutex_put(&(ip_ptr -> nx_ip_protection));
227         }
228 
229         if (needed_status &  NX_IP_UDP_ENABLED)
230         {
231 
232             /* Check for UDP being enabled.  */
233             if (ip_ptr -> nx_ip_udp_packet_receive)
234             {
235                 /* Yes, set the appropriate bit in the current status.  */
236                 current_status =  current_status | NX_IP_UDP_ENABLED;
237             }
238         }
239 
240         if (needed_status & NX_IP_TCP_ENABLED)
241         {
242 
243             /* Check for TCP being enabled.  */
244             if (ip_ptr -> nx_ip_tcp_packet_receive)
245             {
246                 /* Yes, set the appropriate bit in the current status.  */
247                 current_status =  current_status | NX_IP_TCP_ENABLED;
248             }
249         }
250 
251         if (needed_status & NX_IP_INTERFACE_LINK_ENABLED)
252         {
253 
254             /* Get mutex protection.  */
255             tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
256 
257             /* Build the driver request structure.  */
258             driver_request.nx_ip_driver_ptr =         ip_ptr;
259             driver_request.nx_ip_driver_command =     NX_LINK_GET_STATUS;
260             driver_request.nx_ip_driver_return_ptr =  &return_value;
261             driver_request.nx_ip_driver_interface  =  &(ip_ptr -> nx_ip_interface[interface_index]);
262 
263             /* If trace is enabled, insert this event into the trace buffer.  */
264             NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_GET_STATUS, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
265 
266             /* Call link level driver.  */
267             if(ip_ptr -> nx_ip_interface[interface_index].nx_interface_link_driver_entry == NX_NULL)
268             {
269 
270                 /* Release mutex protection.  */
271                 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
272 
273                 return(NX_NOT_SUCCESSFUL);
274             }
275             (ip_ptr -> nx_ip_interface[interface_index].nx_interface_link_driver_entry)(&driver_request);
276 
277             /* If the driver does not recognize this keyword, we fall back to reading the IP link status.*/
278             /*lint -e{644} suppress variable might not be initialized, since "nx_ip_driver_status" was initialized in nx_interface_link_driver_entry. */
279             if (driver_request.nx_ip_driver_status != NX_SUCCESS)
280             {
281                 if (driver_request.nx_ip_driver_status == NX_UNHANDLED_COMMAND)
282                 {
283                     if (ip_ptr -> nx_ip_interface[interface_index].nx_interface_link_up)
284                     {
285                         current_status = current_status | NX_IP_INTERFACE_LINK_ENABLED;
286                     }
287                 }
288             }
289             else
290             {
291 
292                 /* Check for a link up condition.  */
293                 /*lint -e{644} suppress variable might not be initialized, since "return_value" was initialized in nx_interface_link_driver_entry. */
294                 if (return_value == NX_TRUE)
295                 {
296 
297                     /* Yes, set the appropriate bit in the current status.  */
298                     current_status =  current_status | NX_IP_INTERFACE_LINK_ENABLED;
299                 }
300             }
301 
302             /* Release mutex protection.  */
303             tx_mutex_put(&(ip_ptr -> nx_ip_protection));
304         }
305 
306         /* Determine if current status is the same.  If so, break out
307            of this polling loop.  */
308         if (current_status == needed_status)
309         {
310             break;
311         }
312 
313         /* Check for suspension request.  */
314         if (wait_option)
315         {
316 
317             /* Decrease the wait time and sleep.  */
318             if (wait_option > NX_IP_STATUS_CHECK_WAIT_TIME)
319             {
320                 wait_option -= NX_IP_STATUS_CHECK_WAIT_TIME;
321             }
322             else
323             {
324                 wait_option = 0;
325             }
326 
327             /* Sleep for a tick and check again.  */
328             tx_thread_sleep(NX_IP_STATUS_CHECK_WAIT_TIME);
329         }
330         else
331         {
332 
333             /* Get out of the loop.  */
334             break;
335         }
336     }
337 
338     /* Place the current status in the return destination.  */
339     *actual_status =  current_status;
340 
341     /* Update the trace event with the status.  */
342     NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_IP_STATUS_CHECK, 0, 0, current_status, 0);
343 
344     /* Determine what status to return.  */
345     if (needed_status == current_status)
346     {
347 
348         /* Return a success.  */
349         return(NX_SUCCESS);
350     }
351     else
352     {
353 
354         /* Return an error.  */
355         return(NX_NOT_SUCCESSFUL);
356     }
357 }
358 
359