|
@@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
31
|
31
|
#include <ipxe/retry.h>
|
32
|
32
|
#include <ipxe/timer.h>
|
33
|
33
|
#include <ipxe/malloc.h>
|
|
34
|
+#include <ipxe/refcnt.h>
|
34
|
35
|
#include <ipxe/arp.h>
|
35
|
36
|
|
36
|
37
|
/** @file
|
|
@@ -51,6 +52,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
51
|
52
|
|
52
|
53
|
/** An ARP cache entry */
|
53
|
54
|
struct arp_entry {
|
|
55
|
+ /** Reference count */
|
|
56
|
+ struct refcnt refcnt;
|
54
|
57
|
/** List of ARP cache entries */
|
55
|
58
|
struct list_head list;
|
56
|
59
|
/** Network device */
|
|
@@ -76,6 +79,25 @@ struct net_protocol arp_protocol __net_protocol;
|
76
|
79
|
|
77
|
80
|
static void arp_expired ( struct retry_timer *timer, int over );
|
78
|
81
|
|
|
82
|
+/**
|
|
83
|
+ * Free ARP cache entry
|
|
84
|
+ *
|
|
85
|
+ * @v refcnt Reference count
|
|
86
|
+ */
|
|
87
|
+static void arp_free ( struct refcnt *refcnt ) {
|
|
88
|
+ struct arp_entry *arp =
|
|
89
|
+ container_of ( refcnt, struct arp_entry, refcnt );
|
|
90
|
+
|
|
91
|
+ /* Sanity check */
|
|
92
|
+ assert ( list_empty ( &arp->tx_queue ) );
|
|
93
|
+
|
|
94
|
+ /* Drop reference to network device */
|
|
95
|
+ netdev_put ( arp->netdev );
|
|
96
|
+
|
|
97
|
+ /* Free entry */
|
|
98
|
+ free ( arp );
|
|
99
|
+}
|
|
100
|
+
|
79
|
101
|
/**
|
80
|
102
|
* Create ARP cache entry
|
81
|
103
|
*
|
|
@@ -91,27 +113,28 @@ static struct arp_entry * arp_create ( struct net_device *netdev,
|
91
|
113
|
const void *net_source ) {
|
92
|
114
|
struct arp_entry *arp;
|
93
|
115
|
|
94
|
|
- /* Allocate entry and add to cache */
|
|
116
|
+ /* Allocate and initialise entry */
|
95
|
117
|
arp = zalloc ( sizeof ( *arp ) );
|
96
|
118
|
if ( ! arp )
|
97
|
119
|
return NULL;
|
98
|
|
-
|
99
|
|
- /* Initialise entry and add to cache */
|
|
120
|
+ ref_init ( &arp->refcnt, arp_free );
|
100
|
121
|
arp->netdev = netdev_get ( netdev );
|
101
|
122
|
arp->net_protocol = net_protocol;
|
102
|
123
|
memcpy ( arp->net_dest, net_dest,
|
103
|
124
|
net_protocol->net_addr_len );
|
104
|
125
|
memcpy ( arp->net_source, net_source,
|
105
|
126
|
net_protocol->net_addr_len );
|
106
|
|
- timer_init ( &arp->timer, arp_expired, NULL );
|
|
127
|
+ timer_init ( &arp->timer, arp_expired, &arp->refcnt );
|
107
|
128
|
arp->timer.min_timeout = ARP_MIN_TIMEOUT;
|
108
|
129
|
arp->timer.max_timeout = ARP_MAX_TIMEOUT;
|
109
|
130
|
INIT_LIST_HEAD ( &arp->tx_queue );
|
110
|
|
- list_add ( &arp->list, &arp_entries );
|
111
|
131
|
|
112
|
132
|
/* Start timer running to trigger initial transmission */
|
113
|
133
|
start_timer_nodelay ( &arp->timer );
|
114
|
134
|
|
|
135
|
+ /* Transfer ownership to cache */
|
|
136
|
+ list_add ( &arp->list, &arp_entries );
|
|
137
|
+
|
115
|
138
|
DBGC ( arp, "ARP %p %s %s %s created\n", arp, netdev->name,
|
116
|
139
|
net_protocol->name, net_protocol->ntoa ( net_dest ) );
|
117
|
140
|
return arp;
|
|
@@ -174,10 +197,9 @@ static void arp_destroy ( struct arp_entry *arp, int rc ) {
|
174
|
197
|
net_protocol->name, net_protocol->ntoa ( arp->net_dest ),
|
175
|
198
|
strerror ( rc ) );
|
176
|
199
|
|
177
|
|
- /* Drop reference to network device, remove from cache and free */
|
178
|
|
- netdev_put ( arp->netdev );
|
|
200
|
+ /* Remove from cache and drop reference */
|
179
|
201
|
list_del ( &arp->list );
|
180
|
|
- free ( arp );
|
|
202
|
+ ref_put ( &arp->refcnt );
|
181
|
203
|
}
|
182
|
204
|
|
183
|
205
|
/**
|
|
@@ -241,7 +263,6 @@ static void arp_update ( struct arp_entry *arp, const void *ll_dest ) {
|
241
|
263
|
struct ll_protocol *ll_protocol = netdev->ll_protocol;
|
242
|
264
|
struct net_protocol *net_protocol = arp->net_protocol;
|
243
|
265
|
struct io_buffer *iobuf;
|
244
|
|
- struct io_buffer *tmp;
|
245
|
266
|
int rc;
|
246
|
267
|
|
247
|
268
|
DBGC ( arp, "ARP %p %s %s %s updated => %s\n", arp, netdev->name,
|
|
@@ -254,8 +275,13 @@ static void arp_update ( struct arp_entry *arp, const void *ll_dest ) {
|
254
|
275
|
/* Stop retransmission timer */
|
255
|
276
|
stop_timer ( &arp->timer );
|
256
|
277
|
|
257
|
|
- /* Transmit any packets in queue */
|
258
|
|
- list_for_each_entry_safe ( iobuf, tmp, &arp->tx_queue, list ) {
|
|
278
|
+ /* Transmit any packets in queue. Take out a temporary
|
|
279
|
+ * reference on the entry to prevent it from going out of
|
|
280
|
+ * scope during the call to net_tx().
|
|
281
|
+ */
|
|
282
|
+ ref_get ( &arp->refcnt );
|
|
283
|
+ while ( ( iobuf = list_first_entry ( &arp->tx_queue, struct io_buffer,
|
|
284
|
+ list ) ) != NULL ) {
|
259
|
285
|
DBGC2 ( arp, "ARP %p %s %s %s transmitting deferred packet\n",
|
260
|
286
|
arp, netdev->name, net_protocol->name,
|
261
|
287
|
net_protocol->ntoa ( arp->net_dest ) );
|
|
@@ -267,6 +293,7 @@ static void arp_update ( struct arp_entry *arp, const void *ll_dest ) {
|
267
|
293
|
/* Ignore error and continue */
|
268
|
294
|
}
|
269
|
295
|
}
|
|
296
|
+ ref_put ( &arp->refcnt );
|
270
|
297
|
}
|
271
|
298
|
|
272
|
299
|
/**
|