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 Protocol (IP) */
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_ip.h"
30 #include "nx_icmp.h"
31 #include "nx_igmp.h"
32 #ifdef FEATURE_NX_IPV6
33 #include "nx_ipv6.h"
34 #include "nx_icmpv6.h"
35 #endif /* FEATURE_NX_IPV6 */
36
37 #ifdef NX_IPSEC_ENABLE
38 #include "nx_ipsec.h"
39 #endif /* FEATURE_IPSEC_ENABLE */
40
41 /**************************************************************************/
42 /* */
43 /* FUNCTION RELEASE */
44 /* */
45 /* _nx_ip_thread_entry PORTABLE C */
46 /* 6.1.8 */
47 /* AUTHOR */
48 /* */
49 /* Yuxin Zhou, Microsoft Corporation */
50 /* */
51 /* DESCRIPTION */
52 /* */
53 /* This function is the entry point for each IP's helper thread. The */
54 /* IP helper thread is responsible for periodic ARP requests, */
55 /* reassembling fragmented IP messages, and helping with TCP */
56 /* protocol. */
57 /* */
58 /* Note that the priority of this function is determined by the IP */
59 /* create service. */
60 /* */
61 /* INPUT */
62 /* */
63 /* ip_ptr_value Pointer to IP control block */
64 /* */
65 /* OUTPUT */
66 /* */
67 /* status Completion status */
68 /* */
69 /* CALLS */
70 /* */
71 /* tx_event_flags_get Suspend on event flags that */
72 /* are used to signal this */
73 /* thread what to do */
74 /* tx_mutex_get Obtain protection mutex */
75 /* tx_mutex_put Release protection mutex */
76 /* (nx_ip_driver_deferred_packet_handler)Optional deferred packet */
77 /* processing routine */
78 /* _nx_ip_packet_receive IP receive packet processing */
79 /* _nx_ipv6_multicast_join Join IPv6 multicast group */
80 /* (nx_arp_queue_process) ARP receive queue processing */
81 /* (nx_ip_arp_periodic_update) ARP periodic update processing*/
82 /* (nx_ip_rarp_periodic_update) RARP periodic processing */
83 /* (nx_ip_fragment_assembly) IP fragment processing */
84 /* (nx_ip_fragment_timeout_check) Fragment timeout checking */
85 /* (nx_ip_icmp_queue_process) ICMP message queue processing */
86 /* (nx_ip_igmp_queue_process) IGMP message queue processing */
87 /* (nx_ip_igmp_periodic_processing) IGMP periodic processing */
88 /* (nx_ip_tcp_queue_process) TCP message queue processing */
89 /* (nx_ip_tcp_periodic_processing) TCP periodic processing */
90 /* (nx_tcp_deferred_cleanup_check) TCP deferred cleanup check */
91 /* _nx_ipsec_sa_lifetime_tick IPsec lifetime tick update */
92 /* (ip_link_driver) User supplied link driver */
93 /* _nx_ipsec_hw_packet_process IPsec HW packet process */
94 /* _nx_icmpv6_send_ns Send Neighbor Solicitation */
95 /* message */
96 /* (nx_nd_cache_fast_periodic_update) ND Cache fast periodic service*/
97 /* routine */
98 /* (nx_nd_cache_slow_periodic_update) ND Cache slow periodic service*/
99 /* routine */
100 /* _nxd_ipv6_prefix_router_timer_tick IPv6 Preifx service routine */
101 /* _nxd_ipv6_router_solicitation_check IPv6 RS service routine */
102 /* (nx_destination_table_periodic_update) */
103 /* Destination table service */
104 /* routine. */
105 /* */
106 /* CALLED BY */
107 /* */
108 /* ThreadX Scheduler */
109 /* */
110 /* RELEASE HISTORY */
111 /* */
112 /* DATE NAME DESCRIPTION */
113 /* */
114 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
115 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
116 /* resulting in version 6.1 */
117 /* 08-02-2021 Yuxin Zhou Modified comment(s), and */
118 /* supported TCP/IP offload, */
119 /* resulting in version 6.1.8 */
120 /* */
121 /**************************************************************************/
_nx_ip_thread_entry(ULONG ip_ptr_value)122 VOID _nx_ip_thread_entry(ULONG ip_ptr_value)
123 {
124
125 TX_INTERRUPT_SAVE_AREA
126
127 NX_IP_DRIVER driver_request;
128 NX_IP *ip_ptr;
129 ULONG ip_events;
130 NX_PACKET *packet_ptr;
131 UINT i;
132 UINT index;
133 ULONG foo;
134 #ifdef FEATURE_NX_IPV6
135 NXD_IPV6_ADDRESS *interface_ipv6_address;
136 #endif /* FEATURE_NX_IPV6 */
137
138
139 /* Setup IP pointer. */
140 NX_THREAD_EXTENSION_PTR_GET(ip_ptr, NX_IP, ip_ptr_value)
141
142 /* Obtain the IP internal mutex before calling the driver. */
143 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
144
145 /* Set the IP initialization done flag to true. */
146 ip_ptr -> nx_ip_initialize_done = NX_TRUE;
147
148 /* Loop through all physical interfaces to initialize and enable the hardware. */
149 for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++)
150 {
151
152 /* Is this a valid interface with a link driver associated with it? */
153 if ((ip_ptr -> nx_ip_interface[i].nx_interface_valid) && (ip_ptr -> nx_ip_interface[i].nx_interface_link_driver_entry))
154 {
155
156 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
157 /* Clear capability flag first. */
158 ip_ptr -> nx_ip_interface[i].nx_interface_capability_flag = 0;
159 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
160
161
162 ip_ptr -> nx_ip_interface[i].nx_interface_link_up = NX_TRUE;
163
164 /* Yes; attach the interface to the device. */
165 driver_request.nx_ip_driver_ptr = ip_ptr;
166 driver_request.nx_ip_driver_command = NX_LINK_INTERFACE_ATTACH;
167 driver_request.nx_ip_driver_interface = &(ip_ptr -> nx_ip_interface[i]);
168 (ip_ptr -> nx_ip_interface[i].nx_interface_link_driver_entry)(&driver_request);
169
170 #ifdef NX_ENABLE_TCPIP_OFFLOAD
171 if (ip_ptr -> nx_ip_interface[i].nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_TCPIP_OFFLOAD)
172 {
173
174 /* Set checksum capability for TCP/IP offload interface. */
175 ip_ptr -> nx_ip_interface[i].nx_interface_capability_flag |= NX_INTERFACE_CAPABILITY_CHECKSUM_ALL;
176 }
177 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
178
179 /* Call the link driver to initialize the hardware. Among other
180 responsibilities, the driver is required to provide the
181 Maximum Transfer Unit (MTU) for the physical layer. The MTU
182 should represent the actual physical layer transfer size
183 less the physical layer headers and trailers. */
184 driver_request.nx_ip_driver_ptr = ip_ptr;
185 driver_request.nx_ip_driver_command = NX_LINK_INITIALIZE;
186
187 /* If trace is enabled, insert this event into the trace buffer. */
188 NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_INITIALIZE, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
189
190 /*
191 When an IP instance is created, the first interface (nx_ip_interface[0]) is configured using parameters
192 provided in the IP create call.
193
194 When IP thread runs, it invokes the first interface link driver for link initialization.
195 */
196 (ip_ptr -> nx_ip_interface[i].nx_interface_link_driver_entry)(&driver_request);
197
198 /* Call the link driver again to enable the interface. */
199 driver_request.nx_ip_driver_ptr = ip_ptr;
200 driver_request.nx_ip_driver_command = NX_LINK_ENABLE;
201
202 /* If trace is enabled, insert this event into the trace buffer. */
203 NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_LINK_ENABLE, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
204
205 (ip_ptr -> nx_ip_interface[i].nx_interface_link_driver_entry)(&driver_request);
206
207 #ifdef FEATURE_NX_IPV6
208 /* For ever IPv6 address on this interface, set the Solicitated Multicast address. */
209 interface_ipv6_address = ip_ptr -> nx_ip_interface[i].nxd_interface_ipv6_address_list_head;
210
211 while (interface_ipv6_address)
212 {
213 ULONG multicast_address[4];
214
215 SET_SOLICITED_NODE_MULTICAST_ADDRESS(multicast_address, interface_ipv6_address -> nxd_ipv6_address);
216 _nx_ipv6_multicast_join(ip_ptr, multicast_address, &ip_ptr -> nx_ip_interface[i]);
217 interface_ipv6_address = interface_ipv6_address -> nxd_ipv6_address_next;
218 }
219 #ifndef NX_DISABLE_ICMPV6_ROUTER_SOLICITATION
220 if (ip_ptr -> nx_ipv6_packet_receive)
221 {
222 ULONG address[4];
223
224 /* Create the all-node multicast group address, */
225 address[0] = 0xFF020000;
226 address[1] = 0;
227 address[2] = 0;
228 address[3] = 1;
229
230
231 /* Join all-node multicast group. */
232 _nx_ipv6_multicast_join(ip_ptr, address, &ip_ptr -> nx_ip_interface[i]);
233 }
234 #endif
235 #endif
236 }
237 }
238
239 /* Loop to process events for this IP instance. */
240 for (;;)
241 {
242
243 /* Release the IP internal mutex. */
244 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
245
246 /* Pickup IP event flags. */
247 tx_event_flags_get(&(ip_ptr -> nx_ip_events), NX_IP_ALL_EVENTS, TX_OR_CLEAR, &ip_events, TX_WAIT_FOREVER);
248
249 /* Obtain the IP internal mutex before processing the IP event. */
250 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
251
252 #ifdef NX_DRIVER_DEFERRED_PROCESSING
253 /* Check for any packets deferred by the Driver. */
254 /*lint -e{644} suppress variable might not be initialized, since "ip_events" was initialized in tx_event_flags_get. */
255 if (ip_events & NX_IP_DRIVER_PACKET_EVENT)
256 {
257
258 /* Loop to process all deferred packet requests. */
259 while (ip_ptr -> nx_ip_driver_deferred_packet_head)
260 {
261 /* Remove the first packet and process it! */
262
263 /* Disable interrupts. */
264 TX_DISABLE
265
266 /* Pickup the first packet. */
267 packet_ptr = ip_ptr -> nx_ip_driver_deferred_packet_head;
268
269 /* Move the head pointer to the next packet. */
270 ip_ptr -> nx_ip_driver_deferred_packet_head = packet_ptr -> nx_packet_queue_next;
271
272 /* Check for end of deferred processing queue. */
273 if (ip_ptr -> nx_ip_driver_deferred_packet_head == NX_NULL)
274 {
275
276 /* Yes, the queue is empty. Set the tail pointer to NULL. */
277 ip_ptr -> nx_ip_driver_deferred_packet_tail = NX_NULL;
278 }
279
280 /* Restore interrupts. */
281 TX_RESTORE
282
283 /* Add debug information. */
284 NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
285
286 /* make sure that there is a deferred processing function */
287 if (ip_ptr -> nx_ip_driver_deferred_packet_handler)
288 {
289 /* Call the actual Deferred packet processing function. */
290 (ip_ptr -> nx_ip_driver_deferred_packet_handler)(ip_ptr, packet_ptr);
291 }
292 }
293
294 /* Determine if there is anything else to do in the loop. */
295 ip_events = ip_events & ~(NX_IP_DRIVER_PACKET_EVENT);
296 if (!ip_events)
297 {
298 continue;
299 }
300 }
301 #endif
302
303 /* Check for an IP receive packet event. */
304 /*lint -e{644} suppress variable might not be initialized, since "ip_events" was initialized by tx_event_flags_get. */
305 if (ip_events & NX_IP_RECEIVE_EVENT)
306 {
307
308 /* Loop to process all deferred packet requests. */
309 while (ip_ptr -> nx_ip_deferred_received_packet_head)
310 {
311
312 /* Remove the first packet and process it! */
313
314 /* Disable interrupts. */
315 TX_DISABLE
316
317 /* Pickup the first packet. */
318 packet_ptr = ip_ptr -> nx_ip_deferred_received_packet_head;
319
320 /* Move the head pointer to the next packet. */
321 ip_ptr -> nx_ip_deferred_received_packet_head = packet_ptr -> nx_packet_queue_next;
322
323 /* Check for end of deferred processing queue. */
324 if (ip_ptr -> nx_ip_deferred_received_packet_head == NX_NULL)
325 {
326
327 /* Yes, the queue is empty. Set the tail pointer to NULL. */
328 ip_ptr -> nx_ip_deferred_received_packet_tail = NX_NULL;
329 }
330
331 /* Restore interrupts. */
332 TX_RESTORE
333
334 /* Call the actual IP packet receive function. */
335 _nx_ip_packet_receive(ip_ptr, packet_ptr);
336 }
337
338 /* Determine if there is anything else to do in the loop. */
339 ip_events = ip_events & ~(NX_IP_RECEIVE_EVENT);
340 if (!ip_events)
341 {
342 continue;
343 }
344 }
345
346 /* Check for a TCP message event. */
347 if (ip_events & NX_IP_TCP_EVENT)
348 {
349
350 /* Process the TCP packet queue. */
351 (ip_ptr -> nx_ip_tcp_queue_process)(ip_ptr);
352
353 /* Determine if there is anything else to do in the loop. */
354 ip_events = ip_events & ~(NX_IP_TCP_EVENT);
355 if (!ip_events)
356 {
357 continue;
358 }
359 }
360
361 /* Check for a fast TCP event. */
362 if (ip_events & NX_IP_FAST_EVENT)
363 {
364
365 /* Start DAD for the link local address by sending off the first solicitation immediately
366 while subsequent solicitations will occur on the next slow event. */
367 #ifdef FEATURE_NX_IPV6
368 #ifndef NX_DISABLE_IPV6_DAD
369
370 if (ip_ptr -> nx_ip_icmpv6_packet_process)
371 {
372
373 /* Proceed with DAD check only if ICMPv6 is enabled. */
374 for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++)
375 {
376
377 interface_ipv6_address = ip_ptr -> nx_ip_interface[i].nxd_interface_ipv6_address_list_head;
378
379 if (interface_ipv6_address &&
380 interface_ipv6_address -> nxd_ipv6_address_DupAddrDetectTransmit == NX_IPV6_DAD_TRANSMITS)
381 {
382
383
384 /* No. This address is still under DAD. Transmit a NS */
385 /* Note that the 2nd last parameter sendUnicast is set to Zero. In this case
386 the last arg NDCacheEntry is not being used in _nx_icmpv6_send_ns. */
387 _nx_icmpv6_send_ns(ip_ptr,
388 interface_ipv6_address -> nxd_ipv6_address,
389 0, interface_ipv6_address, 0, &ip_ptr -> nx_ipv6_nd_cache[0]);
390
391 interface_ipv6_address -> nxd_ipv6_address_DupAddrDetectTransmit--;
392 }
393 }
394 }
395 #endif
396
397 if (ip_ptr -> nx_nd_cache_fast_periodic_update)
398 {
399 /* Run the ND Cache update routine. This is a 100 millisecond timer */
400 ip_ptr -> nx_nd_cache_fast_periodic_update(ip_ptr);
401 }
402
403 #endif /* FEATURE_NX_IPV6 */
404
405 /* Process the fast TCP processing. */
406 if (ip_ptr -> nx_ip_tcp_fast_periodic_processing)
407 {
408 (ip_ptr -> nx_ip_tcp_fast_periodic_processing)(ip_ptr);
409 }
410
411 /* Determine if there is anything else to do in the loop. */
412 ip_events = ip_events & ~(NX_IP_FAST_EVENT);
413 if (!ip_events)
414 {
415 continue;
416 }
417 }
418
419 /* Check for a periodic events. */
420 if (ip_events & NX_IP_PERIODIC_EVENT)
421 {
422
423 #ifndef NX_DISABLE_IPV4
424 /* Process the ARP periodic update, if ARP has been enabled. */
425 if (ip_ptr -> nx_ip_arp_periodic_update)
426 {
427 (ip_ptr -> nx_ip_arp_periodic_update)(ip_ptr);
428 }
429
430 /* Process the RARP periodic update, if RARP has been enabled. */
431 if (ip_ptr -> nx_ip_rarp_periodic_update)
432 {
433 (ip_ptr -> nx_ip_rarp_periodic_update)(ip_ptr);
434 }
435
436 /* Process IGMP periodic events, if IGMP has been enabled. */
437 if (ip_ptr -> nx_ip_igmp_periodic_processing)
438 {
439 (ip_ptr -> nx_ip_igmp_periodic_processing)(ip_ptr);
440 }
441 #endif /* !NX_DISABLE_IPV4 */
442
443 /* Process IP fragmentation timeouts, if IP fragmenting has been
444 enabled. */
445 if (ip_ptr -> nx_ip_fragment_timeout_check)
446 {
447 (ip_ptr -> nx_ip_fragment_timeout_check)(ip_ptr);
448 }
449
450 /* Process TCP periodic events, if TCP has been enabled. */
451 if (ip_ptr -> nx_ip_tcp_periodic_processing)
452 {
453 (ip_ptr -> nx_ip_tcp_periodic_processing)(ip_ptr);
454 }
455 #ifdef FEATURE_NX_IPV6
456 /* Process IPv6 events, such as DAD... */
457 #ifndef NX_DISABLE_IPV6_DAD
458 if (ip_ptr -> nx_ip_icmpv6_packet_process)
459 {
460 _nx_icmpv6_perform_DAD(ip_ptr);
461 }
462 #endif /* NX_DISABLE_IPV6_DAD */
463 if (ip_ptr -> nx_nd_cache_slow_periodic_update)
464 {
465 /* Run the ND Cache update routine. This is a 1 second timer */
466 ip_ptr -> nx_nd_cache_slow_periodic_update(ip_ptr);
467 }
468
469 _nxd_ipv6_prefix_router_timer_tick(ip_ptr);
470 #ifndef NX_DISABLE_ICMPV6_ROUTER_SOLICITATION
471 _nxd_ipv6_router_solicitation_check(ip_ptr);
472 #endif
473
474 #ifdef NX_IPSEC_ENABLE
475 _nx_ipsec_sa_lifetime_tick(ip_ptr);
476 #endif /* NX_IPSEC_ENABLE */
477
478 #ifdef NX_ENABLE_IPV6_PATH_MTU_DISCOVERY
479
480 if (ip_ptr -> nx_destination_table_periodic_update)
481 {
482
483 /* Run the Destination table update routine. This will update the timers
484 on destination table entries' MTU data, and if expired will initiate
485 MTU path discovery. */
486 ip_ptr -> nx_destination_table_periodic_update(ip_ptr);
487 }
488 #endif /* NX_ENABLE_IPV6_PATH_MTU_DISCOVERY */
489
490 #endif /* FEATURE_NX_IPV6 */
491 /* Determine if there is anything else to do in the loop. */
492 ip_events = ip_events & ~(NX_IP_PERIODIC_EVENT);
493 if (!ip_events)
494 {
495 continue;
496 }
497 }
498
499 #ifdef NX_IPSEC_ENABLE
500 if (ip_events & NX_IP_HW_DONE_EVENT)
501 {
502
503 /* Process the hw_done_packet queue. */
504 _nx_ipsec_hw_packet_process(ip_ptr);
505 }
506 #endif /* NX_IPSEC_ENABLE */
507
508 #ifndef NX_DISABLE_IPV4
509 /* Check for an ARP receive packet event. */
510 if ((ip_events & NX_IP_ARP_REC_EVENT) && (ip_ptr -> nx_ip_arp_queue_process))
511 {
512
513 /* Process the ARP queue. */
514 (ip_ptr -> nx_ip_arp_queue_process)(ip_ptr);
515 }
516
517 /* Check for an RARP receive packet event. */
518 if ((ip_events & NX_IP_RARP_REC_EVENT) && (ip_ptr -> nx_ip_rarp_queue_process))
519 {
520
521 /* Process the RARP queue. */
522 (ip_ptr -> nx_ip_rarp_queue_process)(ip_ptr);
523 }
524
525 /* Check for an IGMP message event. */
526 if (ip_events & NX_IP_IGMP_EVENT)
527 {
528
529 /* Process the ICMP packet queue. */
530 (ip_ptr -> nx_ip_igmp_queue_process)(ip_ptr);
531 }
532
533 /* Check for an IGMP enable event. */
534 if (ip_events & NX_IP_IGMP_ENABLE_EVENT)
535 {
536
537 /* Call the associated driver for this IP instance to register the "all hosts"
538 multicast address. */
539 for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++)
540 {
541 /* Enable the hardware for IGMP for all valid interfaces. */
542 if (ip_ptr -> nx_ip_interface[i].nx_interface_valid)
543 {
544 driver_request.nx_ip_driver_ptr = ip_ptr;
545 driver_request.nx_ip_driver_command = NX_LINK_MULTICAST_JOIN;
546 driver_request.nx_ip_driver_physical_address_msw = NX_IP_MULTICAST_UPPER;
547 /*lint -e{835} -e{845} suppress operating on zero. */
548 driver_request.nx_ip_driver_physical_address_lsw = NX_IP_MULTICAST_LOWER | (NX_ALL_HOSTS_ADDRESS & NX_IP_MULTICAST_MASK);
549 driver_request.nx_ip_driver_interface = &(ip_ptr -> nx_ip_interface[i]);
550
551 /* If trace is enabled, insert this event into the trace buffer. */
552 NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_MULTICAST_JOIN, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
553
554 (ip_ptr -> nx_ip_interface[i].nx_interface_link_driver_entry)(&driver_request);
555 }
556 }
557 }
558 #endif /* !NX_DISABLE_IPV4 */
559
560 /* Check for an IP unfragment event. */
561 if (ip_events & NX_IP_UNFRAG_EVENT)
562 {
563
564 /* Process the IP fragment reassemble, if fragment has been enabled. */
565 if (ip_ptr -> nx_ip_fragment_assembly)
566 {
567 (ip_ptr -> nx_ip_fragment_assembly)(ip_ptr);
568 }
569 }
570
571 #ifndef NX_DISABLE_IPV4
572 /* Check for an ICMP message event. */
573 if (ip_events & NX_IP_ICMP_EVENT)
574 {
575
576 /* Process the ICMP packet queue. */
577 (ip_ptr -> nx_ip_icmp_queue_process)(ip_ptr);
578 }
579 #endif /* NX_DISABLE_IPV4 */
580
581 /* Check for a deferred processing request from the driver. */
582 if (ip_events & NX_IP_DRIVER_DEFERRED_EVENT)
583 {
584
585 /* Go through each valid interface. */
586 for (index = 0; index < NX_MAX_PHYSICAL_INTERFACES; index++)
587 {
588 if (ip_ptr -> nx_ip_interface[index].nx_interface_valid)
589 {
590
591 /* Yes, there is a deferred processing event from the driver. The only valid information
592 fields are the IP pointer and the command. */
593 driver_request.nx_ip_driver_ptr = ip_ptr;
594 driver_request.nx_ip_driver_command = NX_LINK_DEFERRED_PROCESSING;
595 driver_request.nx_ip_driver_interface = &(ip_ptr -> nx_ip_interface[index]);
596 driver_request.nx_ip_driver_return_ptr = &foo;
597
598 (ip_ptr -> nx_ip_interface[index].nx_interface_link_driver_entry)(&driver_request);
599 }
600 }
601 }
602
603 /* Check for a deferred TCP cleanup processing request from the driver. */
604 if (ip_events & NX_IP_TCP_CLEANUP_DEFERRED)
605 {
606
607 /* Yes, there is a deferred cleanup processing event. Call the TCP deferred cleanup
608 processing function. */
609 (ip_ptr -> nx_tcp_deferred_cleanup_check)(ip_ptr);
610 }
611
612 /* Check for a link status change request from the driver. */
613 if (ip_events & NX_IP_LINK_STATUS_EVENT)
614 {
615
616 /* Yes, there is a link status change event. Call the deferred link status processing function. */
617 _nx_ip_deferred_link_status_process(ip_ptr);
618 }
619 }
620 }
621
622