|
@@ -844,6 +844,19 @@ static void neigh_invalidate(struct neighbour *neigh)
|
|
|
skb_queue_purge(&neigh->arp_queue);
|
|
|
}
|
|
|
|
|
|
+static void neigh_probe(struct neighbour *neigh)
|
|
|
+ __releases(neigh->lock)
|
|
|
+{
|
|
|
+ struct sk_buff *skb = skb_peek(&neigh->arp_queue);
|
|
|
+ /* keep skb alive even if arp_queue overflows */
|
|
|
+ if (skb)
|
|
|
+ skb = skb_copy(skb, GFP_ATOMIC);
|
|
|
+ write_unlock(&neigh->lock);
|
|
|
+ neigh->ops->solicit(neigh, skb);
|
|
|
+ atomic_inc(&neigh->probes);
|
|
|
+ kfree_skb(skb);
|
|
|
+}
|
|
|
+
|
|
|
/* Called when a timer expires for a neighbour entry. */
|
|
|
|
|
|
static void neigh_timer_handler(unsigned long arg)
|
|
@@ -920,14 +933,7 @@ static void neigh_timer_handler(unsigned long arg)
|
|
|
neigh_hold(neigh);
|
|
|
}
|
|
|
if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
|
|
|
- struct sk_buff *skb = skb_peek(&neigh->arp_queue);
|
|
|
- /* keep skb alive even if arp_queue overflows */
|
|
|
- if (skb)
|
|
|
- skb = skb_copy(skb, GFP_ATOMIC);
|
|
|
- write_unlock(&neigh->lock);
|
|
|
- neigh->ops->solicit(neigh, skb);
|
|
|
- atomic_inc(&neigh->probes);
|
|
|
- kfree_skb(skb);
|
|
|
+ neigh_probe(neigh);
|
|
|
} else {
|
|
|
out:
|
|
|
write_unlock(&neigh->lock);
|
|
@@ -942,7 +948,7 @@ out:
|
|
|
int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
|
|
|
{
|
|
|
int rc;
|
|
|
- unsigned long now;
|
|
|
+ bool immediate_probe = false;
|
|
|
|
|
|
write_lock_bh(&neigh->lock);
|
|
|
|
|
@@ -950,14 +956,16 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
|
|
|
if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
|
|
|
goto out_unlock_bh;
|
|
|
|
|
|
- now = jiffies;
|
|
|
-
|
|
|
if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
|
|
|
if (neigh->parms->mcast_probes + neigh->parms->app_probes) {
|
|
|
+ unsigned long next, now = jiffies;
|
|
|
+
|
|
|
atomic_set(&neigh->probes, neigh->parms->ucast_probes);
|
|
|
neigh->nud_state = NUD_INCOMPLETE;
|
|
|
- neigh->updated = jiffies;
|
|
|
- neigh_add_timer(neigh, now + 1);
|
|
|
+ neigh->updated = now;
|
|
|
+ next = now + max(neigh->parms->retrans_time, HZ/2);
|
|
|
+ neigh_add_timer(neigh, next);
|
|
|
+ immediate_probe = true;
|
|
|
} else {
|
|
|
neigh->nud_state = NUD_FAILED;
|
|
|
neigh->updated = jiffies;
|
|
@@ -989,7 +997,11 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
|
|
|
rc = 1;
|
|
|
}
|
|
|
out_unlock_bh:
|
|
|
- write_unlock_bh(&neigh->lock);
|
|
|
+ if (immediate_probe)
|
|
|
+ neigh_probe(neigh);
|
|
|
+ else
|
|
|
+ write_unlock(&neigh->lock);
|
|
|
+ local_bh_enable();
|
|
|
return rc;
|
|
|
}
|
|
|
EXPORT_SYMBOL(__neigh_event_send);
|