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