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 /**   Address Resolution Protocol (ARP)                                   */
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_arp.h"
30 #include "nx_packet.h"
31 
32 #ifndef NX_DISABLE_IPV4
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _nx_arp_periodic_update                             PORTABLE C      */
38 /*                                                           6.1          */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Yuxin Zhou, Microsoft Corporation                                   */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function processes ARP periodic update requests by walking     */
46 /*    through the dynamic ARP list to see if another ARP request needs to */
47 /*    be sent.                                                            */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    ip_ptr                                Pointer to IP instance        */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    None                                                                */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    _nx_arp_packet_send                   Send periodic ARP request out */
60 /*    _nx_packet_transmit_release           Release queued packet         */
61 /*                                                                        */
62 /*  CALLED BY                                                             */
63 /*                                                                        */
64 /*    _nx_ip_thread_entry                   IP helper thread              */
65 /*                                                                        */
66 /*  RELEASE HISTORY                                                       */
67 /*                                                                        */
68 /*    DATE              NAME                      DESCRIPTION             */
69 /*                                                                        */
70 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
71 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
72 /*                                            resulting in version 6.1    */
73 /*                                                                        */
74 /**************************************************************************/
_nx_arp_periodic_update(NX_IP * ip_ptr)75 VOID  _nx_arp_periodic_update(NX_IP *ip_ptr)
76 {
77 
78 TX_INTERRUPT_SAVE_AREA
79 
80 ULONG      i;
81 NX_ARP    *arp_entry;
82 NX_PACKET *packet_ptr;
83 NX_PACKET *next_packet_ptr;
84 
85 
86     /* Pickup pointer to ARP dynamic list.  */
87     arp_entry =  ip_ptr -> nx_ip_arp_dynamic_list;
88 
89     /* Loop through the active ARP entries to see if they need updating.  */
90     for (i = 0; i < ip_ptr -> nx_ip_arp_dynamic_active_count; i++)
91     {
92 
93         /* Check this ARP entry to see if it need updating.  */
94         if (arp_entry -> nx_arp_entry_next_update)
95         {
96 
97             /* Decrement the next update field.  */
98             arp_entry -> nx_arp_entry_next_update--;
99 
100             /* Determine if an ARP expiration is present.  */
101             if (!arp_entry -> nx_arp_entry_next_update)
102             {
103 
104                 /* Yes, an ARP expiration is present.   */
105 
106                 /* Determine if the retry counter has been exceeded.  */
107                 if (arp_entry -> nx_arp_retries == NX_ARP_MAXIMUM_RETRIES)
108                 {
109 
110                     /* The number of retries has been exceeded. The entry is removed
111                        from the active list and any queued packet is released.  */
112 
113                     /* Disable interrupts.  */
114                     TX_DISABLE
115 
116                     /* This ARP entry has expired, remove it from the active ARP list.  Check to make
117                        sure it is still active.  */
118                     if (arp_entry -> nx_arp_active_list_head)
119                     {
120 
121                         /* Determine if this is the only ARP entry on the list.  */
122                         if (arp_entry == arp_entry -> nx_arp_active_next)
123                         {
124 
125                             /* Remove the entry from the list.  */
126                             *(arp_entry -> nx_arp_active_list_head) =  NX_NULL;
127                         }
128                         else
129                         {
130 
131                             /* Remove the entry from a list of more than one entry.  */
132 
133                             /* Update the list head pointer.  */
134                             if (*(arp_entry -> nx_arp_active_list_head) == arp_entry)
135                             {
136                                 *(arp_entry -> nx_arp_active_list_head) =  arp_entry -> nx_arp_active_next;
137                             }
138 
139                             /* Update the links of the adjacent ARP entries.  */
140                             (arp_entry -> nx_arp_active_next) -> nx_arp_active_previous =
141                                 arp_entry -> nx_arp_active_previous;
142                             (arp_entry -> nx_arp_active_previous) -> nx_arp_active_next =
143                                 arp_entry -> nx_arp_active_next;
144                         }
145 
146                         /* Decrease the number of active ARP entries.  */
147                         ip_ptr -> nx_ip_arp_dynamic_active_count--;
148 
149                         /* Clear the active head pointer.  */
150                         arp_entry -> nx_arp_active_list_head =  NX_NULL;
151                     }
152 
153                     /* Determine if this is the only ARP entry on the dynamic list.  */
154                     if (arp_entry != arp_entry -> nx_arp_pool_next)
155                     {
156 
157                         /* No. Place the ARP entry at the end of the dynamic ARP pool, which is where new
158                            ARP requests are allocated from.  */
159 
160                         /* Remove the entry from a list of more than one entry.  */
161                         /* Update the links of the adjacent ARP dynamic pool entries.  */
162                         (arp_entry -> nx_arp_pool_next) -> nx_arp_pool_previous =
163                             arp_entry -> nx_arp_pool_previous;
164                         (arp_entry -> nx_arp_pool_previous) -> nx_arp_pool_next =
165                             arp_entry -> nx_arp_pool_next;
166 
167                         /* Update the list head pointer.  */
168                         if (ip_ptr -> nx_ip_arp_dynamic_list == arp_entry)
169                         {
170                             ip_ptr -> nx_ip_arp_dynamic_list =  arp_entry -> nx_arp_pool_next;
171                         }
172 
173 
174                         /* Add ARP entry to the end of the list.  */
175                         arp_entry -> nx_arp_pool_next =
176                             ip_ptr -> nx_ip_arp_dynamic_list;
177                         arp_entry -> nx_arp_pool_previous =
178                             (ip_ptr -> nx_ip_arp_dynamic_list) -> nx_arp_pool_previous;
179                         ((ip_ptr -> nx_ip_arp_dynamic_list) -> nx_arp_pool_previous) -> nx_arp_pool_next =
180                             arp_entry;
181                         (ip_ptr -> nx_ip_arp_dynamic_list) -> nx_arp_pool_previous =   arp_entry;
182                     }
183 
184                     /* Pickup the queued packets head pointer.  */
185                     next_packet_ptr =  arp_entry -> nx_arp_packets_waiting;
186 
187                     /* Clear the queued packets head pointer.  */
188                     arp_entry -> nx_arp_packets_waiting =  NX_NULL;
189 
190                     /* Restore interrupts.  */
191                     TX_RESTORE
192 
193                     /* Loop to remove all queued packets.  */
194                     while (next_packet_ptr)
195                     {
196 
197                         /* Pickup the packet pointer at the head of the queue.  */
198                         packet_ptr =  next_packet_ptr;
199 
200                         /* Move to the next packet in the queue.  */
201                         next_packet_ptr =  next_packet_ptr -> nx_packet_queue_next;
202 
203                         /* Clear the next packet queue pointer.  */
204                         packet_ptr -> nx_packet_queue_next =  NX_NULL;
205 
206 #ifndef NX_DISABLE_IP_INFO
207 
208                         /* Increment the IP send packets dropped count.  */
209                         ip_ptr -> nx_ip_send_packets_dropped++;
210 #endif
211 
212                         /* Release the packet that was queued for the expired ARP entry.  */
213                         _nx_packet_transmit_release(packet_ptr);
214                     }
215                 }
216                 else
217                 {
218 
219                     /* We haven't yet had a response to this ARP request so send it again!  */
220 
221                     /* Increment the ARP retry counter.  */
222                     arp_entry -> nx_arp_retries++;
223 
224                     /* Setup the ARP update rate to the maximum value again.  */
225                     arp_entry -> nx_arp_entry_next_update =  NX_ARP_UPDATE_RATE;
226 
227                     /* Send the ARP request out.  */
228                     _nx_arp_packet_send(ip_ptr, arp_entry -> nx_arp_ip_address, arp_entry -> nx_arp_ip_interface);
229                 }
230             }
231         }
232 
233         /* Move to the next ARP entry.  */
234         arp_entry =  arp_entry -> nx_arp_pool_next;
235     }
236 
237 
238     /* Reduce the defend timeout of interfaces.  */
239     for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++)
240     {
241         if (ip_ptr -> nx_ip_interface[i].nx_interface_valid == NX_FALSE)
242         {
243             continue;
244         }
245 
246         if (ip_ptr -> nx_ip_interface[i].nx_interface_arp_defend_timeout == 0)
247         {
248             continue;
249         }
250 
251         ip_ptr -> nx_ip_interface[i].nx_interface_arp_defend_timeout--;
252     }
253 }
254 #endif /* !NX_DISABLE_IPV4  */
255 
256