aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/neighbour.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/neighbour.c')
-rw-r--r--net/core/neighbour.c50
1 files changed, 31 insertions, 19 deletions
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 1334d7e56f02..039d51e6c284 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -844,6 +844,19 @@ static void neigh_invalidate(struct neighbour *neigh)
844 skb_queue_purge(&neigh->arp_queue); 844 skb_queue_purge(&neigh->arp_queue);
845} 845}
846 846
847static void neigh_probe(struct neighbour *neigh)
848 __releases(neigh->lock)
849{
850 struct sk_buff *skb = skb_peek(&neigh->arp_queue);
851 /* keep skb alive even if arp_queue overflows */
852 if (skb)
853 skb = skb_copy(skb, GFP_ATOMIC);
854 write_unlock(&neigh->lock);
855 neigh->ops->solicit(neigh, skb);
856 atomic_inc(&neigh->probes);
857 kfree_skb(skb);
858}
859
847/* Called when a timer expires for a neighbour entry. */ 860/* Called when a timer expires for a neighbour entry. */
848 861
849static void neigh_timer_handler(unsigned long arg) 862static void neigh_timer_handler(unsigned long arg)
@@ -859,12 +872,8 @@ static void neigh_timer_handler(unsigned long arg)
859 now = jiffies; 872 now = jiffies;
860 next = now + HZ; 873 next = now + HZ;
861 874
862 if (!(state & NUD_IN_TIMER)) { 875 if (!(state & NUD_IN_TIMER))
863#ifndef CONFIG_SMP
864 printk(KERN_WARNING "neigh: timer & !nud_in_timer\n");
865#endif
866 goto out; 876 goto out;
867 }
868 877
869 if (state & NUD_REACHABLE) { 878 if (state & NUD_REACHABLE) {
870 if (time_before_eq(now, 879 if (time_before_eq(now,
@@ -920,14 +929,7 @@ static void neigh_timer_handler(unsigned long arg)
920 neigh_hold(neigh); 929 neigh_hold(neigh);
921 } 930 }
922 if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) { 931 if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
923 struct sk_buff *skb = skb_peek(&neigh->arp_queue); 932 neigh_probe(neigh);
924 /* keep skb alive even if arp_queue overflows */
925 if (skb)
926 skb = skb_copy(skb, GFP_ATOMIC);
927 write_unlock(&neigh->lock);
928 neigh->ops->solicit(neigh, skb);
929 atomic_inc(&neigh->probes);
930 kfree_skb(skb);
931 } else { 933 } else {
932out: 934out:
933 write_unlock(&neigh->lock); 935 write_unlock(&neigh->lock);
@@ -942,7 +944,7 @@ out:
942int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) 944int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
943{ 945{
944 int rc; 946 int rc;
945 unsigned long now; 947 bool immediate_probe = false;
946 948
947 write_lock_bh(&neigh->lock); 949 write_lock_bh(&neigh->lock);
948 950
@@ -950,14 +952,16 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
950 if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE)) 952 if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
951 goto out_unlock_bh; 953 goto out_unlock_bh;
952 954
953 now = jiffies;
954
955 if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) { 955 if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
956 if (neigh->parms->mcast_probes + neigh->parms->app_probes) { 956 if (neigh->parms->mcast_probes + neigh->parms->app_probes) {
957 unsigned long next, now = jiffies;
958
957 atomic_set(&neigh->probes, neigh->parms->ucast_probes); 959 atomic_set(&neigh->probes, neigh->parms->ucast_probes);
958 neigh->nud_state = NUD_INCOMPLETE; 960 neigh->nud_state = NUD_INCOMPLETE;
959 neigh->updated = jiffies; 961 neigh->updated = now;
960 neigh_add_timer(neigh, now + 1); 962 next = now + max(neigh->parms->retrans_time, HZ/2);
963 neigh_add_timer(neigh, next);
964 immediate_probe = true;
961 } else { 965 } else {
962 neigh->nud_state = NUD_FAILED; 966 neigh->nud_state = NUD_FAILED;
963 neigh->updated = jiffies; 967 neigh->updated = jiffies;
@@ -989,7 +993,11 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
989 rc = 1; 993 rc = 1;
990 } 994 }
991out_unlock_bh: 995out_unlock_bh:
992 write_unlock_bh(&neigh->lock); 996 if (immediate_probe)
997 neigh_probe(neigh);
998 else
999 write_unlock(&neigh->lock);
1000 local_bh_enable();
993 return rc; 1001 return rc;
994} 1002}
995EXPORT_SYMBOL(__neigh_event_send); 1003EXPORT_SYMBOL(__neigh_event_send);
@@ -1156,10 +1164,14 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
1156 struct dst_entry *dst = skb_dst(skb); 1164 struct dst_entry *dst = skb_dst(skb);
1157 struct neighbour *n2, *n1 = neigh; 1165 struct neighbour *n2, *n1 = neigh;
1158 write_unlock_bh(&neigh->lock); 1166 write_unlock_bh(&neigh->lock);
1167
1168 rcu_read_lock();
1159 /* On shaper/eql skb->dst->neighbour != neigh :( */ 1169 /* On shaper/eql skb->dst->neighbour != neigh :( */
1160 if (dst && (n2 = dst_get_neighbour(dst)) != NULL) 1170 if (dst && (n2 = dst_get_neighbour(dst)) != NULL)
1161 n1 = n2; 1171 n1 = n2;
1162 n1->output(n1, skb); 1172 n1->output(n1, skb);
1173 rcu_read_unlock();
1174
1163 write_lock_bh(&neigh->lock); 1175 write_lock_bh(&neigh->lock);
1164 } 1176 }
1165 skb_queue_purge(&neigh->arp_queue); 1177 skb_queue_purge(&neigh->arp_queue);