summaryrefslogtreecommitdiffstats
path: root/src/net/arp.c
diff options
context:
space:
mode:
authorMichael Brown2012-10-20 00:03:38 +0200
committerMichael Brown2012-10-20 00:03:38 +0200
commit885384faf360c7501382182e620c32880fc783a5 (patch)
treed92439561bee6e3e7a30099adccef12aaf99efd9 /src/net/arp.c
parent[efi] Expose net device non-volatile settings via HII (diff)
downloadipxe-885384faf360c7501382182e620c32880fc783a5.tar.gz
ipxe-885384faf360c7501382182e620c32880fc783a5.tar.xz
ipxe-885384faf360c7501382182e620c32880fc783a5.zip
[arp] Increase robustness of ARP discarder
Take ownership from the ARP cache at the start of arp_destroy(), to ensure that no code path can lead to arp_destroy() being re-entered. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/net/arp.c')
-rw-r--r--src/net/arp.c17
1 files changed, 10 insertions, 7 deletions
diff --git a/src/net/arp.c b/src/net/arp.c
index d96cb4cc..b94eb906 100644
--- a/src/net/arp.c
+++ b/src/net/arp.c
@@ -180,13 +180,16 @@ static void arp_destroy ( struct arp_entry *arp, int rc ) {
struct net_device *netdev = arp->netdev;
struct net_protocol *net_protocol = arp->net_protocol;
struct io_buffer *iobuf;
- struct io_buffer *tmp;
+
+ /* Take ownership from cache */
+ list_del ( &arp->list );
/* Stop timer */
stop_timer ( &arp->timer );
/* Discard any outstanding I/O buffers */
- list_for_each_entry_safe ( iobuf, tmp, &arp->tx_queue, list ) {
+ while ( ( iobuf = list_first_entry ( &arp->tx_queue, struct io_buffer,
+ list ) ) != NULL ) {
DBGC2 ( arp, "ARP %p %s %s %s discarding deferred packet: "
"%s\n", arp, netdev->name, net_protocol->name,
net_protocol->ntoa ( arp->net_dest ), strerror ( rc ) );
@@ -198,8 +201,7 @@ static void arp_destroy ( struct arp_entry *arp, int rc ) {
net_protocol->name, net_protocol->ntoa ( arp->net_dest ),
strerror ( rc ) );
- /* Remove from cache and drop reference */
- list_del ( &arp->list );
+ /* Drop remaining reference */
ref_put ( &arp->refcnt );
}
@@ -518,12 +520,13 @@ static unsigned int arp_discard ( void ) {
struct arp_entry *arp;
/* Drop oldest cache entry, if any */
- list_for_each_entry_reverse ( arp, &arp_entries, list ) {
+ arp = list_last_entry ( &arp_entries, struct arp_entry, list );
+ if ( arp ) {
arp_destroy ( arp, -ENOBUFS );
return 1;
+ } else {
+ return 0;
}
-
- return 0;
}
/** ARP cache discarder