aboutsummaryrefslogtreecommitdiffstats
path: root/main/linux-grsec/net-next-2.6.git-5ef12d98a19254ee5dc851bd83e214b43ec1f725.patch
diff options
context:
space:
mode:
Diffstat (limited to 'main/linux-grsec/net-next-2.6.git-5ef12d98a19254ee5dc851bd83e214b43ec1f725.patch')
-rw-r--r--main/linux-grsec/net-next-2.6.git-5ef12d98a19254ee5dc851bd83e214b43ec1f725.patch96
1 files changed, 96 insertions, 0 deletions
diff --git a/main/linux-grsec/net-next-2.6.git-5ef12d98a19254ee5dc851bd83e214b43ec1f725.patch b/main/linux-grsec/net-next-2.6.git-5ef12d98a19254ee5dc851bd83e214b43ec1f725.patch
new file mode 100644
index 0000000000..97983d79d2
--- /dev/null
+++ b/main/linux-grsec/net-next-2.6.git-5ef12d98a19254ee5dc851bd83e214b43ec1f725.patch
@@ -0,0 +1,96 @@
+From: Timo Teras <timo.teras@iki.fi>
+Date: Thu, 11 Jun 2009 11:16:28 +0000 (-0700)
+Subject: neigh: fix state transition INCOMPLETE->FAILED via Netlink request
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fdavem%2Fnet-next-2.6.git;a=commitdiff_plain;h=5ef12d98a19254ee5dc851bd83e214b43ec1f725;hp=2b85a34e911bf483c27cfdd124aeb1605145dc80
+
+neigh: fix state transition INCOMPLETE->FAILED via Netlink request
+
+The current code errors out the INCOMPLETE neigh entry skb queue only from
+the timer if maximum probes have been attempted and there has been no reply.
+This also causes the transtion to FAILED state.
+
+However, the neigh entry can be also updated via Netlink to inform that the
+address is unavailable. Currently, neigh_update() just stops the timers and
+leaves the pending skb's unreleased. This results that the clean up code in
+the timer callback is never called, preventing also proper garbage collection.
+
+This fixes neigh_update() to process the pending skb queue immediately if
+INCOMPLETE -> FAILED state transtion occurs due to a Netlink request.
+
+Signed-off-by: Timo Teras <timo.teras@iki.fi>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+
+diff --git a/net/core/neighbour.c b/net/core/neighbour.c
+index c54229b..163b4f5 100644
+--- a/net/core/neighbour.c
++++ b/net/core/neighbour.c
+@@ -771,6 +771,28 @@ static __inline__ int neigh_max_probes(struct neighbour *n)
+ p->ucast_probes + p->app_probes + p->mcast_probes);
+ }
+
++static void neigh_invalidate(struct neighbour *neigh)
++{
++ struct sk_buff *skb;
++
++ NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
++ NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
++ neigh->updated = jiffies;
++
++ /* It is very thin place. report_unreachable is very complicated
++ routine. Particularly, it can hit the same neighbour entry!
++
++ So that, we try to be accurate and avoid dead loop. --ANK
++ */
++ while (neigh->nud_state == NUD_FAILED &&
++ (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
++ write_unlock(&neigh->lock);
++ neigh->ops->error_report(neigh, skb);
++ write_lock(&neigh->lock);
++ }
++ skb_queue_purge(&neigh->arp_queue);
++}
++
+ /* Called when a timer expires for a neighbour entry. */
+
+ static void neigh_timer_handler(unsigned long arg)
+@@ -835,26 +857,9 @@ static void neigh_timer_handler(unsigned long arg)
+
+ if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
+ atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
+- struct sk_buff *skb;
+-
+ neigh->nud_state = NUD_FAILED;
+- neigh->updated = jiffies;
+ notify = 1;
+- NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
+- NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
+-
+- /* It is very thin place. report_unreachable is very complicated
+- routine. Particularly, it can hit the same neighbour entry!
+-
+- So that, we try to be accurate and avoid dead loop. --ANK
+- */
+- while (neigh->nud_state == NUD_FAILED &&
+- (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
+- write_unlock(&neigh->lock);
+- neigh->ops->error_report(neigh, skb);
+- write_lock(&neigh->lock);
+- }
+- skb_queue_purge(&neigh->arp_queue);
++ neigh_invalidate(neigh);
+ }
+
+ if (neigh->nud_state & NUD_IN_TIMER) {
+@@ -1001,6 +1006,11 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
+ neigh->nud_state = new;
+ err = 0;
+ notify = old & NUD_VALID;
++ if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
++ (new & NUD_FAILED)) {
++ neigh_invalidate(neigh);
++ notify = 1;
++ }
+ goto out;
+ }
+