diff options
-rw-r--r-- | include/net/neighbour.h | 1 | ||||
-rw-r--r-- | net/core/neighbour.c | 27 | ||||
-rw-r--r-- | net/ipv4/arp.c | 2 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 2 |
4 files changed, 28 insertions, 4 deletions
diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 0874f7fcd859..f58b384aa6c9 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h | |||
@@ -323,6 +323,7 @@ void __neigh_set_probe_once(struct neighbour *neigh); | |||
323 | bool neigh_remove_one(struct neighbour *ndel, struct neigh_table *tbl); | 323 | bool neigh_remove_one(struct neighbour *ndel, struct neigh_table *tbl); |
324 | void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev); | 324 | void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev); |
325 | int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev); | 325 | int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev); |
326 | int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev); | ||
326 | int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb); | 327 | int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb); |
327 | int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb); | 328 | int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb); |
328 | int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb); | 329 | int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb); |
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index dc1389b8beb1..69c41cb3966d 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
@@ -232,7 +232,8 @@ static void pneigh_queue_purge(struct sk_buff_head *list) | |||
232 | } | 232 | } |
233 | } | 233 | } |
234 | 234 | ||
235 | static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev) | 235 | static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev, |
236 | bool skip_perm) | ||
236 | { | 237 | { |
237 | int i; | 238 | int i; |
238 | struct neigh_hash_table *nht; | 239 | struct neigh_hash_table *nht; |
@@ -250,6 +251,10 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev) | |||
250 | np = &n->next; | 251 | np = &n->next; |
251 | continue; | 252 | continue; |
252 | } | 253 | } |
254 | if (skip_perm && n->nud_state & NUD_PERMANENT) { | ||
255 | np = &n->next; | ||
256 | continue; | ||
257 | } | ||
253 | rcu_assign_pointer(*np, | 258 | rcu_assign_pointer(*np, |
254 | rcu_dereference_protected(n->next, | 259 | rcu_dereference_protected(n->next, |
255 | lockdep_is_held(&tbl->lock))); | 260 | lockdep_is_held(&tbl->lock))); |
@@ -285,21 +290,35 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev) | |||
285 | void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev) | 290 | void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev) |
286 | { | 291 | { |
287 | write_lock_bh(&tbl->lock); | 292 | write_lock_bh(&tbl->lock); |
288 | neigh_flush_dev(tbl, dev); | 293 | neigh_flush_dev(tbl, dev, false); |
289 | write_unlock_bh(&tbl->lock); | 294 | write_unlock_bh(&tbl->lock); |
290 | } | 295 | } |
291 | EXPORT_SYMBOL(neigh_changeaddr); | 296 | EXPORT_SYMBOL(neigh_changeaddr); |
292 | 297 | ||
293 | int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) | 298 | static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev, |
299 | bool skip_perm) | ||
294 | { | 300 | { |
295 | write_lock_bh(&tbl->lock); | 301 | write_lock_bh(&tbl->lock); |
296 | neigh_flush_dev(tbl, dev); | 302 | neigh_flush_dev(tbl, dev, skip_perm); |
297 | pneigh_ifdown_and_unlock(tbl, dev); | 303 | pneigh_ifdown_and_unlock(tbl, dev); |
298 | 304 | ||
299 | del_timer_sync(&tbl->proxy_timer); | 305 | del_timer_sync(&tbl->proxy_timer); |
300 | pneigh_queue_purge(&tbl->proxy_queue); | 306 | pneigh_queue_purge(&tbl->proxy_queue); |
301 | return 0; | 307 | return 0; |
302 | } | 308 | } |
309 | |||
310 | int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev) | ||
311 | { | ||
312 | __neigh_ifdown(tbl, dev, true); | ||
313 | return 0; | ||
314 | } | ||
315 | EXPORT_SYMBOL(neigh_carrier_down); | ||
316 | |||
317 | int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) | ||
318 | { | ||
319 | __neigh_ifdown(tbl, dev, false); | ||
320 | return 0; | ||
321 | } | ||
303 | EXPORT_SYMBOL(neigh_ifdown); | 322 | EXPORT_SYMBOL(neigh_ifdown); |
304 | 323 | ||
305 | static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev) | 324 | static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev) |
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index e90c89ef8c08..850a6f13a082 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c | |||
@@ -1255,6 +1255,8 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event, | |||
1255 | change_info = ptr; | 1255 | change_info = ptr; |
1256 | if (change_info->flags_changed & IFF_NOARP) | 1256 | if (change_info->flags_changed & IFF_NOARP) |
1257 | neigh_changeaddr(&arp_tbl, dev); | 1257 | neigh_changeaddr(&arp_tbl, dev); |
1258 | if (!netif_carrier_ok(dev)) | ||
1259 | neigh_carrier_down(&arp_tbl, dev); | ||
1258 | break; | 1260 | break; |
1259 | default: | 1261 | default: |
1260 | break; | 1262 | break; |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 51863ada15a4..a25cfdd47c89 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -1784,6 +1784,8 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, | |||
1784 | change_info = ptr; | 1784 | change_info = ptr; |
1785 | if (change_info->flags_changed & IFF_NOARP) | 1785 | if (change_info->flags_changed & IFF_NOARP) |
1786 | neigh_changeaddr(&nd_tbl, dev); | 1786 | neigh_changeaddr(&nd_tbl, dev); |
1787 | if (!netif_carrier_ok(dev)) | ||
1788 | neigh_carrier_down(&nd_tbl, dev); | ||
1787 | break; | 1789 | break; |
1788 | case NETDEV_DOWN: | 1790 | case NETDEV_DOWN: |
1789 | neigh_ifdown(&nd_tbl, dev); | 1791 | neigh_ifdown(&nd_tbl, dev); |