diff options
-rw-r--r-- | net/core/neighbour.c | 46 |
1 files changed, 28 insertions, 18 deletions
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index c54229befcfe..163b4f5b0365 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
@@ -771,6 +771,28 @@ static __inline__ int neigh_max_probes(struct neighbour *n) | |||
771 | p->ucast_probes + p->app_probes + p->mcast_probes); | 771 | p->ucast_probes + p->app_probes + p->mcast_probes); |
772 | } | 772 | } |
773 | 773 | ||
774 | static void neigh_invalidate(struct neighbour *neigh) | ||
775 | { | ||
776 | struct sk_buff *skb; | ||
777 | |||
778 | NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed); | ||
779 | NEIGH_PRINTK2("neigh %p is failed.\n", neigh); | ||
780 | neigh->updated = jiffies; | ||
781 | |||
782 | /* It is very thin place. report_unreachable is very complicated | ||
783 | routine. Particularly, it can hit the same neighbour entry! | ||
784 | |||
785 | So that, we try to be accurate and avoid dead loop. --ANK | ||
786 | */ | ||
787 | while (neigh->nud_state == NUD_FAILED && | ||
788 | (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) { | ||
789 | write_unlock(&neigh->lock); | ||
790 | neigh->ops->error_report(neigh, skb); | ||
791 | write_lock(&neigh->lock); | ||
792 | } | ||
793 | skb_queue_purge(&neigh->arp_queue); | ||
794 | } | ||
795 | |||
774 | /* Called when a timer expires for a neighbour entry. */ | 796 | /* Called when a timer expires for a neighbour entry. */ |
775 | 797 | ||
776 | static void neigh_timer_handler(unsigned long arg) | 798 | static void neigh_timer_handler(unsigned long arg) |
@@ -835,26 +857,9 @@ static void neigh_timer_handler(unsigned long arg) | |||
835 | 857 | ||
836 | if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) && | 858 | if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) && |
837 | atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) { | 859 | atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) { |
838 | struct sk_buff *skb; | ||
839 | |||
840 | neigh->nud_state = NUD_FAILED; | 860 | neigh->nud_state = NUD_FAILED; |
841 | neigh->updated = jiffies; | ||
842 | notify = 1; | 861 | notify = 1; |
843 | NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed); | 862 | neigh_invalidate(neigh); |
844 | NEIGH_PRINTK2("neigh %p is failed.\n", neigh); | ||
845 | |||
846 | /* It is very thin place. report_unreachable is very complicated | ||
847 | routine. Particularly, it can hit the same neighbour entry! | ||
848 | |||
849 | So that, we try to be accurate and avoid dead loop. --ANK | ||
850 | */ | ||
851 | while (neigh->nud_state == NUD_FAILED && | ||
852 | (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) { | ||
853 | write_unlock(&neigh->lock); | ||
854 | neigh->ops->error_report(neigh, skb); | ||
855 | write_lock(&neigh->lock); | ||
856 | } | ||
857 | skb_queue_purge(&neigh->arp_queue); | ||
858 | } | 863 | } |
859 | 864 | ||
860 | if (neigh->nud_state & NUD_IN_TIMER) { | 865 | if (neigh->nud_state & NUD_IN_TIMER) { |
@@ -1001,6 +1006,11 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, | |||
1001 | neigh->nud_state = new; | 1006 | neigh->nud_state = new; |
1002 | err = 0; | 1007 | err = 0; |
1003 | notify = old & NUD_VALID; | 1008 | notify = old & NUD_VALID; |
1009 | if ((old & (NUD_INCOMPLETE | NUD_PROBE)) && | ||
1010 | (new & NUD_FAILED)) { | ||
1011 | neigh_invalidate(neigh); | ||
1012 | notify = 1; | ||
1013 | } | ||
1004 | goto out; | 1014 | goto out; |
1005 | } | 1015 | } |
1006 | 1016 | ||