178 |
} |
} |
179 |
|
|
180 |
/** |
/** |
181 |
* Search the ARP table for a specific entry. |
* Search the ARP table for a matching or new entry. |
182 |
* |
* |
183 |
* If an IP address is given, return a pending or stable ARP entry that matches |
* If an IP address is given, return a pending or stable ARP entry that matches |
184 |
* the address. If no match is found, create a new entry with this address set, |
* the address. If no match is found, create a new entry with this address set, |
193 |
* |
* |
194 |
* @param ipaddr IP address to find in ARP cache, or to add if not found. |
* @param ipaddr IP address to find in ARP cache, or to add if not found. |
195 |
* @param flags |
* @param flags |
196 |
* - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling. |
* - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of |
197 |
|
* active (stable or pending) entries. |
198 |
* |
* |
199 |
* @return The ARP entry index that matched or is created, ERR_MEM if no |
* @return The ARP entry index that matched or is created, ERR_MEM if no |
200 |
* entry is found or could be recycled. |
* entry is found or could be recycled. |
201 |
*/ |
*/ |
202 |
static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags) |
static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags) |
203 |
{ |
{ |
204 |
s8_t old_pending, old_stable, empty, i; |
s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE, empty = ARP_TABLE_SIZE, i; |
205 |
u8_t age_pending, age_stable; |
u8_t age_pending = 0, age_stable = 0; |
206 |
#if ARP_QUEUEING |
#if ARP_QUEUEING |
207 |
|
/* oldest entry with packets on queue */ |
208 |
s8_t old_queue = ARP_TABLE_SIZE; |
s8_t old_queue = ARP_TABLE_SIZE; |
209 |
|
/* its age */ |
210 |
u8_t age_queue = 0; |
u8_t age_queue = 0; |
211 |
#endif |
#endif |
212 |
|
|
|
old_pending = old_stable = empty = ARP_TABLE_SIZE; |
|
|
age_pending = age_stable = 0; |
|
|
|
|
213 |
/** |
/** |
214 |
* a) do a search through the cache, remember candidates |
* a) do a search through the cache, remember candidates |
215 |
* b) select candidate entry |
* b) select candidate entry |
237 |
/* if given, does IP address match IP address in ARP entry? */ |
/* if given, does IP address match IP address in ARP entry? */ |
238 |
if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { |
if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { |
239 |
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching pending entry %d\n", i)); |
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching pending entry %d\n", i)); |
240 |
/* found match, simply bail out */ |
/* found exact IP address match, simply bail out */ |
241 |
return i; |
return i; |
242 |
#if ARP_QUEUEING |
#if ARP_QUEUEING |
243 |
/* pending with queued packets? */ |
/* pending with queued packets? */ |
260 |
/* if given, does IP address match IP address in ARP entry? */ |
/* if given, does IP address match IP address in ARP entry? */ |
261 |
if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { |
if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { |
262 |
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching stable entry %d\n", i)); |
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching stable entry %d\n", i)); |
263 |
/* found match, simply bail out */ |
/* found exact IP address match, simply bail out */ |
264 |
return i; |
return i; |
265 |
/* remember entry with oldest stable entry in oldest, its age in maxtime */ |
/* remember entry with oldest stable entry in oldest, its age in maxtime */ |
266 |
} else if (arp_table[i].ctime >= age_stable) { |
} else if (arp_table[i].ctime >= age_stable) { |
269 |
} |
} |
270 |
} |
} |
271 |
} |
} |
272 |
|
/* { we have no match } => try to create a new entry */ |
273 |
|
|
274 |
|
/* no empty entry found and not allowed to recycle? */ |
275 |
|
if ((i == ARP_TABLE_SIZE) && ((flags & ETHARP_TRY_HARD) == 0)) |
276 |
|
{ |
277 |
|
return (s8_t)ERR_MEM; |
278 |
|
} |
279 |
|
|
280 |
/* b) choose the least destructive entry to recycle: |
/* b) choose the least destructive entry to recycle: |
281 |
* 1) empty entry |
* 1) empty entry |
282 |
* 2) oldest stable entry |
* 2) oldest stable entry |
283 |
* 3) oldest pending entry without queued packets |
* 3) oldest pending entry without queued packets |
284 |
* 4) oldest pending entry without queued packets |
* 4) oldest pending entry without queued packets |
285 |
|
* |
286 |
|
* { ETHARP_TRY_HARD is set at this point } |
287 |
*/ |
*/ |
288 |
|
|
289 |
/* 1) empty entry available? */ |
/* 1) empty entry available? */ |
314 |
/* no empty or recyclable entries found */ |
/* no empty or recyclable entries found */ |
315 |
#endif |
#endif |
316 |
} else { |
} else { |
317 |
return ERR_MEM; |
return (s8_t)ERR_MEM; |
318 |
} |
} |
319 |
|
|
320 |
/* { empty or recyclable entry found } */ |
/* { empty or recyclable entry found } */ |
321 |
LWIP_ASSERT("i >= 0", i >= 0); |
LWIP_ASSERT("i >= 0", i >= 0); |
322 |
LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); |
LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); |
323 |
|
|
324 |
/* allowed to recycle a entry? */ |
/* recycle entry (no-op for an already empty entry) */ |
325 |
if (flags & ETHARP_TRY_HARD) { |
arp_table[i].state = ETHARP_STATE_EMPTY; |
326 |
/* recycle (no-op for an already empty entry) */ |
/* IP address given? */ |
327 |
arp_table[i].state = ETHARP_STATE_EMPTY; |
if (ipaddr != NULL) { |
328 |
|
/* set IP address */ |
329 |
|
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
330 |
} |
} |
331 |
|
arp_table[i].ctime = 0; |
|
/* empty entry found or created? */ |
|
|
if (arp_table[i].state == ETHARP_STATE_EMPTY) { |
|
|
/* IP address given? */ |
|
|
if (ipaddr != NULL) { |
|
|
/* set IP address */ |
|
|
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
|
|
} |
|
|
arp_table[i].ctime = 0; |
|
332 |
#if ARP_QUEUEING |
#if ARP_QUEUEING |
333 |
/* remove any queued packets */ |
/* remove any queued packets */ |
334 |
if (arp_table[i].p != NULL) pbuf_free(arp_table[i].p); |
if (arp_table[i].p != NULL) pbuf_free(arp_table[i].p); |
335 |
arp_table[i].p = NULL; |
arp_table[i].p = NULL; |
336 |
#endif |
#endif |
|
/* no entry available */ |
|
|
} else { |
|
|
/* return failure */ |
|
|
i = (s8_t)ERR_MEM; |
|
|
} |
|
|
|
|
337 |
return (err_t)i; |
return (err_t)i; |
338 |
} |
} |
339 |
|
|