summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/neighbour.h1
-rw-r--r--net/core/neighbour.c27
-rw-r--r--net/ipv4/arp.c2
-rw-r--r--net/ipv6/ndisc.c2
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);
323bool neigh_remove_one(struct neighbour *ndel, struct neigh_table *tbl); 323bool neigh_remove_one(struct neighbour *ndel, struct neigh_table *tbl);
324void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev); 324void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
325int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev); 325int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
326int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev);
326int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb); 327int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb);
327int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb); 328int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb);
328int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb); 329int 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
235static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev) 235static 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)
285void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev) 290void 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}
291EXPORT_SYMBOL(neigh_changeaddr); 296EXPORT_SYMBOL(neigh_changeaddr);
292 297
293int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) 298static 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
310int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev)
311{
312 __neigh_ifdown(tbl, dev, true);
313 return 0;
314}
315EXPORT_SYMBOL(neigh_carrier_down);
316
317int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
318{
319 __neigh_ifdown(tbl, dev, false);
320 return 0;
321}
303EXPORT_SYMBOL(neigh_ifdown); 322EXPORT_SYMBOL(neigh_ifdown);
304 323
305static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev) 324static 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);