aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/neighbour.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2005-10-23 02:37:48 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2005-10-23 02:37:48 -0400
commit6fb9974f49f7a6032118c5b6caa6e08e7097913e (patch)
treea1e8f77c1c5cd6a45842f4f02582bb583e6d1019 /net/core/neighbour.c
parent203755029e063066ecc4cf5eee1110ab946c2d88 (diff)
[NEIGH] Fix add_timer race in neigh_add_timer
neigh_add_timer cannot use add_timer unconditionally. The reason is that by the time it has obtained the write lock someone else (e.g., neigh_update) could have already added a new timer. So it should only use mod_timer and deal with its return value accordingly. This bug would have led to rare neighbour cache entry leaks. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'net/core/neighbour.c')
-rw-r--r--net/core/neighbour.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 766caa0dd930..37d8d8c29522 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -816,10 +816,10 @@ static void neigh_timer_handler(unsigned long arg)
816 } 816 }
817 817
818 if (neigh->nud_state & NUD_IN_TIMER) { 818 if (neigh->nud_state & NUD_IN_TIMER) {
819 neigh_hold(neigh);
820 if (time_before(next, jiffies + HZ/2)) 819 if (time_before(next, jiffies + HZ/2))
821 next = jiffies + HZ/2; 820 next = jiffies + HZ/2;
822 neigh_add_timer(neigh, next); 821 if (!mod_timer(&neigh->timer, next))
822 neigh_hold(neigh);
823 } 823 }
824 if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) { 824 if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
825 struct sk_buff *skb = skb_peek(&neigh->arp_queue); 825 struct sk_buff *skb = skb_peek(&neigh->arp_queue);