diff options
Diffstat (limited to 'net/core/neighbour.c')
-rw-r--r-- | net/core/neighbour.c | 50 |
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 | ||
847 | static 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 | ||
849 | static void neigh_timer_handler(unsigned long arg) | 862 | static 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 { |
932 | out: | 934 | out: |
933 | write_unlock(&neigh->lock); | 935 | write_unlock(&neigh->lock); |
@@ -942,7 +944,7 @@ out: | |||
942 | int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) | 944 | int __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 | } |
991 | out_unlock_bh: | 995 | out_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 | } |
995 | EXPORT_SYMBOL(__neigh_event_send); | 1003 | EXPORT_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); |