diff options
Diffstat (limited to 'net/core/neighbour.c')
-rw-r--r-- | net/core/neighbour.c | 57 |
1 files changed, 33 insertions, 24 deletions
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index a1cbce7fdae5..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 | ||
@@ -1088,8 +1098,8 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, | |||
1088 | struct neighbour *n1 = neigh; | 1098 | struct neighbour *n1 = neigh; |
1089 | write_unlock_bh(&neigh->lock); | 1099 | write_unlock_bh(&neigh->lock); |
1090 | /* On shaper/eql skb->dst->neighbour != neigh :( */ | 1100 | /* On shaper/eql skb->dst->neighbour != neigh :( */ |
1091 | if (skb->dst && skb->dst->neighbour) | 1101 | if (skb_dst(skb) && skb_dst(skb)->neighbour) |
1092 | n1 = skb->dst->neighbour; | 1102 | n1 = skb_dst(skb)->neighbour; |
1093 | n1->output(skb); | 1103 | n1->output(skb); |
1094 | write_lock_bh(&neigh->lock); | 1104 | write_lock_bh(&neigh->lock); |
1095 | } | 1105 | } |
@@ -1182,7 +1192,7 @@ EXPORT_SYMBOL(neigh_compat_output); | |||
1182 | 1192 | ||
1183 | int neigh_resolve_output(struct sk_buff *skb) | 1193 | int neigh_resolve_output(struct sk_buff *skb) |
1184 | { | 1194 | { |
1185 | struct dst_entry *dst = skb->dst; | 1195 | struct dst_entry *dst = skb_dst(skb); |
1186 | struct neighbour *neigh; | 1196 | struct neighbour *neigh; |
1187 | int rc = 0; | 1197 | int rc = 0; |
1188 | 1198 | ||
@@ -1229,7 +1239,7 @@ EXPORT_SYMBOL(neigh_resolve_output); | |||
1229 | int neigh_connected_output(struct sk_buff *skb) | 1239 | int neigh_connected_output(struct sk_buff *skb) |
1230 | { | 1240 | { |
1231 | int err; | 1241 | int err; |
1232 | struct dst_entry *dst = skb->dst; | 1242 | struct dst_entry *dst = skb_dst(skb); |
1233 | struct neighbour *neigh = dst->neighbour; | 1243 | struct neighbour *neigh = dst->neighbour; |
1234 | struct net_device *dev = neigh->dev; | 1244 | struct net_device *dev = neigh->dev; |
1235 | 1245 | ||
@@ -1298,8 +1308,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, | |||
1298 | if (time_before(tbl->proxy_timer.expires, sched_next)) | 1308 | if (time_before(tbl->proxy_timer.expires, sched_next)) |
1299 | sched_next = tbl->proxy_timer.expires; | 1309 | sched_next = tbl->proxy_timer.expires; |
1300 | } | 1310 | } |
1301 | dst_release(skb->dst); | 1311 | skb_dst_drop(skb); |
1302 | skb->dst = NULL; | ||
1303 | dev_hold(skb->dev); | 1312 | dev_hold(skb->dev); |
1304 | __skb_queue_tail(&tbl->proxy_queue, skb); | 1313 | __skb_queue_tail(&tbl->proxy_queue, skb); |
1305 | mod_timer(&tbl->proxy_timer, sched_next); | 1314 | mod_timer(&tbl->proxy_timer, sched_next); |