diff options
author | Michael Brown <mcb30@ipxe.org> | 2012-10-19 23:03:38 +0100 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2012-10-19 23:03:38 +0100 |
commit | 885384faf360c7501382182e620c32880fc783a5 (patch) | |
tree | d92439561bee6e3e7a30099adccef12aaf99efd9 /src/net/arp.c | |
parent | a4d125081010ff9816add31af2f732e6ec22a704 (diff) | |
download | ipxe-885384faf360c7501382182e620c32880fc783a5.tar.gz |
[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.c | 17 |
1 files changed, 10 insertions, 7 deletions
diff --git a/src/net/arp.c b/src/net/arp.c index d96cb4ccc..b94eb9064 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 |