xref: /openbmc/linux/net/core/neighbour.c (revision 053c095a)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *	Generic address resolution entity
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *	Authors:
51da177e4SLinus Torvalds  *	Pedro Roque		<roque@di.fc.ul.pt>
61da177e4SLinus Torvalds  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  *	This program is free software; you can redistribute it and/or
91da177e4SLinus Torvalds  *      modify it under the terms of the GNU General Public License
101da177e4SLinus Torvalds  *      as published by the Free Software Foundation; either version
111da177e4SLinus Torvalds  *      2 of the License, or (at your option) any later version.
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  *	Fixes:
141da177e4SLinus Torvalds  *	Vitaly E. Lavrov	releasing NULL neighbor in neigh_add.
151da177e4SLinus Torvalds  *	Harald Welte		Add neighbour cache statistics like rtstat
161da177e4SLinus Torvalds  */
171da177e4SLinus Torvalds 
18e005d193SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19e005d193SJoe Perches 
205a0e3ad6STejun Heo #include <linux/slab.h>
211da177e4SLinus Torvalds #include <linux/types.h>
221da177e4SLinus Torvalds #include <linux/kernel.h>
231da177e4SLinus Torvalds #include <linux/module.h>
241da177e4SLinus Torvalds #include <linux/socket.h>
251da177e4SLinus Torvalds #include <linux/netdevice.h>
261da177e4SLinus Torvalds #include <linux/proc_fs.h>
271da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL
281da177e4SLinus Torvalds #include <linux/sysctl.h>
291da177e4SLinus Torvalds #endif
301da177e4SLinus Torvalds #include <linux/times.h>
31457c4cbcSEric W. Biederman #include <net/net_namespace.h>
321da177e4SLinus Torvalds #include <net/neighbour.h>
331da177e4SLinus Torvalds #include <net/dst.h>
341da177e4SLinus Torvalds #include <net/sock.h>
358d71740cSTom Tucker #include <net/netevent.h>
36a14a49d2SThomas Graf #include <net/netlink.h>
371da177e4SLinus Torvalds #include <linux/rtnetlink.h>
381da177e4SLinus Torvalds #include <linux/random.h>
39543537bdSPaulo Marques #include <linux/string.h>
40c3609d51Svignesh babu #include <linux/log2.h>
411d4c8c29SJiri Pirko #include <linux/inetdevice.h>
42bba24896SJiri Pirko #include <net/addrconf.h>
431da177e4SLinus Torvalds 
44d5d427cdSJoe Perches #define DEBUG
451da177e4SLinus Torvalds #define NEIGH_DEBUG 1
46d5d427cdSJoe Perches #define neigh_dbg(level, fmt, ...)		\
47d5d427cdSJoe Perches do {						\
48d5d427cdSJoe Perches 	if (level <= NEIGH_DEBUG)		\
49d5d427cdSJoe Perches 		pr_debug(fmt, ##__VA_ARGS__);	\
50d5d427cdSJoe Perches } while (0)
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds #define PNEIGH_HASHMASK		0xF
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds static void neigh_timer_handler(unsigned long arg);
55d961db35SThomas Graf static void __neigh_notify(struct neighbour *n, int type, int flags);
56d961db35SThomas Graf static void neigh_update_notify(struct neighbour *neigh);
571da177e4SLinus Torvalds static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
581da177e4SLinus Torvalds 
5945fc3b11SAmos Waterland #ifdef CONFIG_PROC_FS
609a32144eSArjan van de Ven static const struct file_operations neigh_stat_seq_fops;
6145fc3b11SAmos Waterland #endif
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds /*
641da177e4SLinus Torvalds    Neighbour hash table buckets are protected with rwlock tbl->lock.
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds    - All the scans/updates to hash buckets MUST be made under this lock.
671da177e4SLinus Torvalds    - NOTHING clever should be made under this lock: no callbacks
681da177e4SLinus Torvalds      to protocol backends, no attempts to send something to network.
691da177e4SLinus Torvalds      It will result in deadlocks, if backend/driver wants to use neighbour
701da177e4SLinus Torvalds      cache.
711da177e4SLinus Torvalds    - If the entry requires some non-trivial actions, increase
721da177e4SLinus Torvalds      its reference count and release table lock.
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds    Neighbour entries are protected:
751da177e4SLinus Torvalds    - with reference count.
761da177e4SLinus Torvalds    - with rwlock neigh->lock
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds    Reference count prevents destruction.
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds    neigh->lock mainly serializes ll address data and its validity state.
811da177e4SLinus Torvalds    However, the same lock is used to protect another entry fields:
821da177e4SLinus Torvalds     - timer
831da177e4SLinus Torvalds     - resolution queue
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds    Again, nothing clever shall be made under neigh->lock,
861da177e4SLinus Torvalds    the most complicated procedure, which we allow is dev->hard_header.
871da177e4SLinus Torvalds    It is supposed, that dev->hard_header is simplistic and does
881da177e4SLinus Torvalds    not make callbacks to neighbour tables.
891da177e4SLinus Torvalds  */
901da177e4SLinus Torvalds 
918f40b161SDavid S. Miller static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
921da177e4SLinus Torvalds {
931da177e4SLinus Torvalds 	kfree_skb(skb);
941da177e4SLinus Torvalds 	return -ENETDOWN;
951da177e4SLinus Torvalds }
961da177e4SLinus Torvalds 
974f494554SThomas Graf static void neigh_cleanup_and_release(struct neighbour *neigh)
984f494554SThomas Graf {
994f494554SThomas Graf 	if (neigh->parms->neigh_cleanup)
1004f494554SThomas Graf 		neigh->parms->neigh_cleanup(neigh);
1014f494554SThomas Graf 
102d961db35SThomas Graf 	__neigh_notify(neigh, RTM_DELNEIGH, 0);
1034f494554SThomas Graf 	neigh_release(neigh);
1044f494554SThomas Graf }
1054f494554SThomas Graf 
1061da177e4SLinus Torvalds /*
1071da177e4SLinus Torvalds  * It is random distribution in the interval (1/2)*base...(3/2)*base.
1081da177e4SLinus Torvalds  * It corresponds to default IPv6 settings and is not overridable,
1091da177e4SLinus Torvalds  * because it is really reasonable choice.
1101da177e4SLinus Torvalds  */
1111da177e4SLinus Torvalds 
1121da177e4SLinus Torvalds unsigned long neigh_rand_reach_time(unsigned long base)
1131da177e4SLinus Torvalds {
11463862b5bSAruna-Hewapathirane 	return base ? (prandom_u32() % base) + (base >> 1) : 0;
1151da177e4SLinus Torvalds }
1160a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_rand_reach_time);
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds static int neigh_forced_gc(struct neigh_table *tbl)
1201da177e4SLinus Torvalds {
1211da177e4SLinus Torvalds 	int shrunk = 0;
1221da177e4SLinus Torvalds 	int i;
123d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
128d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
129d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
130cd089336SDavid S. Miller 	for (i = 0; i < (1 << nht->hash_shift); i++) {
131767e97e1SEric Dumazet 		struct neighbour *n;
132767e97e1SEric Dumazet 		struct neighbour __rcu **np;
1331da177e4SLinus Torvalds 
134d6bf7817SEric Dumazet 		np = &nht->hash_buckets[i];
135767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
136767e97e1SEric Dumazet 					lockdep_is_held(&tbl->lock))) != NULL) {
1371da177e4SLinus Torvalds 			/* Neighbour record may be discarded if:
1381da177e4SLinus Torvalds 			 * - nobody refers to it.
1391da177e4SLinus Torvalds 			 * - it is not permanent
1401da177e4SLinus Torvalds 			 */
1411da177e4SLinus Torvalds 			write_lock(&n->lock);
1421da177e4SLinus Torvalds 			if (atomic_read(&n->refcnt) == 1 &&
1431da177e4SLinus Torvalds 			    !(n->nud_state & NUD_PERMANENT)) {
144767e97e1SEric Dumazet 				rcu_assign_pointer(*np,
145767e97e1SEric Dumazet 					rcu_dereference_protected(n->next,
146767e97e1SEric Dumazet 						  lockdep_is_held(&tbl->lock)));
1471da177e4SLinus Torvalds 				n->dead = 1;
1481da177e4SLinus Torvalds 				shrunk	= 1;
1491da177e4SLinus Torvalds 				write_unlock(&n->lock);
1504f494554SThomas Graf 				neigh_cleanup_and_release(n);
1511da177e4SLinus Torvalds 				continue;
1521da177e4SLinus Torvalds 			}
1531da177e4SLinus Torvalds 			write_unlock(&n->lock);
1541da177e4SLinus Torvalds 			np = &n->next;
1551da177e4SLinus Torvalds 		}
1561da177e4SLinus Torvalds 	}
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds 	tbl->last_flush = jiffies;
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds 	return shrunk;
1631da177e4SLinus Torvalds }
1641da177e4SLinus Torvalds 
165a43d8994SPavel Emelyanov static void neigh_add_timer(struct neighbour *n, unsigned long when)
166a43d8994SPavel Emelyanov {
167a43d8994SPavel Emelyanov 	neigh_hold(n);
168a43d8994SPavel Emelyanov 	if (unlikely(mod_timer(&n->timer, when))) {
169a43d8994SPavel Emelyanov 		printk("NEIGH: BUG, double timer add, state is %x\n",
170a43d8994SPavel Emelyanov 		       n->nud_state);
171a43d8994SPavel Emelyanov 		dump_stack();
172a43d8994SPavel Emelyanov 	}
173a43d8994SPavel Emelyanov }
174a43d8994SPavel Emelyanov 
1751da177e4SLinus Torvalds static int neigh_del_timer(struct neighbour *n)
1761da177e4SLinus Torvalds {
1771da177e4SLinus Torvalds 	if ((n->nud_state & NUD_IN_TIMER) &&
1781da177e4SLinus Torvalds 	    del_timer(&n->timer)) {
1791da177e4SLinus Torvalds 		neigh_release(n);
1801da177e4SLinus Torvalds 		return 1;
1811da177e4SLinus Torvalds 	}
1821da177e4SLinus Torvalds 	return 0;
1831da177e4SLinus Torvalds }
1841da177e4SLinus Torvalds 
1851da177e4SLinus Torvalds static void pneigh_queue_purge(struct sk_buff_head *list)
1861da177e4SLinus Torvalds {
1871da177e4SLinus Torvalds 	struct sk_buff *skb;
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds 	while ((skb = skb_dequeue(list)) != NULL) {
1901da177e4SLinus Torvalds 		dev_put(skb->dev);
1911da177e4SLinus Torvalds 		kfree_skb(skb);
1921da177e4SLinus Torvalds 	}
1931da177e4SLinus Torvalds }
1941da177e4SLinus Torvalds 
19549636bb1SHerbert Xu static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
1961da177e4SLinus Torvalds {
1971da177e4SLinus Torvalds 	int i;
198d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
1991da177e4SLinus Torvalds 
200d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
201d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
202d6bf7817SEric Dumazet 
203cd089336SDavid S. Miller 	for (i = 0; i < (1 << nht->hash_shift); i++) {
204767e97e1SEric Dumazet 		struct neighbour *n;
205767e97e1SEric Dumazet 		struct neighbour __rcu **np = &nht->hash_buckets[i];
2061da177e4SLinus Torvalds 
207767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
208767e97e1SEric Dumazet 					lockdep_is_held(&tbl->lock))) != NULL) {
2091da177e4SLinus Torvalds 			if (dev && n->dev != dev) {
2101da177e4SLinus Torvalds 				np = &n->next;
2111da177e4SLinus Torvalds 				continue;
2121da177e4SLinus Torvalds 			}
213767e97e1SEric Dumazet 			rcu_assign_pointer(*np,
214767e97e1SEric Dumazet 				   rcu_dereference_protected(n->next,
215767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
2161da177e4SLinus Torvalds 			write_lock(&n->lock);
2171da177e4SLinus Torvalds 			neigh_del_timer(n);
2181da177e4SLinus Torvalds 			n->dead = 1;
2191da177e4SLinus Torvalds 
2201da177e4SLinus Torvalds 			if (atomic_read(&n->refcnt) != 1) {
2211da177e4SLinus Torvalds 				/* The most unpleasant situation.
2221da177e4SLinus Torvalds 				   We must destroy neighbour entry,
2231da177e4SLinus Torvalds 				   but someone still uses it.
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds 				   The destroy will be delayed until
2261da177e4SLinus Torvalds 				   the last user releases us, but
2271da177e4SLinus Torvalds 				   we must kill timers etc. and move
2281da177e4SLinus Torvalds 				   it to safe state.
2291da177e4SLinus Torvalds 				 */
230c9ab4d85SEric Dumazet 				__skb_queue_purge(&n->arp_queue);
2318b5c171bSEric Dumazet 				n->arp_queue_len_bytes = 0;
2321da177e4SLinus Torvalds 				n->output = neigh_blackhole;
2331da177e4SLinus Torvalds 				if (n->nud_state & NUD_VALID)
2341da177e4SLinus Torvalds 					n->nud_state = NUD_NOARP;
2351da177e4SLinus Torvalds 				else
2361da177e4SLinus Torvalds 					n->nud_state = NUD_NONE;
237d5d427cdSJoe Perches 				neigh_dbg(2, "neigh %p is stray\n", n);
2381da177e4SLinus Torvalds 			}
2391da177e4SLinus Torvalds 			write_unlock(&n->lock);
2404f494554SThomas Graf 			neigh_cleanup_and_release(n);
2411da177e4SLinus Torvalds 		}
2421da177e4SLinus Torvalds 	}
24349636bb1SHerbert Xu }
2441da177e4SLinus Torvalds 
24549636bb1SHerbert Xu void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
24649636bb1SHerbert Xu {
24749636bb1SHerbert Xu 	write_lock_bh(&tbl->lock);
24849636bb1SHerbert Xu 	neigh_flush_dev(tbl, dev);
24949636bb1SHerbert Xu 	write_unlock_bh(&tbl->lock);
25049636bb1SHerbert Xu }
2510a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_changeaddr);
25249636bb1SHerbert Xu 
25349636bb1SHerbert Xu int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
25449636bb1SHerbert Xu {
25549636bb1SHerbert Xu 	write_lock_bh(&tbl->lock);
25649636bb1SHerbert Xu 	neigh_flush_dev(tbl, dev);
2571da177e4SLinus Torvalds 	pneigh_ifdown(tbl, dev);
2581da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds 	del_timer_sync(&tbl->proxy_timer);
2611da177e4SLinus Torvalds 	pneigh_queue_purge(&tbl->proxy_queue);
2621da177e4SLinus Torvalds 	return 0;
2631da177e4SLinus Torvalds }
2640a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_ifdown);
2651da177e4SLinus Torvalds 
266596b9b68SDavid Miller static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev)
2671da177e4SLinus Torvalds {
2681da177e4SLinus Torvalds 	struct neighbour *n = NULL;
2691da177e4SLinus Torvalds 	unsigned long now = jiffies;
2701da177e4SLinus Torvalds 	int entries;
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds 	entries = atomic_inc_return(&tbl->entries) - 1;
2731da177e4SLinus Torvalds 	if (entries >= tbl->gc_thresh3 ||
2741da177e4SLinus Torvalds 	    (entries >= tbl->gc_thresh2 &&
2751da177e4SLinus Torvalds 	     time_after(now, tbl->last_flush + 5 * HZ))) {
2761da177e4SLinus Torvalds 		if (!neigh_forced_gc(tbl) &&
2771da177e4SLinus Torvalds 		    entries >= tbl->gc_thresh3)
2781da177e4SLinus Torvalds 			goto out_entries;
2791da177e4SLinus Torvalds 	}
2801da177e4SLinus Torvalds 
28108433effSYOSHIFUJI Hideaki / 吉藤英明 	n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
2821da177e4SLinus Torvalds 	if (!n)
2831da177e4SLinus Torvalds 		goto out_entries;
2841da177e4SLinus Torvalds 
285c9ab4d85SEric Dumazet 	__skb_queue_head_init(&n->arp_queue);
2861da177e4SLinus Torvalds 	rwlock_init(&n->lock);
2870ed8ddf4SEric Dumazet 	seqlock_init(&n->ha_lock);
2881da177e4SLinus Torvalds 	n->updated	  = n->used = now;
2891da177e4SLinus Torvalds 	n->nud_state	  = NUD_NONE;
2901da177e4SLinus Torvalds 	n->output	  = neigh_blackhole;
291f6b72b62SDavid S. Miller 	seqlock_init(&n->hh.hh_lock);
2921da177e4SLinus Torvalds 	n->parms	  = neigh_parms_clone(&tbl->parms);
293b24b8a24SPavel Emelyanov 	setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n);
2941da177e4SLinus Torvalds 
2951da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, allocs);
2961da177e4SLinus Torvalds 	n->tbl		  = tbl;
2971da177e4SLinus Torvalds 	atomic_set(&n->refcnt, 1);
2981da177e4SLinus Torvalds 	n->dead		  = 1;
2991da177e4SLinus Torvalds out:
3001da177e4SLinus Torvalds 	return n;
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds out_entries:
3031da177e4SLinus Torvalds 	atomic_dec(&tbl->entries);
3041da177e4SLinus Torvalds 	goto out;
3051da177e4SLinus Torvalds }
3061da177e4SLinus Torvalds 
3072c2aba6cSDavid S. Miller static void neigh_get_hash_rnd(u32 *x)
3082c2aba6cSDavid S. Miller {
3092c2aba6cSDavid S. Miller 	get_random_bytes(x, sizeof(*x));
3102c2aba6cSDavid S. Miller 	*x |= 1;
3112c2aba6cSDavid S. Miller }
3122c2aba6cSDavid S. Miller 
313cd089336SDavid S. Miller static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
3141da177e4SLinus Torvalds {
315cd089336SDavid S. Miller 	size_t size = (1 << shift) * sizeof(struct neighbour *);
316d6bf7817SEric Dumazet 	struct neigh_hash_table *ret;
3176193d2beSEric Dumazet 	struct neighbour __rcu **buckets;
3182c2aba6cSDavid S. Miller 	int i;
3191da177e4SLinus Torvalds 
320d6bf7817SEric Dumazet 	ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
321d6bf7817SEric Dumazet 	if (!ret)
322d6bf7817SEric Dumazet 		return NULL;
323d6bf7817SEric Dumazet 	if (size <= PAGE_SIZE)
324d6bf7817SEric Dumazet 		buckets = kzalloc(size, GFP_ATOMIC);
325d6bf7817SEric Dumazet 	else
3266193d2beSEric Dumazet 		buckets = (struct neighbour __rcu **)
327d6bf7817SEric Dumazet 			  __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
328d6bf7817SEric Dumazet 					   get_order(size));
329d6bf7817SEric Dumazet 	if (!buckets) {
330d6bf7817SEric Dumazet 		kfree(ret);
331d6bf7817SEric Dumazet 		return NULL;
3321da177e4SLinus Torvalds 	}
3336193d2beSEric Dumazet 	ret->hash_buckets = buckets;
334cd089336SDavid S. Miller 	ret->hash_shift = shift;
3352c2aba6cSDavid S. Miller 	for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
3362c2aba6cSDavid S. Miller 		neigh_get_hash_rnd(&ret->hash_rnd[i]);
3371da177e4SLinus Torvalds 	return ret;
3381da177e4SLinus Torvalds }
3391da177e4SLinus Torvalds 
340d6bf7817SEric Dumazet static void neigh_hash_free_rcu(struct rcu_head *head)
3411da177e4SLinus Torvalds {
342d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = container_of(head,
343d6bf7817SEric Dumazet 						    struct neigh_hash_table,
344d6bf7817SEric Dumazet 						    rcu);
345cd089336SDavid S. Miller 	size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
3466193d2beSEric Dumazet 	struct neighbour __rcu **buckets = nht->hash_buckets;
3471da177e4SLinus Torvalds 
3481da177e4SLinus Torvalds 	if (size <= PAGE_SIZE)
349d6bf7817SEric Dumazet 		kfree(buckets);
3501da177e4SLinus Torvalds 	else
351d6bf7817SEric Dumazet 		free_pages((unsigned long)buckets, get_order(size));
352d6bf7817SEric Dumazet 	kfree(nht);
3531da177e4SLinus Torvalds }
3541da177e4SLinus Torvalds 
355d6bf7817SEric Dumazet static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
356cd089336SDavid S. Miller 						unsigned long new_shift)
3571da177e4SLinus Torvalds {
358d6bf7817SEric Dumazet 	unsigned int i, hash;
359d6bf7817SEric Dumazet 	struct neigh_hash_table *new_nht, *old_nht;
3601da177e4SLinus Torvalds 
3611da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, hash_grows);
3621da177e4SLinus Torvalds 
363d6bf7817SEric Dumazet 	old_nht = rcu_dereference_protected(tbl->nht,
364d6bf7817SEric Dumazet 					    lockdep_is_held(&tbl->lock));
365cd089336SDavid S. Miller 	new_nht = neigh_hash_alloc(new_shift);
366d6bf7817SEric Dumazet 	if (!new_nht)
367d6bf7817SEric Dumazet 		return old_nht;
3681da177e4SLinus Torvalds 
369cd089336SDavid S. Miller 	for (i = 0; i < (1 << old_nht->hash_shift); i++) {
3701da177e4SLinus Torvalds 		struct neighbour *n, *next;
3711da177e4SLinus Torvalds 
372767e97e1SEric Dumazet 		for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
373767e97e1SEric Dumazet 						   lockdep_is_held(&tbl->lock));
374d6bf7817SEric Dumazet 		     n != NULL;
375d6bf7817SEric Dumazet 		     n = next) {
376d6bf7817SEric Dumazet 			hash = tbl->hash(n->primary_key, n->dev,
377d6bf7817SEric Dumazet 					 new_nht->hash_rnd);
3781da177e4SLinus Torvalds 
379cd089336SDavid S. Miller 			hash >>= (32 - new_nht->hash_shift);
380767e97e1SEric Dumazet 			next = rcu_dereference_protected(n->next,
381767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock));
3821da177e4SLinus Torvalds 
383767e97e1SEric Dumazet 			rcu_assign_pointer(n->next,
384767e97e1SEric Dumazet 					   rcu_dereference_protected(
385767e97e1SEric Dumazet 						new_nht->hash_buckets[hash],
386767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
387767e97e1SEric Dumazet 			rcu_assign_pointer(new_nht->hash_buckets[hash], n);
3881da177e4SLinus Torvalds 		}
3891da177e4SLinus Torvalds 	}
3901da177e4SLinus Torvalds 
391d6bf7817SEric Dumazet 	rcu_assign_pointer(tbl->nht, new_nht);
392d6bf7817SEric Dumazet 	call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
393d6bf7817SEric Dumazet 	return new_nht;
3941da177e4SLinus Torvalds }
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
3971da177e4SLinus Torvalds 			       struct net_device *dev)
3981da177e4SLinus Torvalds {
3991da177e4SLinus Torvalds 	struct neighbour *n;
4001da177e4SLinus Torvalds 	int key_len = tbl->key_len;
401bc4bf5f3SPavel Emelyanov 	u32 hash_val;
402d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
4031da177e4SLinus Torvalds 
4041da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, lookups);
4051da177e4SLinus Torvalds 
406d6bf7817SEric Dumazet 	rcu_read_lock_bh();
407d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
408cd089336SDavid S. Miller 	hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
409767e97e1SEric Dumazet 
410767e97e1SEric Dumazet 	for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
411767e97e1SEric Dumazet 	     n != NULL;
412767e97e1SEric Dumazet 	     n = rcu_dereference_bh(n->next)) {
4131da177e4SLinus Torvalds 		if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
414767e97e1SEric Dumazet 			if (!atomic_inc_not_zero(&n->refcnt))
415767e97e1SEric Dumazet 				n = NULL;
4161da177e4SLinus Torvalds 			NEIGH_CACHE_STAT_INC(tbl, hits);
4171da177e4SLinus Torvalds 			break;
4181da177e4SLinus Torvalds 		}
4191da177e4SLinus Torvalds 	}
420767e97e1SEric Dumazet 
421d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
4221da177e4SLinus Torvalds 	return n;
4231da177e4SLinus Torvalds }
4240a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_lookup);
4251da177e4SLinus Torvalds 
426426b5303SEric W. Biederman struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
427426b5303SEric W. Biederman 				     const void *pkey)
4281da177e4SLinus Torvalds {
4291da177e4SLinus Torvalds 	struct neighbour *n;
4301da177e4SLinus Torvalds 	int key_len = tbl->key_len;
431bc4bf5f3SPavel Emelyanov 	u32 hash_val;
432d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
4331da177e4SLinus Torvalds 
4341da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, lookups);
4351da177e4SLinus Torvalds 
436d6bf7817SEric Dumazet 	rcu_read_lock_bh();
437d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
438cd089336SDavid S. Miller 	hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
439767e97e1SEric Dumazet 
440767e97e1SEric Dumazet 	for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
441767e97e1SEric Dumazet 	     n != NULL;
442767e97e1SEric Dumazet 	     n = rcu_dereference_bh(n->next)) {
443426b5303SEric W. Biederman 		if (!memcmp(n->primary_key, pkey, key_len) &&
444878628fbSYOSHIFUJI Hideaki 		    net_eq(dev_net(n->dev), net)) {
445767e97e1SEric Dumazet 			if (!atomic_inc_not_zero(&n->refcnt))
446767e97e1SEric Dumazet 				n = NULL;
4471da177e4SLinus Torvalds 			NEIGH_CACHE_STAT_INC(tbl, hits);
4481da177e4SLinus Torvalds 			break;
4491da177e4SLinus Torvalds 		}
4501da177e4SLinus Torvalds 	}
451767e97e1SEric Dumazet 
452d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
4531da177e4SLinus Torvalds 	return n;
4541da177e4SLinus Torvalds }
4550a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_lookup_nodev);
4561da177e4SLinus Torvalds 
457a263b309SDavid S. Miller struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
458a263b309SDavid S. Miller 				 struct net_device *dev, bool want_ref)
4591da177e4SLinus Torvalds {
4601da177e4SLinus Torvalds 	u32 hash_val;
4611da177e4SLinus Torvalds 	int key_len = tbl->key_len;
4621da177e4SLinus Torvalds 	int error;
463596b9b68SDavid Miller 	struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev);
464d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
4651da177e4SLinus Torvalds 
4661da177e4SLinus Torvalds 	if (!n) {
4671da177e4SLinus Torvalds 		rc = ERR_PTR(-ENOBUFS);
4681da177e4SLinus Torvalds 		goto out;
4691da177e4SLinus Torvalds 	}
4701da177e4SLinus Torvalds 
4711da177e4SLinus Torvalds 	memcpy(n->primary_key, pkey, key_len);
4721da177e4SLinus Torvalds 	n->dev = dev;
4731da177e4SLinus Torvalds 	dev_hold(dev);
4741da177e4SLinus Torvalds 
4751da177e4SLinus Torvalds 	/* Protocol specific setup. */
4761da177e4SLinus Torvalds 	if (tbl->constructor &&	(error = tbl->constructor(n)) < 0) {
4771da177e4SLinus Torvalds 		rc = ERR_PTR(error);
4781da177e4SLinus Torvalds 		goto out_neigh_release;
4791da177e4SLinus Torvalds 	}
4801da177e4SLinus Torvalds 
481da6a8fa0SDavid Miller 	if (dev->netdev_ops->ndo_neigh_construct) {
482da6a8fa0SDavid Miller 		error = dev->netdev_ops->ndo_neigh_construct(n);
483da6a8fa0SDavid Miller 		if (error < 0) {
484da6a8fa0SDavid Miller 			rc = ERR_PTR(error);
485da6a8fa0SDavid Miller 			goto out_neigh_release;
486da6a8fa0SDavid Miller 		}
487da6a8fa0SDavid Miller 	}
488da6a8fa0SDavid Miller 
489447f2191SDavid S. Miller 	/* Device specific setup. */
490447f2191SDavid S. Miller 	if (n->parms->neigh_setup &&
491447f2191SDavid S. Miller 	    (error = n->parms->neigh_setup(n)) < 0) {
492447f2191SDavid S. Miller 		rc = ERR_PTR(error);
493447f2191SDavid S. Miller 		goto out_neigh_release;
494447f2191SDavid S. Miller 	}
495447f2191SDavid S. Miller 
4961f9248e5SJiri Pirko 	n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1);
4971da177e4SLinus Torvalds 
4981da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
499d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
500d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
5011da177e4SLinus Torvalds 
502cd089336SDavid S. Miller 	if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
503cd089336SDavid S. Miller 		nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
5041da177e4SLinus Torvalds 
505cd089336SDavid S. Miller 	hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
5061da177e4SLinus Torvalds 
5071da177e4SLinus Torvalds 	if (n->parms->dead) {
5081da177e4SLinus Torvalds 		rc = ERR_PTR(-EINVAL);
5091da177e4SLinus Torvalds 		goto out_tbl_unlock;
5101da177e4SLinus Torvalds 	}
5111da177e4SLinus Torvalds 
512767e97e1SEric Dumazet 	for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
513767e97e1SEric Dumazet 					    lockdep_is_held(&tbl->lock));
514767e97e1SEric Dumazet 	     n1 != NULL;
515767e97e1SEric Dumazet 	     n1 = rcu_dereference_protected(n1->next,
516767e97e1SEric Dumazet 			lockdep_is_held(&tbl->lock))) {
5171da177e4SLinus Torvalds 		if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {
518a263b309SDavid S. Miller 			if (want_ref)
5191da177e4SLinus Torvalds 				neigh_hold(n1);
5201da177e4SLinus Torvalds 			rc = n1;
5211da177e4SLinus Torvalds 			goto out_tbl_unlock;
5221da177e4SLinus Torvalds 		}
5231da177e4SLinus Torvalds 	}
5241da177e4SLinus Torvalds 
5251da177e4SLinus Torvalds 	n->dead = 0;
526a263b309SDavid S. Miller 	if (want_ref)
5271da177e4SLinus Torvalds 		neigh_hold(n);
528767e97e1SEric Dumazet 	rcu_assign_pointer(n->next,
529767e97e1SEric Dumazet 			   rcu_dereference_protected(nht->hash_buckets[hash_val],
530767e97e1SEric Dumazet 						     lockdep_is_held(&tbl->lock)));
531767e97e1SEric Dumazet 	rcu_assign_pointer(nht->hash_buckets[hash_val], n);
5321da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
533d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is created\n", n);
5341da177e4SLinus Torvalds 	rc = n;
5351da177e4SLinus Torvalds out:
5361da177e4SLinus Torvalds 	return rc;
5371da177e4SLinus Torvalds out_tbl_unlock:
5381da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
5391da177e4SLinus Torvalds out_neigh_release:
5401da177e4SLinus Torvalds 	neigh_release(n);
5411da177e4SLinus Torvalds 	goto out;
5421da177e4SLinus Torvalds }
543a263b309SDavid S. Miller EXPORT_SYMBOL(__neigh_create);
5441da177e4SLinus Torvalds 
545be01d655SYOSHIFUJI Hideaki static u32 pneigh_hash(const void *pkey, int key_len)
546fa86d322SPavel Emelyanov {
547fa86d322SPavel Emelyanov 	u32 hash_val = *(u32 *)(pkey + key_len - 4);
548fa86d322SPavel Emelyanov 	hash_val ^= (hash_val >> 16);
549fa86d322SPavel Emelyanov 	hash_val ^= hash_val >> 8;
550fa86d322SPavel Emelyanov 	hash_val ^= hash_val >> 4;
551fa86d322SPavel Emelyanov 	hash_val &= PNEIGH_HASHMASK;
552be01d655SYOSHIFUJI Hideaki 	return hash_val;
553fa86d322SPavel Emelyanov }
554fa86d322SPavel Emelyanov 
555be01d655SYOSHIFUJI Hideaki static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
556be01d655SYOSHIFUJI Hideaki 					      struct net *net,
557be01d655SYOSHIFUJI Hideaki 					      const void *pkey,
558be01d655SYOSHIFUJI Hideaki 					      int key_len,
559be01d655SYOSHIFUJI Hideaki 					      struct net_device *dev)
560be01d655SYOSHIFUJI Hideaki {
561be01d655SYOSHIFUJI Hideaki 	while (n) {
562be01d655SYOSHIFUJI Hideaki 		if (!memcmp(n->key, pkey, key_len) &&
563be01d655SYOSHIFUJI Hideaki 		    net_eq(pneigh_net(n), net) &&
564be01d655SYOSHIFUJI Hideaki 		    (n->dev == dev || !n->dev))
565fa86d322SPavel Emelyanov 			return n;
566be01d655SYOSHIFUJI Hideaki 		n = n->next;
567be01d655SYOSHIFUJI Hideaki 	}
568be01d655SYOSHIFUJI Hideaki 	return NULL;
569be01d655SYOSHIFUJI Hideaki }
570be01d655SYOSHIFUJI Hideaki 
571be01d655SYOSHIFUJI Hideaki struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
572be01d655SYOSHIFUJI Hideaki 		struct net *net, const void *pkey, struct net_device *dev)
573be01d655SYOSHIFUJI Hideaki {
574be01d655SYOSHIFUJI Hideaki 	int key_len = tbl->key_len;
575be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
576be01d655SYOSHIFUJI Hideaki 
577be01d655SYOSHIFUJI Hideaki 	return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
578be01d655SYOSHIFUJI Hideaki 				 net, pkey, key_len, dev);
579fa86d322SPavel Emelyanov }
5800a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL_GPL(__pneigh_lookup);
581fa86d322SPavel Emelyanov 
582426b5303SEric W. Biederman struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
583426b5303SEric W. Biederman 				    struct net *net, const void *pkey,
5841da177e4SLinus Torvalds 				    struct net_device *dev, int creat)
5851da177e4SLinus Torvalds {
5861da177e4SLinus Torvalds 	struct pneigh_entry *n;
5871da177e4SLinus Torvalds 	int key_len = tbl->key_len;
588be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
5891da177e4SLinus Torvalds 
5901da177e4SLinus Torvalds 	read_lock_bh(&tbl->lock);
591be01d655SYOSHIFUJI Hideaki 	n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
592be01d655SYOSHIFUJI Hideaki 			      net, pkey, key_len, dev);
593be01d655SYOSHIFUJI Hideaki 	read_unlock_bh(&tbl->lock);
5941da177e4SLinus Torvalds 
595be01d655SYOSHIFUJI Hideaki 	if (n || !creat)
5961da177e4SLinus Torvalds 		goto out;
5971da177e4SLinus Torvalds 
5984ae28944SPavel Emelyanov 	ASSERT_RTNL();
5994ae28944SPavel Emelyanov 
6001da177e4SLinus Torvalds 	n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
6011da177e4SLinus Torvalds 	if (!n)
6021da177e4SLinus Torvalds 		goto out;
6031da177e4SLinus Torvalds 
604e42ea986SEric Dumazet 	write_pnet(&n->net, hold_net(net));
6051da177e4SLinus Torvalds 	memcpy(n->key, pkey, key_len);
6061da177e4SLinus Torvalds 	n->dev = dev;
6071da177e4SLinus Torvalds 	if (dev)
6081da177e4SLinus Torvalds 		dev_hold(dev);
6091da177e4SLinus Torvalds 
6101da177e4SLinus Torvalds 	if (tbl->pconstructor && tbl->pconstructor(n)) {
6111da177e4SLinus Torvalds 		if (dev)
6121da177e4SLinus Torvalds 			dev_put(dev);
613da12f735SDenis V. Lunev 		release_net(net);
6141da177e4SLinus Torvalds 		kfree(n);
6151da177e4SLinus Torvalds 		n = NULL;
6161da177e4SLinus Torvalds 		goto out;
6171da177e4SLinus Torvalds 	}
6181da177e4SLinus Torvalds 
6191da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
6201da177e4SLinus Torvalds 	n->next = tbl->phash_buckets[hash_val];
6211da177e4SLinus Torvalds 	tbl->phash_buckets[hash_val] = n;
6221da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
6231da177e4SLinus Torvalds out:
6241da177e4SLinus Torvalds 	return n;
6251da177e4SLinus Torvalds }
6260a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(pneigh_lookup);
6271da177e4SLinus Torvalds 
6281da177e4SLinus Torvalds 
629426b5303SEric W. Biederman int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
6301da177e4SLinus Torvalds 		  struct net_device *dev)
6311da177e4SLinus Torvalds {
6321da177e4SLinus Torvalds 	struct pneigh_entry *n, **np;
6331da177e4SLinus Torvalds 	int key_len = tbl->key_len;
634be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
6351da177e4SLinus Torvalds 
6361da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
6371da177e4SLinus Torvalds 	for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
6381da177e4SLinus Torvalds 	     np = &n->next) {
639426b5303SEric W. Biederman 		if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
640878628fbSYOSHIFUJI Hideaki 		    net_eq(pneigh_net(n), net)) {
6411da177e4SLinus Torvalds 			*np = n->next;
6421da177e4SLinus Torvalds 			write_unlock_bh(&tbl->lock);
6431da177e4SLinus Torvalds 			if (tbl->pdestructor)
6441da177e4SLinus Torvalds 				tbl->pdestructor(n);
6451da177e4SLinus Torvalds 			if (n->dev)
6461da177e4SLinus Torvalds 				dev_put(n->dev);
64757da52c1SYOSHIFUJI Hideaki 			release_net(pneigh_net(n));
6481da177e4SLinus Torvalds 			kfree(n);
6491da177e4SLinus Torvalds 			return 0;
6501da177e4SLinus Torvalds 		}
6511da177e4SLinus Torvalds 	}
6521da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
6531da177e4SLinus Torvalds 	return -ENOENT;
6541da177e4SLinus Torvalds }
6551da177e4SLinus Torvalds 
6561da177e4SLinus Torvalds static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
6571da177e4SLinus Torvalds {
6581da177e4SLinus Torvalds 	struct pneigh_entry *n, **np;
6591da177e4SLinus Torvalds 	u32 h;
6601da177e4SLinus Torvalds 
6611da177e4SLinus Torvalds 	for (h = 0; h <= PNEIGH_HASHMASK; h++) {
6621da177e4SLinus Torvalds 		np = &tbl->phash_buckets[h];
6631da177e4SLinus Torvalds 		while ((n = *np) != NULL) {
6641da177e4SLinus Torvalds 			if (!dev || n->dev == dev) {
6651da177e4SLinus Torvalds 				*np = n->next;
6661da177e4SLinus Torvalds 				if (tbl->pdestructor)
6671da177e4SLinus Torvalds 					tbl->pdestructor(n);
6681da177e4SLinus Torvalds 				if (n->dev)
6691da177e4SLinus Torvalds 					dev_put(n->dev);
67057da52c1SYOSHIFUJI Hideaki 				release_net(pneigh_net(n));
6711da177e4SLinus Torvalds 				kfree(n);
6721da177e4SLinus Torvalds 				continue;
6731da177e4SLinus Torvalds 			}
6741da177e4SLinus Torvalds 			np = &n->next;
6751da177e4SLinus Torvalds 		}
6761da177e4SLinus Torvalds 	}
6771da177e4SLinus Torvalds 	return -ENOENT;
6781da177e4SLinus Torvalds }
6791da177e4SLinus Torvalds 
68006f0511dSDenis V. Lunev static void neigh_parms_destroy(struct neigh_parms *parms);
68106f0511dSDenis V. Lunev 
68206f0511dSDenis V. Lunev static inline void neigh_parms_put(struct neigh_parms *parms)
68306f0511dSDenis V. Lunev {
68406f0511dSDenis V. Lunev 	if (atomic_dec_and_test(&parms->refcnt))
68506f0511dSDenis V. Lunev 		neigh_parms_destroy(parms);
68606f0511dSDenis V. Lunev }
6871da177e4SLinus Torvalds 
6881da177e4SLinus Torvalds /*
6891da177e4SLinus Torvalds  *	neighbour must already be out of the table;
6901da177e4SLinus Torvalds  *
6911da177e4SLinus Torvalds  */
6921da177e4SLinus Torvalds void neigh_destroy(struct neighbour *neigh)
6931da177e4SLinus Torvalds {
694da6a8fa0SDavid Miller 	struct net_device *dev = neigh->dev;
695da6a8fa0SDavid Miller 
6961da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
6971da177e4SLinus Torvalds 
6981da177e4SLinus Torvalds 	if (!neigh->dead) {
699e005d193SJoe Perches 		pr_warn("Destroying alive neighbour %p\n", neigh);
7001da177e4SLinus Torvalds 		dump_stack();
7011da177e4SLinus Torvalds 		return;
7021da177e4SLinus Torvalds 	}
7031da177e4SLinus Torvalds 
7041da177e4SLinus Torvalds 	if (neigh_del_timer(neigh))
705e005d193SJoe Perches 		pr_warn("Impossible event\n");
7061da177e4SLinus Torvalds 
707c9ab4d85SEric Dumazet 	write_lock_bh(&neigh->lock);
708c9ab4d85SEric Dumazet 	__skb_queue_purge(&neigh->arp_queue);
709c9ab4d85SEric Dumazet 	write_unlock_bh(&neigh->lock);
7108b5c171bSEric Dumazet 	neigh->arp_queue_len_bytes = 0;
7111da177e4SLinus Torvalds 
712447f2191SDavid S. Miller 	if (dev->netdev_ops->ndo_neigh_destroy)
713447f2191SDavid S. Miller 		dev->netdev_ops->ndo_neigh_destroy(neigh);
714447f2191SDavid S. Miller 
715da6a8fa0SDavid Miller 	dev_put(dev);
7161da177e4SLinus Torvalds 	neigh_parms_put(neigh->parms);
7171da177e4SLinus Torvalds 
718d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is destroyed\n", neigh);
7191da177e4SLinus Torvalds 
7201da177e4SLinus Torvalds 	atomic_dec(&neigh->tbl->entries);
7215b8b0060SDavid Miller 	kfree_rcu(neigh, rcu);
7221da177e4SLinus Torvalds }
7230a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_destroy);
7241da177e4SLinus Torvalds 
7251da177e4SLinus Torvalds /* Neighbour state is suspicious;
7261da177e4SLinus Torvalds    disable fast path.
7271da177e4SLinus Torvalds 
7281da177e4SLinus Torvalds    Called with write_locked neigh.
7291da177e4SLinus Torvalds  */
7301da177e4SLinus Torvalds static void neigh_suspect(struct neighbour *neigh)
7311da177e4SLinus Torvalds {
732d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is suspected\n", neigh);
7331da177e4SLinus Torvalds 
7341da177e4SLinus Torvalds 	neigh->output = neigh->ops->output;
7351da177e4SLinus Torvalds }
7361da177e4SLinus Torvalds 
7371da177e4SLinus Torvalds /* Neighbour state is OK;
7381da177e4SLinus Torvalds    enable fast path.
7391da177e4SLinus Torvalds 
7401da177e4SLinus Torvalds    Called with write_locked neigh.
7411da177e4SLinus Torvalds  */
7421da177e4SLinus Torvalds static void neigh_connect(struct neighbour *neigh)
7431da177e4SLinus Torvalds {
744d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is connected\n", neigh);
7451da177e4SLinus Torvalds 
7461da177e4SLinus Torvalds 	neigh->output = neigh->ops->connected_output;
7471da177e4SLinus Torvalds }
7481da177e4SLinus Torvalds 
749e4c4e448SEric Dumazet static void neigh_periodic_work(struct work_struct *work)
7501da177e4SLinus Torvalds {
751e4c4e448SEric Dumazet 	struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
752767e97e1SEric Dumazet 	struct neighbour *n;
753767e97e1SEric Dumazet 	struct neighbour __rcu **np;
754e4c4e448SEric Dumazet 	unsigned int i;
755d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
7561da177e4SLinus Torvalds 
7571da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
7581da177e4SLinus Torvalds 
759e4c4e448SEric Dumazet 	write_lock_bh(&tbl->lock);
760d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
761d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
7621da177e4SLinus Torvalds 
7631da177e4SLinus Torvalds 	/*
7641da177e4SLinus Torvalds 	 *	periodically recompute ReachableTime from random function
7651da177e4SLinus Torvalds 	 */
7661da177e4SLinus Torvalds 
767e4c4e448SEric Dumazet 	if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
7681da177e4SLinus Torvalds 		struct neigh_parms *p;
769e4c4e448SEric Dumazet 		tbl->last_rand = jiffies;
77075fbfd33SNicolas Dichtel 		list_for_each_entry(p, &tbl->parms_list, list)
7711da177e4SLinus Torvalds 			p->reachable_time =
7721f9248e5SJiri Pirko 				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
7731da177e4SLinus Torvalds 	}
7741da177e4SLinus Torvalds 
775feff9ab2SDuan Jiong 	if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
776feff9ab2SDuan Jiong 		goto out;
777feff9ab2SDuan Jiong 
778cd089336SDavid S. Miller 	for (i = 0 ; i < (1 << nht->hash_shift); i++) {
779d6bf7817SEric Dumazet 		np = &nht->hash_buckets[i];
7801da177e4SLinus Torvalds 
781767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
782767e97e1SEric Dumazet 				lockdep_is_held(&tbl->lock))) != NULL) {
7831da177e4SLinus Torvalds 			unsigned int state;
7841da177e4SLinus Torvalds 
7851da177e4SLinus Torvalds 			write_lock(&n->lock);
7861da177e4SLinus Torvalds 
7871da177e4SLinus Torvalds 			state = n->nud_state;
7881da177e4SLinus Torvalds 			if (state & (NUD_PERMANENT | NUD_IN_TIMER)) {
7891da177e4SLinus Torvalds 				write_unlock(&n->lock);
7901da177e4SLinus Torvalds 				goto next_elt;
7911da177e4SLinus Torvalds 			}
7921da177e4SLinus Torvalds 
7931da177e4SLinus Torvalds 			if (time_before(n->used, n->confirmed))
7941da177e4SLinus Torvalds 				n->used = n->confirmed;
7951da177e4SLinus Torvalds 
7961da177e4SLinus Torvalds 			if (atomic_read(&n->refcnt) == 1 &&
7971da177e4SLinus Torvalds 			    (state == NUD_FAILED ||
7981f9248e5SJiri Pirko 			     time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
7991da177e4SLinus Torvalds 				*np = n->next;
8001da177e4SLinus Torvalds 				n->dead = 1;
8011da177e4SLinus Torvalds 				write_unlock(&n->lock);
8024f494554SThomas Graf 				neigh_cleanup_and_release(n);
8031da177e4SLinus Torvalds 				continue;
8041da177e4SLinus Torvalds 			}
8051da177e4SLinus Torvalds 			write_unlock(&n->lock);
8061da177e4SLinus Torvalds 
8071da177e4SLinus Torvalds next_elt:
8081da177e4SLinus Torvalds 			np = &n->next;
8091da177e4SLinus Torvalds 		}
810e4c4e448SEric Dumazet 		/*
811e4c4e448SEric Dumazet 		 * It's fine to release lock here, even if hash table
812e4c4e448SEric Dumazet 		 * grows while we are preempted.
813e4c4e448SEric Dumazet 		 */
814e4c4e448SEric Dumazet 		write_unlock_bh(&tbl->lock);
815e4c4e448SEric Dumazet 		cond_resched();
816e4c4e448SEric Dumazet 		write_lock_bh(&tbl->lock);
81784338a6cSMichel Machado 		nht = rcu_dereference_protected(tbl->nht,
81884338a6cSMichel Machado 						lockdep_is_held(&tbl->lock));
819e4c4e448SEric Dumazet 	}
8202724680bSYOSHIFUJI Hideaki / 吉藤英明 out:
8211f9248e5SJiri Pirko 	/* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks.
8221f9248e5SJiri Pirko 	 * ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2
8231f9248e5SJiri Pirko 	 * BASE_REACHABLE_TIME.
8241da177e4SLinus Torvalds 	 */
825f618002bSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
8261f9248e5SJiri Pirko 			      NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1);
827e4c4e448SEric Dumazet 	write_unlock_bh(&tbl->lock);
8281da177e4SLinus Torvalds }
8291da177e4SLinus Torvalds 
8301da177e4SLinus Torvalds static __inline__ int neigh_max_probes(struct neighbour *n)
8311da177e4SLinus Torvalds {
8321da177e4SLinus Torvalds 	struct neigh_parms *p = n->parms;
833a960ff81STimo Teräs 	int max_probes = NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES);
834a960ff81STimo Teräs 	if (!(n->nud_state & NUD_PROBE))
835a960ff81STimo Teräs 		max_probes += NEIGH_VAR(p, MCAST_PROBES);
836a960ff81STimo Teräs 	return max_probes;
8371da177e4SLinus Torvalds }
8381da177e4SLinus Torvalds 
8395ef12d98STimo Teras static void neigh_invalidate(struct neighbour *neigh)
8400a141509SEric Dumazet 	__releases(neigh->lock)
8410a141509SEric Dumazet 	__acquires(neigh->lock)
8425ef12d98STimo Teras {
8435ef12d98STimo Teras 	struct sk_buff *skb;
8445ef12d98STimo Teras 
8455ef12d98STimo Teras 	NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
846d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is failed\n", neigh);
8475ef12d98STimo Teras 	neigh->updated = jiffies;
8485ef12d98STimo Teras 
8495ef12d98STimo Teras 	/* It is very thin place. report_unreachable is very complicated
8505ef12d98STimo Teras 	   routine. Particularly, it can hit the same neighbour entry!
8515ef12d98STimo Teras 
8525ef12d98STimo Teras 	   So that, we try to be accurate and avoid dead loop. --ANK
8535ef12d98STimo Teras 	 */
8545ef12d98STimo Teras 	while (neigh->nud_state == NUD_FAILED &&
8555ef12d98STimo Teras 	       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
8565ef12d98STimo Teras 		write_unlock(&neigh->lock);
8575ef12d98STimo Teras 		neigh->ops->error_report(neigh, skb);
8585ef12d98STimo Teras 		write_lock(&neigh->lock);
8595ef12d98STimo Teras 	}
860c9ab4d85SEric Dumazet 	__skb_queue_purge(&neigh->arp_queue);
8618b5c171bSEric Dumazet 	neigh->arp_queue_len_bytes = 0;
8625ef12d98STimo Teras }
8635ef12d98STimo Teras 
864cd28ca0aSEric Dumazet static void neigh_probe(struct neighbour *neigh)
865cd28ca0aSEric Dumazet 	__releases(neigh->lock)
866cd28ca0aSEric Dumazet {
8674ed377e3SHannes Frederic Sowa 	struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);
868cd28ca0aSEric Dumazet 	/* keep skb alive even if arp_queue overflows */
869cd28ca0aSEric Dumazet 	if (skb)
870cd28ca0aSEric Dumazet 		skb = skb_copy(skb, GFP_ATOMIC);
871cd28ca0aSEric Dumazet 	write_unlock(&neigh->lock);
872cd28ca0aSEric Dumazet 	neigh->ops->solicit(neigh, skb);
873cd28ca0aSEric Dumazet 	atomic_inc(&neigh->probes);
874cd28ca0aSEric Dumazet 	kfree_skb(skb);
875cd28ca0aSEric Dumazet }
876cd28ca0aSEric Dumazet 
8771da177e4SLinus Torvalds /* Called when a timer expires for a neighbour entry. */
8781da177e4SLinus Torvalds 
8791da177e4SLinus Torvalds static void neigh_timer_handler(unsigned long arg)
8801da177e4SLinus Torvalds {
8811da177e4SLinus Torvalds 	unsigned long now, next;
8821da177e4SLinus Torvalds 	struct neighbour *neigh = (struct neighbour *)arg;
88395c96174SEric Dumazet 	unsigned int state;
8841da177e4SLinus Torvalds 	int notify = 0;
8851da177e4SLinus Torvalds 
8861da177e4SLinus Torvalds 	write_lock(&neigh->lock);
8871da177e4SLinus Torvalds 
8881da177e4SLinus Torvalds 	state = neigh->nud_state;
8891da177e4SLinus Torvalds 	now = jiffies;
8901da177e4SLinus Torvalds 	next = now + HZ;
8911da177e4SLinus Torvalds 
892045f7b3bSDavid S. Miller 	if (!(state & NUD_IN_TIMER))
8931da177e4SLinus Torvalds 		goto out;
8941da177e4SLinus Torvalds 
8951da177e4SLinus Torvalds 	if (state & NUD_REACHABLE) {
8961da177e4SLinus Torvalds 		if (time_before_eq(now,
8971da177e4SLinus Torvalds 				   neigh->confirmed + neigh->parms->reachable_time)) {
898d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is still alive\n", neigh);
8991da177e4SLinus Torvalds 			next = neigh->confirmed + neigh->parms->reachable_time;
9001da177e4SLinus Torvalds 		} else if (time_before_eq(now,
9011f9248e5SJiri Pirko 					  neigh->used +
9021f9248e5SJiri Pirko 					  NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
903d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is delayed\n", neigh);
9041da177e4SLinus Torvalds 			neigh->nud_state = NUD_DELAY;
905955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
9061da177e4SLinus Torvalds 			neigh_suspect(neigh);
9071f9248e5SJiri Pirko 			next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME);
9081da177e4SLinus Torvalds 		} else {
909d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is suspected\n", neigh);
9101da177e4SLinus Torvalds 			neigh->nud_state = NUD_STALE;
911955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
9121da177e4SLinus Torvalds 			neigh_suspect(neigh);
9138d71740cSTom Tucker 			notify = 1;
9141da177e4SLinus Torvalds 		}
9151da177e4SLinus Torvalds 	} else if (state & NUD_DELAY) {
9161da177e4SLinus Torvalds 		if (time_before_eq(now,
9171f9248e5SJiri Pirko 				   neigh->confirmed +
9181f9248e5SJiri Pirko 				   NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
919d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is now reachable\n", neigh);
9201da177e4SLinus Torvalds 			neigh->nud_state = NUD_REACHABLE;
921955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
9221da177e4SLinus Torvalds 			neigh_connect(neigh);
9238d71740cSTom Tucker 			notify = 1;
9241da177e4SLinus Torvalds 			next = neigh->confirmed + neigh->parms->reachable_time;
9251da177e4SLinus Torvalds 		} else {
926d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is probed\n", neigh);
9271da177e4SLinus Torvalds 			neigh->nud_state = NUD_PROBE;
928955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
9291da177e4SLinus Torvalds 			atomic_set(&neigh->probes, 0);
9301f9248e5SJiri Pirko 			next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
9311da177e4SLinus Torvalds 		}
9321da177e4SLinus Torvalds 	} else {
9331da177e4SLinus Torvalds 		/* NUD_PROBE|NUD_INCOMPLETE */
9341f9248e5SJiri Pirko 		next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
9351da177e4SLinus Torvalds 	}
9361da177e4SLinus Torvalds 
9371da177e4SLinus Torvalds 	if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
9381da177e4SLinus Torvalds 	    atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
9391da177e4SLinus Torvalds 		neigh->nud_state = NUD_FAILED;
9401da177e4SLinus Torvalds 		notify = 1;
9415ef12d98STimo Teras 		neigh_invalidate(neigh);
9425e2c21dcSDuan Jiong 		goto out;
9431da177e4SLinus Torvalds 	}
9441da177e4SLinus Torvalds 
9451da177e4SLinus Torvalds 	if (neigh->nud_state & NUD_IN_TIMER) {
9461da177e4SLinus Torvalds 		if (time_before(next, jiffies + HZ/2))
9471da177e4SLinus Torvalds 			next = jiffies + HZ/2;
9486fb9974fSHerbert Xu 		if (!mod_timer(&neigh->timer, next))
9496fb9974fSHerbert Xu 			neigh_hold(neigh);
9501da177e4SLinus Torvalds 	}
9511da177e4SLinus Torvalds 	if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
952cd28ca0aSEric Dumazet 		neigh_probe(neigh);
9539ff56607SDavid S. Miller 	} else {
9541da177e4SLinus Torvalds out:
9551da177e4SLinus Torvalds 		write_unlock(&neigh->lock);
9569ff56607SDavid S. Miller 	}
9571da177e4SLinus Torvalds 
958d961db35SThomas Graf 	if (notify)
959d961db35SThomas Graf 		neigh_update_notify(neigh);
960d961db35SThomas Graf 
9611da177e4SLinus Torvalds 	neigh_release(neigh);
9621da177e4SLinus Torvalds }
9631da177e4SLinus Torvalds 
9641da177e4SLinus Torvalds int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
9651da177e4SLinus Torvalds {
9661da177e4SLinus Torvalds 	int rc;
967cd28ca0aSEric Dumazet 	bool immediate_probe = false;
9681da177e4SLinus Torvalds 
9691da177e4SLinus Torvalds 	write_lock_bh(&neigh->lock);
9701da177e4SLinus Torvalds 
9711da177e4SLinus Torvalds 	rc = 0;
9721da177e4SLinus Torvalds 	if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
9731da177e4SLinus Torvalds 		goto out_unlock_bh;
9741da177e4SLinus Torvalds 
9751da177e4SLinus Torvalds 	if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
9761f9248e5SJiri Pirko 		if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
9771f9248e5SJiri Pirko 		    NEIGH_VAR(neigh->parms, APP_PROBES)) {
978cd28ca0aSEric Dumazet 			unsigned long next, now = jiffies;
979cd28ca0aSEric Dumazet 
9801f9248e5SJiri Pirko 			atomic_set(&neigh->probes,
9811f9248e5SJiri Pirko 				   NEIGH_VAR(neigh->parms, UCAST_PROBES));
9821da177e4SLinus Torvalds 			neigh->nud_state     = NUD_INCOMPLETE;
983cd28ca0aSEric Dumazet 			neigh->updated = now;
9841f9248e5SJiri Pirko 			next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
9851f9248e5SJiri Pirko 					 HZ/2);
986cd28ca0aSEric Dumazet 			neigh_add_timer(neigh, next);
987cd28ca0aSEric Dumazet 			immediate_probe = true;
9881da177e4SLinus Torvalds 		} else {
9891da177e4SLinus Torvalds 			neigh->nud_state = NUD_FAILED;
990955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
9911da177e4SLinus Torvalds 			write_unlock_bh(&neigh->lock);
9921da177e4SLinus Torvalds 
9931da177e4SLinus Torvalds 			kfree_skb(skb);
9941da177e4SLinus Torvalds 			return 1;
9951da177e4SLinus Torvalds 		}
9961da177e4SLinus Torvalds 	} else if (neigh->nud_state & NUD_STALE) {
997d5d427cdSJoe Perches 		neigh_dbg(2, "neigh %p is delayed\n", neigh);
9981da177e4SLinus Torvalds 		neigh->nud_state = NUD_DELAY;
999955aaa2fSYOSHIFUJI Hideaki 		neigh->updated = jiffies;
10001f9248e5SJiri Pirko 		neigh_add_timer(neigh, jiffies +
10011f9248e5SJiri Pirko 				NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME));
10021da177e4SLinus Torvalds 	}
10031da177e4SLinus Torvalds 
10041da177e4SLinus Torvalds 	if (neigh->nud_state == NUD_INCOMPLETE) {
10051da177e4SLinus Torvalds 		if (skb) {
10068b5c171bSEric Dumazet 			while (neigh->arp_queue_len_bytes + skb->truesize >
10071f9248e5SJiri Pirko 			       NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) {
10081da177e4SLinus Torvalds 				struct sk_buff *buff;
10098b5c171bSEric Dumazet 
1010f72051b0SDavid S. Miller 				buff = __skb_dequeue(&neigh->arp_queue);
10118b5c171bSEric Dumazet 				if (!buff)
10128b5c171bSEric Dumazet 					break;
10138b5c171bSEric Dumazet 				neigh->arp_queue_len_bytes -= buff->truesize;
10141da177e4SLinus Torvalds 				kfree_skb(buff);
10159a6d276eSNeil Horman 				NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
10161da177e4SLinus Torvalds 			}
1017a4731138SEric Dumazet 			skb_dst_force(skb);
10181da177e4SLinus Torvalds 			__skb_queue_tail(&neigh->arp_queue, skb);
10198b5c171bSEric Dumazet 			neigh->arp_queue_len_bytes += skb->truesize;
10201da177e4SLinus Torvalds 		}
10211da177e4SLinus Torvalds 		rc = 1;
10221da177e4SLinus Torvalds 	}
10231da177e4SLinus Torvalds out_unlock_bh:
1024cd28ca0aSEric Dumazet 	if (immediate_probe)
1025cd28ca0aSEric Dumazet 		neigh_probe(neigh);
1026cd28ca0aSEric Dumazet 	else
1027cd28ca0aSEric Dumazet 		write_unlock(&neigh->lock);
1028cd28ca0aSEric Dumazet 	local_bh_enable();
10291da177e4SLinus Torvalds 	return rc;
10301da177e4SLinus Torvalds }
10310a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(__neigh_event_send);
10321da177e4SLinus Torvalds 
1033f6b72b62SDavid S. Miller static void neigh_update_hhs(struct neighbour *neigh)
10341da177e4SLinus Torvalds {
10351da177e4SLinus Torvalds 	struct hh_cache *hh;
10363b04dddeSStephen Hemminger 	void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
103791a72a70SDoug Kehn 		= NULL;
103891a72a70SDoug Kehn 
103991a72a70SDoug Kehn 	if (neigh->dev->header_ops)
104091a72a70SDoug Kehn 		update = neigh->dev->header_ops->cache_update;
10411da177e4SLinus Torvalds 
10421da177e4SLinus Torvalds 	if (update) {
1043f6b72b62SDavid S. Miller 		hh = &neigh->hh;
1044f6b72b62SDavid S. Miller 		if (hh->hh_len) {
10453644f0ceSStephen Hemminger 			write_seqlock_bh(&hh->hh_lock);
10461da177e4SLinus Torvalds 			update(hh, neigh->dev, neigh->ha);
10473644f0ceSStephen Hemminger 			write_sequnlock_bh(&hh->hh_lock);
10481da177e4SLinus Torvalds 		}
10491da177e4SLinus Torvalds 	}
10501da177e4SLinus Torvalds }
10511da177e4SLinus Torvalds 
10521da177e4SLinus Torvalds 
10531da177e4SLinus Torvalds 
10541da177e4SLinus Torvalds /* Generic update routine.
10551da177e4SLinus Torvalds    -- lladdr is new lladdr or NULL, if it is not supplied.
10561da177e4SLinus Torvalds    -- new    is new state.
10571da177e4SLinus Torvalds    -- flags
10581da177e4SLinus Torvalds 	NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
10591da177e4SLinus Torvalds 				if it is different.
10601da177e4SLinus Torvalds 	NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
10611da177e4SLinus Torvalds 				lladdr instead of overriding it
10621da177e4SLinus Torvalds 				if it is different.
10631da177e4SLinus Torvalds 				It also allows to retain current state
10641da177e4SLinus Torvalds 				if lladdr is unchanged.
10651da177e4SLinus Torvalds 	NEIGH_UPDATE_F_ADMIN	means that the change is administrative.
10661da177e4SLinus Torvalds 
10671da177e4SLinus Torvalds 	NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
10681da177e4SLinus Torvalds 				NTF_ROUTER flag.
10691da177e4SLinus Torvalds 	NEIGH_UPDATE_F_ISROUTER	indicates if the neighbour is known as
10701da177e4SLinus Torvalds 				a router.
10711da177e4SLinus Torvalds 
10721da177e4SLinus Torvalds    Caller MUST hold reference count on the entry.
10731da177e4SLinus Torvalds  */
10741da177e4SLinus Torvalds 
10751da177e4SLinus Torvalds int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
10761da177e4SLinus Torvalds 		 u32 flags)
10771da177e4SLinus Torvalds {
10781da177e4SLinus Torvalds 	u8 old;
10791da177e4SLinus Torvalds 	int err;
10801da177e4SLinus Torvalds 	int notify = 0;
10811da177e4SLinus Torvalds 	struct net_device *dev;
10821da177e4SLinus Torvalds 	int update_isrouter = 0;
10831da177e4SLinus Torvalds 
10841da177e4SLinus Torvalds 	write_lock_bh(&neigh->lock);
10851da177e4SLinus Torvalds 
10861da177e4SLinus Torvalds 	dev    = neigh->dev;
10871da177e4SLinus Torvalds 	old    = neigh->nud_state;
10881da177e4SLinus Torvalds 	err    = -EPERM;
10891da177e4SLinus Torvalds 
10901da177e4SLinus Torvalds 	if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
10911da177e4SLinus Torvalds 	    (old & (NUD_NOARP | NUD_PERMANENT)))
10921da177e4SLinus Torvalds 		goto out;
10931da177e4SLinus Torvalds 
10941da177e4SLinus Torvalds 	if (!(new & NUD_VALID)) {
10951da177e4SLinus Torvalds 		neigh_del_timer(neigh);
10961da177e4SLinus Torvalds 		if (old & NUD_CONNECTED)
10971da177e4SLinus Torvalds 			neigh_suspect(neigh);
10981da177e4SLinus Torvalds 		neigh->nud_state = new;
10991da177e4SLinus Torvalds 		err = 0;
11001da177e4SLinus Torvalds 		notify = old & NUD_VALID;
11015ef12d98STimo Teras 		if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
11025ef12d98STimo Teras 		    (new & NUD_FAILED)) {
11035ef12d98STimo Teras 			neigh_invalidate(neigh);
11045ef12d98STimo Teras 			notify = 1;
11055ef12d98STimo Teras 		}
11061da177e4SLinus Torvalds 		goto out;
11071da177e4SLinus Torvalds 	}
11081da177e4SLinus Torvalds 
11091da177e4SLinus Torvalds 	/* Compare new lladdr with cached one */
11101da177e4SLinus Torvalds 	if (!dev->addr_len) {
11111da177e4SLinus Torvalds 		/* First case: device needs no address. */
11121da177e4SLinus Torvalds 		lladdr = neigh->ha;
11131da177e4SLinus Torvalds 	} else if (lladdr) {
11141da177e4SLinus Torvalds 		/* The second case: if something is already cached
11151da177e4SLinus Torvalds 		   and a new address is proposed:
11161da177e4SLinus Torvalds 		   - compare new & old
11171da177e4SLinus Torvalds 		   - if they are different, check override flag
11181da177e4SLinus Torvalds 		 */
11191da177e4SLinus Torvalds 		if ((old & NUD_VALID) &&
11201da177e4SLinus Torvalds 		    !memcmp(lladdr, neigh->ha, dev->addr_len))
11211da177e4SLinus Torvalds 			lladdr = neigh->ha;
11221da177e4SLinus Torvalds 	} else {
11231da177e4SLinus Torvalds 		/* No address is supplied; if we know something,
11241da177e4SLinus Torvalds 		   use it, otherwise discard the request.
11251da177e4SLinus Torvalds 		 */
11261da177e4SLinus Torvalds 		err = -EINVAL;
11271da177e4SLinus Torvalds 		if (!(old & NUD_VALID))
11281da177e4SLinus Torvalds 			goto out;
11291da177e4SLinus Torvalds 		lladdr = neigh->ha;
11301da177e4SLinus Torvalds 	}
11311da177e4SLinus Torvalds 
11321da177e4SLinus Torvalds 	if (new & NUD_CONNECTED)
11331da177e4SLinus Torvalds 		neigh->confirmed = jiffies;
11341da177e4SLinus Torvalds 	neigh->updated = jiffies;
11351da177e4SLinus Torvalds 
11361da177e4SLinus Torvalds 	/* If entry was valid and address is not changed,
11371da177e4SLinus Torvalds 	   do not change entry state, if new one is STALE.
11381da177e4SLinus Torvalds 	 */
11391da177e4SLinus Torvalds 	err = 0;
11401da177e4SLinus Torvalds 	update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
11411da177e4SLinus Torvalds 	if (old & NUD_VALID) {
11421da177e4SLinus Torvalds 		if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
11431da177e4SLinus Torvalds 			update_isrouter = 0;
11441da177e4SLinus Torvalds 			if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
11451da177e4SLinus Torvalds 			    (old & NUD_CONNECTED)) {
11461da177e4SLinus Torvalds 				lladdr = neigh->ha;
11471da177e4SLinus Torvalds 				new = NUD_STALE;
11481da177e4SLinus Torvalds 			} else
11491da177e4SLinus Torvalds 				goto out;
11501da177e4SLinus Torvalds 		} else {
11511da177e4SLinus Torvalds 			if (lladdr == neigh->ha && new == NUD_STALE &&
11521da177e4SLinus Torvalds 			    ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) ||
11531da177e4SLinus Torvalds 			     (old & NUD_CONNECTED))
11541da177e4SLinus Torvalds 			    )
11551da177e4SLinus Torvalds 				new = old;
11561da177e4SLinus Torvalds 		}
11571da177e4SLinus Torvalds 	}
11581da177e4SLinus Torvalds 
11591da177e4SLinus Torvalds 	if (new != old) {
11601da177e4SLinus Torvalds 		neigh_del_timer(neigh);
1161a43d8994SPavel Emelyanov 		if (new & NUD_IN_TIMER)
1162667347f1SDavid S. Miller 			neigh_add_timer(neigh, (jiffies +
11631da177e4SLinus Torvalds 						((new & NUD_REACHABLE) ?
1164667347f1SDavid S. Miller 						 neigh->parms->reachable_time :
1165667347f1SDavid S. Miller 						 0)));
11661da177e4SLinus Torvalds 		neigh->nud_state = new;
116753385d2dSBob Gilligan 		notify = 1;
11681da177e4SLinus Torvalds 	}
11691da177e4SLinus Torvalds 
11701da177e4SLinus Torvalds 	if (lladdr != neigh->ha) {
11710ed8ddf4SEric Dumazet 		write_seqlock(&neigh->ha_lock);
11721da177e4SLinus Torvalds 		memcpy(&neigh->ha, lladdr, dev->addr_len);
11730ed8ddf4SEric Dumazet 		write_sequnlock(&neigh->ha_lock);
11741da177e4SLinus Torvalds 		neigh_update_hhs(neigh);
11751da177e4SLinus Torvalds 		if (!(new & NUD_CONNECTED))
11761da177e4SLinus Torvalds 			neigh->confirmed = jiffies -
11771f9248e5SJiri Pirko 				      (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1);
11781da177e4SLinus Torvalds 		notify = 1;
11791da177e4SLinus Torvalds 	}
11801da177e4SLinus Torvalds 	if (new == old)
11811da177e4SLinus Torvalds 		goto out;
11821da177e4SLinus Torvalds 	if (new & NUD_CONNECTED)
11831da177e4SLinus Torvalds 		neigh_connect(neigh);
11841da177e4SLinus Torvalds 	else
11851da177e4SLinus Torvalds 		neigh_suspect(neigh);
11861da177e4SLinus Torvalds 	if (!(old & NUD_VALID)) {
11871da177e4SLinus Torvalds 		struct sk_buff *skb;
11881da177e4SLinus Torvalds 
11891da177e4SLinus Torvalds 		/* Again: avoid dead loop if something went wrong */
11901da177e4SLinus Torvalds 
11911da177e4SLinus Torvalds 		while (neigh->nud_state & NUD_VALID &&
11921da177e4SLinus Torvalds 		       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
119369cce1d1SDavid S. Miller 			struct dst_entry *dst = skb_dst(skb);
119469cce1d1SDavid S. Miller 			struct neighbour *n2, *n1 = neigh;
11951da177e4SLinus Torvalds 			write_unlock_bh(&neigh->lock);
1196e049f288Sroy.qing.li@gmail.com 
1197e049f288Sroy.qing.li@gmail.com 			rcu_read_lock();
119813a43d94SDavid S. Miller 
119913a43d94SDavid S. Miller 			/* Why not just use 'neigh' as-is?  The problem is that
120013a43d94SDavid S. Miller 			 * things such as shaper, eql, and sch_teql can end up
120113a43d94SDavid S. Miller 			 * using alternative, different, neigh objects to output
120213a43d94SDavid S. Miller 			 * the packet in the output path.  So what we need to do
120313a43d94SDavid S. Miller 			 * here is re-lookup the top-level neigh in the path so
120413a43d94SDavid S. Miller 			 * we can reinject the packet there.
120513a43d94SDavid S. Miller 			 */
120613a43d94SDavid S. Miller 			n2 = NULL;
120713a43d94SDavid S. Miller 			if (dst) {
120813a43d94SDavid S. Miller 				n2 = dst_neigh_lookup_skb(dst, skb);
120913a43d94SDavid S. Miller 				if (n2)
121069cce1d1SDavid S. Miller 					n1 = n2;
121113a43d94SDavid S. Miller 			}
12128f40b161SDavid S. Miller 			n1->output(n1, skb);
121313a43d94SDavid S. Miller 			if (n2)
121413a43d94SDavid S. Miller 				neigh_release(n2);
1215e049f288Sroy.qing.li@gmail.com 			rcu_read_unlock();
1216e049f288Sroy.qing.li@gmail.com 
12171da177e4SLinus Torvalds 			write_lock_bh(&neigh->lock);
12181da177e4SLinus Torvalds 		}
1219c9ab4d85SEric Dumazet 		__skb_queue_purge(&neigh->arp_queue);
12208b5c171bSEric Dumazet 		neigh->arp_queue_len_bytes = 0;
12211da177e4SLinus Torvalds 	}
12221da177e4SLinus Torvalds out:
12231da177e4SLinus Torvalds 	if (update_isrouter) {
12241da177e4SLinus Torvalds 		neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ?
12251da177e4SLinus Torvalds 			(neigh->flags | NTF_ROUTER) :
12261da177e4SLinus Torvalds 			(neigh->flags & ~NTF_ROUTER);
12271da177e4SLinus Torvalds 	}
12281da177e4SLinus Torvalds 	write_unlock_bh(&neigh->lock);
12298d71740cSTom Tucker 
12308d71740cSTom Tucker 	if (notify)
1231d961db35SThomas Graf 		neigh_update_notify(neigh);
1232d961db35SThomas Graf 
12331da177e4SLinus Torvalds 	return err;
12341da177e4SLinus Torvalds }
12350a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_update);
12361da177e4SLinus Torvalds 
12377e980569SJiri Benc /* Update the neigh to listen temporarily for probe responses, even if it is
12387e980569SJiri Benc  * in a NUD_FAILED state. The caller has to hold neigh->lock for writing.
12397e980569SJiri Benc  */
12407e980569SJiri Benc void __neigh_set_probe_once(struct neighbour *neigh)
12417e980569SJiri Benc {
12427e980569SJiri Benc 	neigh->updated = jiffies;
12437e980569SJiri Benc 	if (!(neigh->nud_state & NUD_FAILED))
12447e980569SJiri Benc 		return;
12452176d5d4SDuan Jiong 	neigh->nud_state = NUD_INCOMPLETE;
12462176d5d4SDuan Jiong 	atomic_set(&neigh->probes, neigh_max_probes(neigh));
12477e980569SJiri Benc 	neigh_add_timer(neigh,
12487e980569SJiri Benc 			jiffies + NEIGH_VAR(neigh->parms, RETRANS_TIME));
12497e980569SJiri Benc }
12507e980569SJiri Benc EXPORT_SYMBOL(__neigh_set_probe_once);
12517e980569SJiri Benc 
12521da177e4SLinus Torvalds struct neighbour *neigh_event_ns(struct neigh_table *tbl,
12531da177e4SLinus Torvalds 				 u8 *lladdr, void *saddr,
12541da177e4SLinus Torvalds 				 struct net_device *dev)
12551da177e4SLinus Torvalds {
12561da177e4SLinus Torvalds 	struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
12571da177e4SLinus Torvalds 						 lladdr || !dev->addr_len);
12581da177e4SLinus Torvalds 	if (neigh)
12591da177e4SLinus Torvalds 		neigh_update(neigh, lladdr, NUD_STALE,
12601da177e4SLinus Torvalds 			     NEIGH_UPDATE_F_OVERRIDE);
12611da177e4SLinus Torvalds 	return neigh;
12621da177e4SLinus Torvalds }
12630a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_event_ns);
12641da177e4SLinus Torvalds 
126534d101ddSEric Dumazet /* called with read_lock_bh(&n->lock); */
1266f6b72b62SDavid S. Miller static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst)
12671da177e4SLinus Torvalds {
12681da177e4SLinus Torvalds 	struct net_device *dev = dst->dev;
1269f6b72b62SDavid S. Miller 	__be16 prot = dst->ops->protocol;
1270f6b72b62SDavid S. Miller 	struct hh_cache	*hh = &n->hh;
12710ed8ddf4SEric Dumazet 
12720ed8ddf4SEric Dumazet 	write_lock_bh(&n->lock);
127334d101ddSEric Dumazet 
1274f6b72b62SDavid S. Miller 	/* Only one thread can come in here and initialize the
1275f6b72b62SDavid S. Miller 	 * hh_cache entry.
1276f6b72b62SDavid S. Miller 	 */
1277b23b5455SDavid S. Miller 	if (!hh->hh_len)
1278b23b5455SDavid S. Miller 		dev->header_ops->cache(n, hh, prot);
1279f6b72b62SDavid S. Miller 
12800ed8ddf4SEric Dumazet 	write_unlock_bh(&n->lock);
12811da177e4SLinus Torvalds }
12821da177e4SLinus Torvalds 
12831da177e4SLinus Torvalds /* This function can be used in contexts, where only old dev_queue_xmit
1284767e97e1SEric Dumazet  * worked, f.e. if you want to override normal output path (eql, shaper),
1285767e97e1SEric Dumazet  * but resolution is not made yet.
12861da177e4SLinus Torvalds  */
12871da177e4SLinus Torvalds 
12888f40b161SDavid S. Miller int neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb)
12891da177e4SLinus Torvalds {
12901da177e4SLinus Torvalds 	struct net_device *dev = skb->dev;
12911da177e4SLinus Torvalds 
1292bbe735e4SArnaldo Carvalho de Melo 	__skb_pull(skb, skb_network_offset(skb));
12931da177e4SLinus Torvalds 
12940c4e8581SStephen Hemminger 	if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
12951da177e4SLinus Torvalds 			    skb->len) < 0 &&
12962205369aSDavid S. Miller 	    dev_rebuild_header(skb))
12971da177e4SLinus Torvalds 		return 0;
12981da177e4SLinus Torvalds 
12991da177e4SLinus Torvalds 	return dev_queue_xmit(skb);
13001da177e4SLinus Torvalds }
13010a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_compat_output);
13021da177e4SLinus Torvalds 
13031da177e4SLinus Torvalds /* Slow and careful. */
13041da177e4SLinus Torvalds 
13058f40b161SDavid S. Miller int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
13061da177e4SLinus Torvalds {
1307adf30907SEric Dumazet 	struct dst_entry *dst = skb_dst(skb);
13081da177e4SLinus Torvalds 	int rc = 0;
13091da177e4SLinus Torvalds 
13108f40b161SDavid S. Miller 	if (!dst)
13111da177e4SLinus Torvalds 		goto discard;
13121da177e4SLinus Torvalds 
13131da177e4SLinus Torvalds 	if (!neigh_event_send(neigh, skb)) {
13141da177e4SLinus Torvalds 		int err;
13151da177e4SLinus Torvalds 		struct net_device *dev = neigh->dev;
13160ed8ddf4SEric Dumazet 		unsigned int seq;
131734d101ddSEric Dumazet 
1318f6b72b62SDavid S. Miller 		if (dev->header_ops->cache && !neigh->hh.hh_len)
1319f6b72b62SDavid S. Miller 			neigh_hh_init(neigh, dst);
132034d101ddSEric Dumazet 
13210ed8ddf4SEric Dumazet 		do {
1322e1f16503Sramesh.nagappa@gmail.com 			__skb_pull(skb, skb_network_offset(skb));
13230ed8ddf4SEric Dumazet 			seq = read_seqbegin(&neigh->ha_lock);
13240c4e8581SStephen Hemminger 			err = dev_hard_header(skb, dev, ntohs(skb->protocol),
13251da177e4SLinus Torvalds 					      neigh->ha, NULL, skb->len);
13260ed8ddf4SEric Dumazet 		} while (read_seqretry(&neigh->ha_lock, seq));
132734d101ddSEric Dumazet 
13281da177e4SLinus Torvalds 		if (err >= 0)
1329542d4d68SDavid S. Miller 			rc = dev_queue_xmit(skb);
13301da177e4SLinus Torvalds 		else
13311da177e4SLinus Torvalds 			goto out_kfree_skb;
13321da177e4SLinus Torvalds 	}
13331da177e4SLinus Torvalds out:
13341da177e4SLinus Torvalds 	return rc;
13351da177e4SLinus Torvalds discard:
1336d5d427cdSJoe Perches 	neigh_dbg(1, "%s: dst=%p neigh=%p\n", __func__, dst, neigh);
13371da177e4SLinus Torvalds out_kfree_skb:
13381da177e4SLinus Torvalds 	rc = -EINVAL;
13391da177e4SLinus Torvalds 	kfree_skb(skb);
13401da177e4SLinus Torvalds 	goto out;
13411da177e4SLinus Torvalds }
13420a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_resolve_output);
13431da177e4SLinus Torvalds 
13441da177e4SLinus Torvalds /* As fast as possible without hh cache */
13451da177e4SLinus Torvalds 
13468f40b161SDavid S. Miller int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
13471da177e4SLinus Torvalds {
13481da177e4SLinus Torvalds 	struct net_device *dev = neigh->dev;
13490ed8ddf4SEric Dumazet 	unsigned int seq;
13508f40b161SDavid S. Miller 	int err;
13511da177e4SLinus Torvalds 
13520ed8ddf4SEric Dumazet 	do {
1353e1f16503Sramesh.nagappa@gmail.com 		__skb_pull(skb, skb_network_offset(skb));
13540ed8ddf4SEric Dumazet 		seq = read_seqbegin(&neigh->ha_lock);
13550c4e8581SStephen Hemminger 		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
13561da177e4SLinus Torvalds 				      neigh->ha, NULL, skb->len);
13570ed8ddf4SEric Dumazet 	} while (read_seqretry(&neigh->ha_lock, seq));
13580ed8ddf4SEric Dumazet 
13591da177e4SLinus Torvalds 	if (err >= 0)
1360542d4d68SDavid S. Miller 		err = dev_queue_xmit(skb);
13611da177e4SLinus Torvalds 	else {
13621da177e4SLinus Torvalds 		err = -EINVAL;
13631da177e4SLinus Torvalds 		kfree_skb(skb);
13641da177e4SLinus Torvalds 	}
13651da177e4SLinus Torvalds 	return err;
13661da177e4SLinus Torvalds }
13670a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_connected_output);
13681da177e4SLinus Torvalds 
13698f40b161SDavid S. Miller int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
13708f40b161SDavid S. Miller {
13718f40b161SDavid S. Miller 	return dev_queue_xmit(skb);
13728f40b161SDavid S. Miller }
13738f40b161SDavid S. Miller EXPORT_SYMBOL(neigh_direct_output);
13748f40b161SDavid S. Miller 
13751da177e4SLinus Torvalds static void neigh_proxy_process(unsigned long arg)
13761da177e4SLinus Torvalds {
13771da177e4SLinus Torvalds 	struct neigh_table *tbl = (struct neigh_table *)arg;
13781da177e4SLinus Torvalds 	long sched_next = 0;
13791da177e4SLinus Torvalds 	unsigned long now = jiffies;
1380f72051b0SDavid S. Miller 	struct sk_buff *skb, *n;
13811da177e4SLinus Torvalds 
13821da177e4SLinus Torvalds 	spin_lock(&tbl->proxy_queue.lock);
13831da177e4SLinus Torvalds 
1384f72051b0SDavid S. Miller 	skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1385f72051b0SDavid S. Miller 		long tdif = NEIGH_CB(skb)->sched_next - now;
13861da177e4SLinus Torvalds 
13871da177e4SLinus Torvalds 		if (tdif <= 0) {
1388f72051b0SDavid S. Miller 			struct net_device *dev = skb->dev;
138920e6074eSEric Dumazet 
1390f72051b0SDavid S. Miller 			__skb_unlink(skb, &tbl->proxy_queue);
139120e6074eSEric Dumazet 			if (tbl->proxy_redo && netif_running(dev)) {
139220e6074eSEric Dumazet 				rcu_read_lock();
1393f72051b0SDavid S. Miller 				tbl->proxy_redo(skb);
139420e6074eSEric Dumazet 				rcu_read_unlock();
139520e6074eSEric Dumazet 			} else {
1396f72051b0SDavid S. Miller 				kfree_skb(skb);
139720e6074eSEric Dumazet 			}
13981da177e4SLinus Torvalds 
13991da177e4SLinus Torvalds 			dev_put(dev);
14001da177e4SLinus Torvalds 		} else if (!sched_next || tdif < sched_next)
14011da177e4SLinus Torvalds 			sched_next = tdif;
14021da177e4SLinus Torvalds 	}
14031da177e4SLinus Torvalds 	del_timer(&tbl->proxy_timer);
14041da177e4SLinus Torvalds 	if (sched_next)
14051da177e4SLinus Torvalds 		mod_timer(&tbl->proxy_timer, jiffies + sched_next);
14061da177e4SLinus Torvalds 	spin_unlock(&tbl->proxy_queue.lock);
14071da177e4SLinus Torvalds }
14081da177e4SLinus Torvalds 
14091da177e4SLinus Torvalds void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
14101da177e4SLinus Torvalds 		    struct sk_buff *skb)
14111da177e4SLinus Torvalds {
14121da177e4SLinus Torvalds 	unsigned long now = jiffies;
141363862b5bSAruna-Hewapathirane 
141463862b5bSAruna-Hewapathirane 	unsigned long sched_next = now + (prandom_u32() %
14151f9248e5SJiri Pirko 					  NEIGH_VAR(p, PROXY_DELAY));
14161da177e4SLinus Torvalds 
14171f9248e5SJiri Pirko 	if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) {
14181da177e4SLinus Torvalds 		kfree_skb(skb);
14191da177e4SLinus Torvalds 		return;
14201da177e4SLinus Torvalds 	}
1421a61bbcf2SPatrick McHardy 
1422a61bbcf2SPatrick McHardy 	NEIGH_CB(skb)->sched_next = sched_next;
1423a61bbcf2SPatrick McHardy 	NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
14241da177e4SLinus Torvalds 
14251da177e4SLinus Torvalds 	spin_lock(&tbl->proxy_queue.lock);
14261da177e4SLinus Torvalds 	if (del_timer(&tbl->proxy_timer)) {
14271da177e4SLinus Torvalds 		if (time_before(tbl->proxy_timer.expires, sched_next))
14281da177e4SLinus Torvalds 			sched_next = tbl->proxy_timer.expires;
14291da177e4SLinus Torvalds 	}
1430adf30907SEric Dumazet 	skb_dst_drop(skb);
14311da177e4SLinus Torvalds 	dev_hold(skb->dev);
14321da177e4SLinus Torvalds 	__skb_queue_tail(&tbl->proxy_queue, skb);
14331da177e4SLinus Torvalds 	mod_timer(&tbl->proxy_timer, sched_next);
14341da177e4SLinus Torvalds 	spin_unlock(&tbl->proxy_queue.lock);
14351da177e4SLinus Torvalds }
14360a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(pneigh_enqueue);
14371da177e4SLinus Torvalds 
143897fd5bc7STobias Klauser static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
1439426b5303SEric W. Biederman 						      struct net *net, int ifindex)
1440426b5303SEric W. Biederman {
1441426b5303SEric W. Biederman 	struct neigh_parms *p;
1442426b5303SEric W. Biederman 
144375fbfd33SNicolas Dichtel 	list_for_each_entry(p, &tbl->parms_list, list) {
1444878628fbSYOSHIFUJI Hideaki 		if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
1445170d6f99SGao feng 		    (!p->dev && !ifindex && net_eq(net, &init_net)))
1446426b5303SEric W. Biederman 			return p;
1447426b5303SEric W. Biederman 	}
1448426b5303SEric W. Biederman 
1449426b5303SEric W. Biederman 	return NULL;
1450426b5303SEric W. Biederman }
14511da177e4SLinus Torvalds 
14521da177e4SLinus Torvalds struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
14531da177e4SLinus Torvalds 				      struct neigh_table *tbl)
14541da177e4SLinus Torvalds {
1455cf89d6b2SGao feng 	struct neigh_parms *p;
145600829823SStephen Hemminger 	struct net *net = dev_net(dev);
145700829823SStephen Hemminger 	const struct net_device_ops *ops = dev->netdev_ops;
14581da177e4SLinus Torvalds 
1459cf89d6b2SGao feng 	p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL);
14601da177e4SLinus Torvalds 	if (p) {
14611da177e4SLinus Torvalds 		p->tbl		  = tbl;
14621da177e4SLinus Torvalds 		atomic_set(&p->refcnt, 1);
14631da177e4SLinus Torvalds 		p->reachable_time =
14641f9248e5SJiri Pirko 				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
1465c7fb64dbSThomas Graf 		dev_hold(dev);
1466c7fb64dbSThomas Graf 		p->dev = dev;
1467e42ea986SEric Dumazet 		write_pnet(&p->net, hold_net(net));
14681da177e4SLinus Torvalds 		p->sysctl_table = NULL;
146963134803SVeaceslav Falico 
147063134803SVeaceslav Falico 		if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
147163134803SVeaceslav Falico 			release_net(net);
147263134803SVeaceslav Falico 			dev_put(dev);
147363134803SVeaceslav Falico 			kfree(p);
147463134803SVeaceslav Falico 			return NULL;
147563134803SVeaceslav Falico 		}
147663134803SVeaceslav Falico 
14771da177e4SLinus Torvalds 		write_lock_bh(&tbl->lock);
147875fbfd33SNicolas Dichtel 		list_add(&p->list, &tbl->parms.list);
14791da177e4SLinus Torvalds 		write_unlock_bh(&tbl->lock);
14801d4c8c29SJiri Pirko 
14811d4c8c29SJiri Pirko 		neigh_parms_data_state_cleanall(p);
14821da177e4SLinus Torvalds 	}
14831da177e4SLinus Torvalds 	return p;
14841da177e4SLinus Torvalds }
14850a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_parms_alloc);
14861da177e4SLinus Torvalds 
14871da177e4SLinus Torvalds static void neigh_rcu_free_parms(struct rcu_head *head)
14881da177e4SLinus Torvalds {
14891da177e4SLinus Torvalds 	struct neigh_parms *parms =
14901da177e4SLinus Torvalds 		container_of(head, struct neigh_parms, rcu_head);
14911da177e4SLinus Torvalds 
14921da177e4SLinus Torvalds 	neigh_parms_put(parms);
14931da177e4SLinus Torvalds }
14941da177e4SLinus Torvalds 
14951da177e4SLinus Torvalds void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
14961da177e4SLinus Torvalds {
14971da177e4SLinus Torvalds 	if (!parms || parms == &tbl->parms)
14981da177e4SLinus Torvalds 		return;
14991da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
150075fbfd33SNicolas Dichtel 	list_del(&parms->list);
15011da177e4SLinus Torvalds 	parms->dead = 1;
15021da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
1503cecbb639SDavid S. Miller 	if (parms->dev)
1504cecbb639SDavid S. Miller 		dev_put(parms->dev);
15051da177e4SLinus Torvalds 	call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
15061da177e4SLinus Torvalds }
15070a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_parms_release);
15081da177e4SLinus Torvalds 
150906f0511dSDenis V. Lunev static void neigh_parms_destroy(struct neigh_parms *parms)
15101da177e4SLinus Torvalds {
151157da52c1SYOSHIFUJI Hideaki 	release_net(neigh_parms_net(parms));
15121da177e4SLinus Torvalds 	kfree(parms);
15131da177e4SLinus Torvalds }
15141da177e4SLinus Torvalds 
1515c2ecba71SPavel Emelianov static struct lock_class_key neigh_table_proxy_queue_class;
1516c2ecba71SPavel Emelianov 
1517d7480fd3SWANG Cong static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly;
1518d7480fd3SWANG Cong 
1519d7480fd3SWANG Cong void neigh_table_init(int index, struct neigh_table *tbl)
15201da177e4SLinus Torvalds {
15211da177e4SLinus Torvalds 	unsigned long now = jiffies;
15221da177e4SLinus Torvalds 	unsigned long phsize;
15231da177e4SLinus Torvalds 
152475fbfd33SNicolas Dichtel 	INIT_LIST_HEAD(&tbl->parms_list);
152575fbfd33SNicolas Dichtel 	list_add(&tbl->parms.list, &tbl->parms_list);
1526e42ea986SEric Dumazet 	write_pnet(&tbl->parms.net, &init_net);
15271da177e4SLinus Torvalds 	atomic_set(&tbl->parms.refcnt, 1);
15281da177e4SLinus Torvalds 	tbl->parms.reachable_time =
15291f9248e5SJiri Pirko 			  neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME));
15301da177e4SLinus Torvalds 
15311da177e4SLinus Torvalds 	tbl->stats = alloc_percpu(struct neigh_statistics);
15321da177e4SLinus Torvalds 	if (!tbl->stats)
15331da177e4SLinus Torvalds 		panic("cannot create neighbour cache statistics");
15341da177e4SLinus Torvalds 
15351da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
15369b739ba5SAlexey Dobriyan 	if (!proc_create_data(tbl->id, 0, init_net.proc_net_stat,
15379b739ba5SAlexey Dobriyan 			      &neigh_stat_seq_fops, tbl))
15381da177e4SLinus Torvalds 		panic("cannot create neighbour proc dir entry");
15391da177e4SLinus Torvalds #endif
15401da177e4SLinus Torvalds 
1541cd089336SDavid S. Miller 	RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
15421da177e4SLinus Torvalds 
15431da177e4SLinus Torvalds 	phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
154477d04bd9SAndrew Morton 	tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
15451da177e4SLinus Torvalds 
1546d6bf7817SEric Dumazet 	if (!tbl->nht || !tbl->phash_buckets)
15471da177e4SLinus Torvalds 		panic("cannot allocate neighbour cache hashes");
15481da177e4SLinus Torvalds 
154908433effSYOSHIFUJI Hideaki / 吉藤英明 	if (!tbl->entry_size)
155008433effSYOSHIFUJI Hideaki / 吉藤英明 		tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
155108433effSYOSHIFUJI Hideaki / 吉藤英明 					tbl->key_len, NEIGH_PRIV_ALIGN);
155208433effSYOSHIFUJI Hideaki / 吉藤英明 	else
155308433effSYOSHIFUJI Hideaki / 吉藤英明 		WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
155408433effSYOSHIFUJI Hideaki / 吉藤英明 
15551da177e4SLinus Torvalds 	rwlock_init(&tbl->lock);
1556203b42f7STejun Heo 	INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
1557f618002bSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
1558f618002bSviresh kumar 			tbl->parms.reachable_time);
1559b24b8a24SPavel Emelyanov 	setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl);
1560c2ecba71SPavel Emelianov 	skb_queue_head_init_class(&tbl->proxy_queue,
1561c2ecba71SPavel Emelianov 			&neigh_table_proxy_queue_class);
15621da177e4SLinus Torvalds 
15631da177e4SLinus Torvalds 	tbl->last_flush = now;
15641da177e4SLinus Torvalds 	tbl->last_rand	= now + tbl->parms.reachable_time * 20;
1565bd89efc5SSimon Kelley 
1566d7480fd3SWANG Cong 	neigh_tables[index] = tbl;
15671da177e4SLinus Torvalds }
15680a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_table_init);
15691da177e4SLinus Torvalds 
1570d7480fd3SWANG Cong int neigh_table_clear(int index, struct neigh_table *tbl)
15711da177e4SLinus Torvalds {
1572d7480fd3SWANG Cong 	neigh_tables[index] = NULL;
15731da177e4SLinus Torvalds 	/* It is not clean... Fix it to unload IPv6 module safely */
1574a5c30b34STejun Heo 	cancel_delayed_work_sync(&tbl->gc_work);
15751da177e4SLinus Torvalds 	del_timer_sync(&tbl->proxy_timer);
15761da177e4SLinus Torvalds 	pneigh_queue_purge(&tbl->proxy_queue);
15771da177e4SLinus Torvalds 	neigh_ifdown(tbl, NULL);
15781da177e4SLinus Torvalds 	if (atomic_read(&tbl->entries))
1579e005d193SJoe Perches 		pr_crit("neighbour leakage\n");
15801da177e4SLinus Torvalds 
15816193d2beSEric Dumazet 	call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
15826193d2beSEric Dumazet 		 neigh_hash_free_rcu);
1583d6bf7817SEric Dumazet 	tbl->nht = NULL;
15841da177e4SLinus Torvalds 
15851da177e4SLinus Torvalds 	kfree(tbl->phash_buckets);
15861da177e4SLinus Torvalds 	tbl->phash_buckets = NULL;
15871da177e4SLinus Torvalds 
15883f192b5cSAlexey Dobriyan 	remove_proc_entry(tbl->id, init_net.proc_net_stat);
15893f192b5cSAlexey Dobriyan 
15903fcde74bSKirill Korotaev 	free_percpu(tbl->stats);
15913fcde74bSKirill Korotaev 	tbl->stats = NULL;
15923fcde74bSKirill Korotaev 
15931da177e4SLinus Torvalds 	return 0;
15941da177e4SLinus Torvalds }
15950a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_table_clear);
15961da177e4SLinus Torvalds 
1597d7480fd3SWANG Cong static struct neigh_table *neigh_find_table(int family)
1598d7480fd3SWANG Cong {
1599d7480fd3SWANG Cong 	struct neigh_table *tbl = NULL;
1600d7480fd3SWANG Cong 
1601d7480fd3SWANG Cong 	switch (family) {
1602d7480fd3SWANG Cong 	case AF_INET:
1603d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_ARP_TABLE];
1604d7480fd3SWANG Cong 		break;
1605d7480fd3SWANG Cong 	case AF_INET6:
1606d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_ND_TABLE];
1607d7480fd3SWANG Cong 		break;
1608d7480fd3SWANG Cong 	case AF_DECnet:
1609d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_DN_TABLE];
1610d7480fd3SWANG Cong 		break;
1611d7480fd3SWANG Cong 	}
1612d7480fd3SWANG Cong 
1613d7480fd3SWANG Cong 	return tbl;
1614d7480fd3SWANG Cong }
1615d7480fd3SWANG Cong 
1616661d2967SThomas Graf static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh)
16171da177e4SLinus Torvalds {
16183b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
1619a14a49d2SThomas Graf 	struct ndmsg *ndm;
1620a14a49d2SThomas Graf 	struct nlattr *dst_attr;
16211da177e4SLinus Torvalds 	struct neigh_table *tbl;
1622d7480fd3SWANG Cong 	struct neighbour *neigh;
16231da177e4SLinus Torvalds 	struct net_device *dev = NULL;
1624a14a49d2SThomas Graf 	int err = -EINVAL;
16251da177e4SLinus Torvalds 
1626110b2499SEric Dumazet 	ASSERT_RTNL();
1627a14a49d2SThomas Graf 	if (nlmsg_len(nlh) < sizeof(*ndm))
16281da177e4SLinus Torvalds 		goto out;
16291da177e4SLinus Torvalds 
1630a14a49d2SThomas Graf 	dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
1631a14a49d2SThomas Graf 	if (dst_attr == NULL)
1632a14a49d2SThomas Graf 		goto out;
1633a14a49d2SThomas Graf 
1634a14a49d2SThomas Graf 	ndm = nlmsg_data(nlh);
1635a14a49d2SThomas Graf 	if (ndm->ndm_ifindex) {
1636110b2499SEric Dumazet 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
1637a14a49d2SThomas Graf 		if (dev == NULL) {
1638a14a49d2SThomas Graf 			err = -ENODEV;
1639a14a49d2SThomas Graf 			goto out;
1640a14a49d2SThomas Graf 		}
1641a14a49d2SThomas Graf 	}
1642a14a49d2SThomas Graf 
1643d7480fd3SWANG Cong 	tbl = neigh_find_table(ndm->ndm_family);
1644d7480fd3SWANG Cong 	if (tbl == NULL)
1645d7480fd3SWANG Cong 		return -EAFNOSUPPORT;
16461da177e4SLinus Torvalds 
1647a14a49d2SThomas Graf 	if (nla_len(dst_attr) < tbl->key_len)
1648110b2499SEric Dumazet 		goto out;
16491da177e4SLinus Torvalds 
16501da177e4SLinus Torvalds 	if (ndm->ndm_flags & NTF_PROXY) {
1651426b5303SEric W. Biederman 		err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
1652110b2499SEric Dumazet 		goto out;
16531da177e4SLinus Torvalds 	}
16541da177e4SLinus Torvalds 
1655a14a49d2SThomas Graf 	if (dev == NULL)
1656110b2499SEric Dumazet 		goto out;
16571da177e4SLinus Torvalds 
1658a14a49d2SThomas Graf 	neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1659a14a49d2SThomas Graf 	if (neigh == NULL) {
1660a14a49d2SThomas Graf 		err = -ENOENT;
1661110b2499SEric Dumazet 		goto out;
1662a14a49d2SThomas Graf 	}
1663a14a49d2SThomas Graf 
1664a14a49d2SThomas Graf 	err = neigh_update(neigh, NULL, NUD_FAILED,
16651da177e4SLinus Torvalds 			   NEIGH_UPDATE_F_OVERRIDE |
16661da177e4SLinus Torvalds 			   NEIGH_UPDATE_F_ADMIN);
1667a14a49d2SThomas Graf 	neigh_release(neigh);
1668a14a49d2SThomas Graf 
16691da177e4SLinus Torvalds out:
16701da177e4SLinus Torvalds 	return err;
16711da177e4SLinus Torvalds }
16721da177e4SLinus Torvalds 
1673661d2967SThomas Graf static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh)
16741da177e4SLinus Torvalds {
1675d7480fd3SWANG Cong 	int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
16763b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
16775208debdSThomas Graf 	struct ndmsg *ndm;
16785208debdSThomas Graf 	struct nlattr *tb[NDA_MAX+1];
16791da177e4SLinus Torvalds 	struct neigh_table *tbl;
16801da177e4SLinus Torvalds 	struct net_device *dev = NULL;
1681d7480fd3SWANG Cong 	struct neighbour *neigh;
1682d7480fd3SWANG Cong 	void *dst, *lladdr;
16835208debdSThomas Graf 	int err;
16841da177e4SLinus Torvalds 
1685110b2499SEric Dumazet 	ASSERT_RTNL();
16865208debdSThomas Graf 	err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
16875208debdSThomas Graf 	if (err < 0)
16881da177e4SLinus Torvalds 		goto out;
16891da177e4SLinus Torvalds 
16905208debdSThomas Graf 	err = -EINVAL;
16915208debdSThomas Graf 	if (tb[NDA_DST] == NULL)
16925208debdSThomas Graf 		goto out;
16935208debdSThomas Graf 
16945208debdSThomas Graf 	ndm = nlmsg_data(nlh);
16955208debdSThomas Graf 	if (ndm->ndm_ifindex) {
1696110b2499SEric Dumazet 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
16975208debdSThomas Graf 		if (dev == NULL) {
16985208debdSThomas Graf 			err = -ENODEV;
16995208debdSThomas Graf 			goto out;
17005208debdSThomas Graf 		}
17015208debdSThomas Graf 
17025208debdSThomas Graf 		if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len)
1703110b2499SEric Dumazet 			goto out;
17045208debdSThomas Graf 	}
17055208debdSThomas Graf 
1706d7480fd3SWANG Cong 	tbl = neigh_find_table(ndm->ndm_family);
1707d7480fd3SWANG Cong 	if (tbl == NULL)
1708d7480fd3SWANG Cong 		return -EAFNOSUPPORT;
17091da177e4SLinus Torvalds 
17105208debdSThomas Graf 	if (nla_len(tb[NDA_DST]) < tbl->key_len)
1711110b2499SEric Dumazet 		goto out;
17125208debdSThomas Graf 	dst = nla_data(tb[NDA_DST]);
17135208debdSThomas Graf 	lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
17141da177e4SLinus Torvalds 
17151da177e4SLinus Torvalds 	if (ndm->ndm_flags & NTF_PROXY) {
171662dd9318SVille Nuorvala 		struct pneigh_entry *pn;
171762dd9318SVille Nuorvala 
17185208debdSThomas Graf 		err = -ENOBUFS;
1719426b5303SEric W. Biederman 		pn = pneigh_lookup(tbl, net, dst, dev, 1);
172062dd9318SVille Nuorvala 		if (pn) {
172162dd9318SVille Nuorvala 			pn->flags = ndm->ndm_flags;
172262dd9318SVille Nuorvala 			err = 0;
172362dd9318SVille Nuorvala 		}
1724110b2499SEric Dumazet 		goto out;
17251da177e4SLinus Torvalds 	}
17261da177e4SLinus Torvalds 
17275208debdSThomas Graf 	if (dev == NULL)
1728110b2499SEric Dumazet 		goto out;
17291da177e4SLinus Torvalds 
17305208debdSThomas Graf 	neigh = neigh_lookup(tbl, dst, dev);
17315208debdSThomas Graf 	if (neigh == NULL) {
17325208debdSThomas Graf 		if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
17331da177e4SLinus Torvalds 			err = -ENOENT;
1734110b2499SEric Dumazet 			goto out;
17355208debdSThomas Graf 		}
17365208debdSThomas Graf 
17375208debdSThomas Graf 		neigh = __neigh_lookup_errno(tbl, dst, dev);
17385208debdSThomas Graf 		if (IS_ERR(neigh)) {
17395208debdSThomas Graf 			err = PTR_ERR(neigh);
1740110b2499SEric Dumazet 			goto out;
17411da177e4SLinus Torvalds 		}
17425208debdSThomas Graf 	} else {
17435208debdSThomas Graf 		if (nlh->nlmsg_flags & NLM_F_EXCL) {
17445208debdSThomas Graf 			err = -EEXIST;
17455208debdSThomas Graf 			neigh_release(neigh);
1746110b2499SEric Dumazet 			goto out;
17471da177e4SLinus Torvalds 		}
17481da177e4SLinus Torvalds 
17495208debdSThomas Graf 		if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
17505208debdSThomas Graf 			flags &= ~NEIGH_UPDATE_F_OVERRIDE;
17515208debdSThomas Graf 	}
17521da177e4SLinus Torvalds 
17530c5c2d30SEric Biederman 	if (ndm->ndm_flags & NTF_USE) {
17540c5c2d30SEric Biederman 		neigh_event_send(neigh, NULL);
17550c5c2d30SEric Biederman 		err = 0;
17560c5c2d30SEric Biederman 	} else
17575208debdSThomas Graf 		err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
17585208debdSThomas Graf 	neigh_release(neigh);
17591da177e4SLinus Torvalds 
17601da177e4SLinus Torvalds out:
17611da177e4SLinus Torvalds 	return err;
17621da177e4SLinus Torvalds }
17631da177e4SLinus Torvalds 
1764c7fb64dbSThomas Graf static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
1765c7fb64dbSThomas Graf {
1766ca860fb3SThomas Graf 	struct nlattr *nest;
1767e386c6ebSThomas Graf 
1768ca860fb3SThomas Graf 	nest = nla_nest_start(skb, NDTA_PARMS);
1769ca860fb3SThomas Graf 	if (nest == NULL)
1770ca860fb3SThomas Graf 		return -ENOBUFS;
1771c7fb64dbSThomas Graf 
17729a6308d7SDavid S. Miller 	if ((parms->dev &&
17739a6308d7SDavid S. Miller 	     nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
17749a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)) ||
17751f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_QUEUE_LENBYTES,
17761f9248e5SJiri Pirko 			NEIGH_VAR(parms, QUEUE_LEN_BYTES)) ||
17778b5c171bSEric Dumazet 	    /* approximative value for deprecated QUEUE_LEN (in packets) */
17789a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTPA_QUEUE_LEN,
17791f9248e5SJiri Pirko 			NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) ||
17801f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) ||
17811f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) ||
17821f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_UCAST_PROBES,
17831f9248e5SJiri Pirko 			NEIGH_VAR(parms, UCAST_PROBES)) ||
17841f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_MCAST_PROBES,
17851f9248e5SJiri Pirko 			NEIGH_VAR(parms, MCAST_PROBES)) ||
17869a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time) ||
17879a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
17881f9248e5SJiri Pirko 			  NEIGH_VAR(parms, BASE_REACHABLE_TIME)) ||
17891f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_GC_STALETIME,
17901f9248e5SJiri Pirko 			  NEIGH_VAR(parms, GC_STALETIME)) ||
17919a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
17921f9248e5SJiri Pirko 			  NEIGH_VAR(parms, DELAY_PROBE_TIME)) ||
17931f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_RETRANS_TIME,
17941f9248e5SJiri Pirko 			  NEIGH_VAR(parms, RETRANS_TIME)) ||
17951f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_ANYCAST_DELAY,
17961f9248e5SJiri Pirko 			  NEIGH_VAR(parms, ANYCAST_DELAY)) ||
17971f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_PROXY_DELAY,
17981f9248e5SJiri Pirko 			  NEIGH_VAR(parms, PROXY_DELAY)) ||
17991f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_LOCKTIME,
18001f9248e5SJiri Pirko 			  NEIGH_VAR(parms, LOCKTIME)))
18019a6308d7SDavid S. Miller 		goto nla_put_failure;
1802ca860fb3SThomas Graf 	return nla_nest_end(skb, nest);
1803c7fb64dbSThomas Graf 
1804ca860fb3SThomas Graf nla_put_failure:
1805bc3ed28cSThomas Graf 	nla_nest_cancel(skb, nest);
1806bc3ed28cSThomas Graf 	return -EMSGSIZE;
1807c7fb64dbSThomas Graf }
1808c7fb64dbSThomas Graf 
1809ca860fb3SThomas Graf static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
1810ca860fb3SThomas Graf 			      u32 pid, u32 seq, int type, int flags)
1811c7fb64dbSThomas Graf {
1812c7fb64dbSThomas Graf 	struct nlmsghdr *nlh;
1813c7fb64dbSThomas Graf 	struct ndtmsg *ndtmsg;
1814c7fb64dbSThomas Graf 
1815ca860fb3SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1816ca860fb3SThomas Graf 	if (nlh == NULL)
181726932566SPatrick McHardy 		return -EMSGSIZE;
1818c7fb64dbSThomas Graf 
1819ca860fb3SThomas Graf 	ndtmsg = nlmsg_data(nlh);
1820c7fb64dbSThomas Graf 
1821c7fb64dbSThomas Graf 	read_lock_bh(&tbl->lock);
1822c7fb64dbSThomas Graf 	ndtmsg->ndtm_family = tbl->family;
18239ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad1   = 0;
18249ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad2   = 0;
1825c7fb64dbSThomas Graf 
18269a6308d7SDavid S. Miller 	if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
18279a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval) ||
18289a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
18299a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
18309a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
18319a6308d7SDavid S. Miller 		goto nla_put_failure;
1832c7fb64dbSThomas Graf 	{
1833c7fb64dbSThomas Graf 		unsigned long now = jiffies;
1834c7fb64dbSThomas Graf 		unsigned int flush_delta = now - tbl->last_flush;
1835c7fb64dbSThomas Graf 		unsigned int rand_delta = now - tbl->last_rand;
1836d6bf7817SEric Dumazet 		struct neigh_hash_table *nht;
1837c7fb64dbSThomas Graf 		struct ndt_config ndc = {
1838c7fb64dbSThomas Graf 			.ndtc_key_len		= tbl->key_len,
1839c7fb64dbSThomas Graf 			.ndtc_entry_size	= tbl->entry_size,
1840c7fb64dbSThomas Graf 			.ndtc_entries		= atomic_read(&tbl->entries),
1841c7fb64dbSThomas Graf 			.ndtc_last_flush	= jiffies_to_msecs(flush_delta),
1842c7fb64dbSThomas Graf 			.ndtc_last_rand		= jiffies_to_msecs(rand_delta),
1843c7fb64dbSThomas Graf 			.ndtc_proxy_qlen	= tbl->proxy_queue.qlen,
1844c7fb64dbSThomas Graf 		};
1845c7fb64dbSThomas Graf 
1846d6bf7817SEric Dumazet 		rcu_read_lock_bh();
1847d6bf7817SEric Dumazet 		nht = rcu_dereference_bh(tbl->nht);
18482c2aba6cSDavid S. Miller 		ndc.ndtc_hash_rnd = nht->hash_rnd[0];
1849cd089336SDavid S. Miller 		ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
1850d6bf7817SEric Dumazet 		rcu_read_unlock_bh();
1851d6bf7817SEric Dumazet 
18529a6308d7SDavid S. Miller 		if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
18539a6308d7SDavid S. Miller 			goto nla_put_failure;
1854c7fb64dbSThomas Graf 	}
1855c7fb64dbSThomas Graf 
1856c7fb64dbSThomas Graf 	{
1857c7fb64dbSThomas Graf 		int cpu;
1858c7fb64dbSThomas Graf 		struct ndt_stats ndst;
1859c7fb64dbSThomas Graf 
1860c7fb64dbSThomas Graf 		memset(&ndst, 0, sizeof(ndst));
1861c7fb64dbSThomas Graf 
18626f912042SKAMEZAWA Hiroyuki 		for_each_possible_cpu(cpu) {
1863c7fb64dbSThomas Graf 			struct neigh_statistics	*st;
1864c7fb64dbSThomas Graf 
1865c7fb64dbSThomas Graf 			st = per_cpu_ptr(tbl->stats, cpu);
1866c7fb64dbSThomas Graf 			ndst.ndts_allocs		+= st->allocs;
1867c7fb64dbSThomas Graf 			ndst.ndts_destroys		+= st->destroys;
1868c7fb64dbSThomas Graf 			ndst.ndts_hash_grows		+= st->hash_grows;
1869c7fb64dbSThomas Graf 			ndst.ndts_res_failed		+= st->res_failed;
1870c7fb64dbSThomas Graf 			ndst.ndts_lookups		+= st->lookups;
1871c7fb64dbSThomas Graf 			ndst.ndts_hits			+= st->hits;
1872c7fb64dbSThomas Graf 			ndst.ndts_rcv_probes_mcast	+= st->rcv_probes_mcast;
1873c7fb64dbSThomas Graf 			ndst.ndts_rcv_probes_ucast	+= st->rcv_probes_ucast;
1874c7fb64dbSThomas Graf 			ndst.ndts_periodic_gc_runs	+= st->periodic_gc_runs;
1875c7fb64dbSThomas Graf 			ndst.ndts_forced_gc_runs	+= st->forced_gc_runs;
1876c7fb64dbSThomas Graf 		}
1877c7fb64dbSThomas Graf 
18789a6308d7SDavid S. Miller 		if (nla_put(skb, NDTA_STATS, sizeof(ndst), &ndst))
18799a6308d7SDavid S. Miller 			goto nla_put_failure;
1880c7fb64dbSThomas Graf 	}
1881c7fb64dbSThomas Graf 
1882c7fb64dbSThomas Graf 	BUG_ON(tbl->parms.dev);
1883c7fb64dbSThomas Graf 	if (neightbl_fill_parms(skb, &tbl->parms) < 0)
1884ca860fb3SThomas Graf 		goto nla_put_failure;
1885c7fb64dbSThomas Graf 
1886c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
1887053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
1888053c095aSJohannes Berg 	return 0;
1889c7fb64dbSThomas Graf 
1890ca860fb3SThomas Graf nla_put_failure:
1891c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
189226932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
189326932566SPatrick McHardy 	return -EMSGSIZE;
1894c7fb64dbSThomas Graf }
1895c7fb64dbSThomas Graf 
1896ca860fb3SThomas Graf static int neightbl_fill_param_info(struct sk_buff *skb,
1897ca860fb3SThomas Graf 				    struct neigh_table *tbl,
1898c7fb64dbSThomas Graf 				    struct neigh_parms *parms,
1899ca860fb3SThomas Graf 				    u32 pid, u32 seq, int type,
1900ca860fb3SThomas Graf 				    unsigned int flags)
1901c7fb64dbSThomas Graf {
1902c7fb64dbSThomas Graf 	struct ndtmsg *ndtmsg;
1903c7fb64dbSThomas Graf 	struct nlmsghdr *nlh;
1904c7fb64dbSThomas Graf 
1905ca860fb3SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1906ca860fb3SThomas Graf 	if (nlh == NULL)
190726932566SPatrick McHardy 		return -EMSGSIZE;
1908c7fb64dbSThomas Graf 
1909ca860fb3SThomas Graf 	ndtmsg = nlmsg_data(nlh);
1910c7fb64dbSThomas Graf 
1911c7fb64dbSThomas Graf 	read_lock_bh(&tbl->lock);
1912c7fb64dbSThomas Graf 	ndtmsg->ndtm_family = tbl->family;
19139ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad1   = 0;
19149ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad2   = 0;
1915c7fb64dbSThomas Graf 
1916ca860fb3SThomas Graf 	if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
1917ca860fb3SThomas Graf 	    neightbl_fill_parms(skb, parms) < 0)
1918ca860fb3SThomas Graf 		goto errout;
1919c7fb64dbSThomas Graf 
1920c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
1921053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
1922053c095aSJohannes Berg 	return 0;
1923ca860fb3SThomas Graf errout:
1924c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
192526932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
192626932566SPatrick McHardy 	return -EMSGSIZE;
1927c7fb64dbSThomas Graf }
1928c7fb64dbSThomas Graf 
1929ef7c79edSPatrick McHardy static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
19306b3f8674SThomas Graf 	[NDTA_NAME]		= { .type = NLA_STRING },
19316b3f8674SThomas Graf 	[NDTA_THRESH1]		= { .type = NLA_U32 },
19326b3f8674SThomas Graf 	[NDTA_THRESH2]		= { .type = NLA_U32 },
19336b3f8674SThomas Graf 	[NDTA_THRESH3]		= { .type = NLA_U32 },
19346b3f8674SThomas Graf 	[NDTA_GC_INTERVAL]	= { .type = NLA_U64 },
19356b3f8674SThomas Graf 	[NDTA_PARMS]		= { .type = NLA_NESTED },
19366b3f8674SThomas Graf };
19376b3f8674SThomas Graf 
1938ef7c79edSPatrick McHardy static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
19396b3f8674SThomas Graf 	[NDTPA_IFINDEX]			= { .type = NLA_U32 },
19406b3f8674SThomas Graf 	[NDTPA_QUEUE_LEN]		= { .type = NLA_U32 },
19416b3f8674SThomas Graf 	[NDTPA_PROXY_QLEN]		= { .type = NLA_U32 },
19426b3f8674SThomas Graf 	[NDTPA_APP_PROBES]		= { .type = NLA_U32 },
19436b3f8674SThomas Graf 	[NDTPA_UCAST_PROBES]		= { .type = NLA_U32 },
19446b3f8674SThomas Graf 	[NDTPA_MCAST_PROBES]		= { .type = NLA_U32 },
19456b3f8674SThomas Graf 	[NDTPA_BASE_REACHABLE_TIME]	= { .type = NLA_U64 },
19466b3f8674SThomas Graf 	[NDTPA_GC_STALETIME]		= { .type = NLA_U64 },
19476b3f8674SThomas Graf 	[NDTPA_DELAY_PROBE_TIME]	= { .type = NLA_U64 },
19486b3f8674SThomas Graf 	[NDTPA_RETRANS_TIME]		= { .type = NLA_U64 },
19496b3f8674SThomas Graf 	[NDTPA_ANYCAST_DELAY]		= { .type = NLA_U64 },
19506b3f8674SThomas Graf 	[NDTPA_PROXY_DELAY]		= { .type = NLA_U64 },
19516b3f8674SThomas Graf 	[NDTPA_LOCKTIME]		= { .type = NLA_U64 },
19526b3f8674SThomas Graf };
19536b3f8674SThomas Graf 
1954661d2967SThomas Graf static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh)
1955c7fb64dbSThomas Graf {
19563b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
1957c7fb64dbSThomas Graf 	struct neigh_table *tbl;
19586b3f8674SThomas Graf 	struct ndtmsg *ndtmsg;
19596b3f8674SThomas Graf 	struct nlattr *tb[NDTA_MAX+1];
1960d7480fd3SWANG Cong 	bool found = false;
1961d7480fd3SWANG Cong 	int err, tidx;
1962c7fb64dbSThomas Graf 
19636b3f8674SThomas Graf 	err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
19646b3f8674SThomas Graf 			  nl_neightbl_policy);
19656b3f8674SThomas Graf 	if (err < 0)
19666b3f8674SThomas Graf 		goto errout;
1967c7fb64dbSThomas Graf 
19686b3f8674SThomas Graf 	if (tb[NDTA_NAME] == NULL) {
19696b3f8674SThomas Graf 		err = -EINVAL;
19706b3f8674SThomas Graf 		goto errout;
19716b3f8674SThomas Graf 	}
19726b3f8674SThomas Graf 
19736b3f8674SThomas Graf 	ndtmsg = nlmsg_data(nlh);
1974d7480fd3SWANG Cong 
1975d7480fd3SWANG Cong 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
1976d7480fd3SWANG Cong 		tbl = neigh_tables[tidx];
1977d7480fd3SWANG Cong 		if (!tbl)
1978d7480fd3SWANG Cong 			continue;
1979c7fb64dbSThomas Graf 		if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
1980c7fb64dbSThomas Graf 			continue;
1981d7480fd3SWANG Cong 		if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) {
1982d7480fd3SWANG Cong 			found = true;
1983c7fb64dbSThomas Graf 			break;
1984c7fb64dbSThomas Graf 		}
1985c7fb64dbSThomas Graf 	}
1986c7fb64dbSThomas Graf 
1987d7480fd3SWANG Cong 	if (!found)
1988d7480fd3SWANG Cong 		return -ENOENT;
1989d7480fd3SWANG Cong 
1990c7fb64dbSThomas Graf 	/*
1991c7fb64dbSThomas Graf 	 * We acquire tbl->lock to be nice to the periodic timers and
1992c7fb64dbSThomas Graf 	 * make sure they always see a consistent set of values.
1993c7fb64dbSThomas Graf 	 */
1994c7fb64dbSThomas Graf 	write_lock_bh(&tbl->lock);
1995c7fb64dbSThomas Graf 
19966b3f8674SThomas Graf 	if (tb[NDTA_PARMS]) {
19976b3f8674SThomas Graf 		struct nlattr *tbp[NDTPA_MAX+1];
1998c7fb64dbSThomas Graf 		struct neigh_parms *p;
19996b3f8674SThomas Graf 		int i, ifindex = 0;
2000c7fb64dbSThomas Graf 
20016b3f8674SThomas Graf 		err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS],
20026b3f8674SThomas Graf 				       nl_ntbl_parm_policy);
20036b3f8674SThomas Graf 		if (err < 0)
20046b3f8674SThomas Graf 			goto errout_tbl_lock;
2005c7fb64dbSThomas Graf 
20066b3f8674SThomas Graf 		if (tbp[NDTPA_IFINDEX])
20076b3f8674SThomas Graf 			ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
2008c7fb64dbSThomas Graf 
200997fd5bc7STobias Klauser 		p = lookup_neigh_parms(tbl, net, ifindex);
2010c7fb64dbSThomas Graf 		if (p == NULL) {
2011c7fb64dbSThomas Graf 			err = -ENOENT;
20126b3f8674SThomas Graf 			goto errout_tbl_lock;
2013c7fb64dbSThomas Graf 		}
2014c7fb64dbSThomas Graf 
20156b3f8674SThomas Graf 		for (i = 1; i <= NDTPA_MAX; i++) {
20166b3f8674SThomas Graf 			if (tbp[i] == NULL)
20176b3f8674SThomas Graf 				continue;
2018c7fb64dbSThomas Graf 
20196b3f8674SThomas Graf 			switch (i) {
20206b3f8674SThomas Graf 			case NDTPA_QUEUE_LEN:
20211f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
20221f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]) *
20231f9248e5SJiri Pirko 					      SKB_TRUESIZE(ETH_FRAME_LEN));
20248b5c171bSEric Dumazet 				break;
20258b5c171bSEric Dumazet 			case NDTPA_QUEUE_LENBYTES:
20261f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
20271f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
20286b3f8674SThomas Graf 				break;
20296b3f8674SThomas Graf 			case NDTPA_PROXY_QLEN:
20301f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, PROXY_QLEN,
20311f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
20326b3f8674SThomas Graf 				break;
20336b3f8674SThomas Graf 			case NDTPA_APP_PROBES:
20341f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, APP_PROBES,
20351f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
20366b3f8674SThomas Graf 				break;
20376b3f8674SThomas Graf 			case NDTPA_UCAST_PROBES:
20381f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, UCAST_PROBES,
20391f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
20406b3f8674SThomas Graf 				break;
20416b3f8674SThomas Graf 			case NDTPA_MCAST_PROBES:
20421f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, MCAST_PROBES,
20431f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
20446b3f8674SThomas Graf 				break;
20456b3f8674SThomas Graf 			case NDTPA_BASE_REACHABLE_TIME:
20461f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,
20471f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
20484bf6980dSJean-Francois Remy 				/* update reachable_time as well, otherwise, the change will
20494bf6980dSJean-Francois Remy 				 * only be effective after the next time neigh_periodic_work
20504bf6980dSJean-Francois Remy 				 * decides to recompute it (can be multiple minutes)
20514bf6980dSJean-Francois Remy 				 */
20524bf6980dSJean-Francois Remy 				p->reachable_time =
20534bf6980dSJean-Francois Remy 					neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
20546b3f8674SThomas Graf 				break;
20556b3f8674SThomas Graf 			case NDTPA_GC_STALETIME:
20561f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, GC_STALETIME,
20571f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
20586b3f8674SThomas Graf 				break;
20596b3f8674SThomas Graf 			case NDTPA_DELAY_PROBE_TIME:
20601f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, DELAY_PROBE_TIME,
20611f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
20626b3f8674SThomas Graf 				break;
20636b3f8674SThomas Graf 			case NDTPA_RETRANS_TIME:
20641f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, RETRANS_TIME,
20651f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
20666b3f8674SThomas Graf 				break;
20676b3f8674SThomas Graf 			case NDTPA_ANYCAST_DELAY:
20683977458cSJiri Pirko 				NEIGH_VAR_SET(p, ANYCAST_DELAY,
20693977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
20706b3f8674SThomas Graf 				break;
20716b3f8674SThomas Graf 			case NDTPA_PROXY_DELAY:
20723977458cSJiri Pirko 				NEIGH_VAR_SET(p, PROXY_DELAY,
20733977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
20746b3f8674SThomas Graf 				break;
20756b3f8674SThomas Graf 			case NDTPA_LOCKTIME:
20763977458cSJiri Pirko 				NEIGH_VAR_SET(p, LOCKTIME,
20773977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
20786b3f8674SThomas Graf 				break;
2079c7fb64dbSThomas Graf 			}
20806b3f8674SThomas Graf 		}
20816b3f8674SThomas Graf 	}
20826b3f8674SThomas Graf 
2083dc25c676SGao feng 	err = -ENOENT;
2084dc25c676SGao feng 	if ((tb[NDTA_THRESH1] || tb[NDTA_THRESH2] ||
2085dc25c676SGao feng 	     tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]) &&
2086dc25c676SGao feng 	    !net_eq(net, &init_net))
2087dc25c676SGao feng 		goto errout_tbl_lock;
2088dc25c676SGao feng 
20896b3f8674SThomas Graf 	if (tb[NDTA_THRESH1])
20906b3f8674SThomas Graf 		tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
20916b3f8674SThomas Graf 
20926b3f8674SThomas Graf 	if (tb[NDTA_THRESH2])
20936b3f8674SThomas Graf 		tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
20946b3f8674SThomas Graf 
20956b3f8674SThomas Graf 	if (tb[NDTA_THRESH3])
20966b3f8674SThomas Graf 		tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
20976b3f8674SThomas Graf 
20986b3f8674SThomas Graf 	if (tb[NDTA_GC_INTERVAL])
20996b3f8674SThomas Graf 		tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2100c7fb64dbSThomas Graf 
2101c7fb64dbSThomas Graf 	err = 0;
2102c7fb64dbSThomas Graf 
21036b3f8674SThomas Graf errout_tbl_lock:
2104c7fb64dbSThomas Graf 	write_unlock_bh(&tbl->lock);
21056b3f8674SThomas Graf errout:
2106c7fb64dbSThomas Graf 	return err;
2107c7fb64dbSThomas Graf }
2108c7fb64dbSThomas Graf 
2109c8822a4eSThomas Graf static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
2110c7fb64dbSThomas Graf {
21113b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
2112ca860fb3SThomas Graf 	int family, tidx, nidx = 0;
2113ca860fb3SThomas Graf 	int tbl_skip = cb->args[0];
2114ca860fb3SThomas Graf 	int neigh_skip = cb->args[1];
2115c7fb64dbSThomas Graf 	struct neigh_table *tbl;
2116c7fb64dbSThomas Graf 
2117ca860fb3SThomas Graf 	family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
2118c7fb64dbSThomas Graf 
2119d7480fd3SWANG Cong 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2120c7fb64dbSThomas Graf 		struct neigh_parms *p;
2121c7fb64dbSThomas Graf 
2122d7480fd3SWANG Cong 		tbl = neigh_tables[tidx];
2123d7480fd3SWANG Cong 		if (!tbl)
2124d7480fd3SWANG Cong 			continue;
2125d7480fd3SWANG Cong 
2126ca860fb3SThomas Graf 		if (tidx < tbl_skip || (family && tbl->family != family))
2127c7fb64dbSThomas Graf 			continue;
2128c7fb64dbSThomas Graf 
212915e47304SEric W. Biederman 		if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
2130ca860fb3SThomas Graf 				       cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
2131ca860fb3SThomas Graf 				       NLM_F_MULTI) <= 0)
2132c7fb64dbSThomas Graf 			break;
2133c7fb64dbSThomas Graf 
213475fbfd33SNicolas Dichtel 		nidx = 0;
213575fbfd33SNicolas Dichtel 		p = list_next_entry(&tbl->parms, list);
213675fbfd33SNicolas Dichtel 		list_for_each_entry_from(p, &tbl->parms_list, list) {
2137878628fbSYOSHIFUJI Hideaki 			if (!net_eq(neigh_parms_net(p), net))
2138426b5303SEric W. Biederman 				continue;
2139426b5303SEric W. Biederman 
2140efc683fcSGautam Kachroo 			if (nidx < neigh_skip)
2141efc683fcSGautam Kachroo 				goto next;
2142c7fb64dbSThomas Graf 
2143ca860fb3SThomas Graf 			if (neightbl_fill_param_info(skb, tbl, p,
214415e47304SEric W. Biederman 						     NETLINK_CB(cb->skb).portid,
2145ca860fb3SThomas Graf 						     cb->nlh->nlmsg_seq,
2146ca860fb3SThomas Graf 						     RTM_NEWNEIGHTBL,
2147ca860fb3SThomas Graf 						     NLM_F_MULTI) <= 0)
2148c7fb64dbSThomas Graf 				goto out;
2149efc683fcSGautam Kachroo 		next:
2150efc683fcSGautam Kachroo 			nidx++;
2151c7fb64dbSThomas Graf 		}
2152c7fb64dbSThomas Graf 
2153ca860fb3SThomas Graf 		neigh_skip = 0;
2154c7fb64dbSThomas Graf 	}
2155c7fb64dbSThomas Graf out:
2156ca860fb3SThomas Graf 	cb->args[0] = tidx;
2157ca860fb3SThomas Graf 	cb->args[1] = nidx;
2158c7fb64dbSThomas Graf 
2159c7fb64dbSThomas Graf 	return skb->len;
2160c7fb64dbSThomas Graf }
21611da177e4SLinus Torvalds 
21628b8aec50SThomas Graf static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
21638b8aec50SThomas Graf 			   u32 pid, u32 seq, int type, unsigned int flags)
21641da177e4SLinus Torvalds {
21651da177e4SLinus Torvalds 	unsigned long now = jiffies;
21661da177e4SLinus Torvalds 	struct nda_cacheinfo ci;
21678b8aec50SThomas Graf 	struct nlmsghdr *nlh;
21688b8aec50SThomas Graf 	struct ndmsg *ndm;
21691da177e4SLinus Torvalds 
21708b8aec50SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
21718b8aec50SThomas Graf 	if (nlh == NULL)
217226932566SPatrick McHardy 		return -EMSGSIZE;
21738b8aec50SThomas Graf 
21748b8aec50SThomas Graf 	ndm = nlmsg_data(nlh);
21758b8aec50SThomas Graf 	ndm->ndm_family	 = neigh->ops->family;
21769ef1d4c7SPatrick McHardy 	ndm->ndm_pad1    = 0;
21779ef1d4c7SPatrick McHardy 	ndm->ndm_pad2    = 0;
21788b8aec50SThomas Graf 	ndm->ndm_flags	 = neigh->flags;
21798b8aec50SThomas Graf 	ndm->ndm_type	 = neigh->type;
21808b8aec50SThomas Graf 	ndm->ndm_ifindex = neigh->dev->ifindex;
21811da177e4SLinus Torvalds 
21829a6308d7SDavid S. Miller 	if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
21839a6308d7SDavid S. Miller 		goto nla_put_failure;
21848b8aec50SThomas Graf 
21858b8aec50SThomas Graf 	read_lock_bh(&neigh->lock);
21868b8aec50SThomas Graf 	ndm->ndm_state	 = neigh->nud_state;
21870ed8ddf4SEric Dumazet 	if (neigh->nud_state & NUD_VALID) {
21880ed8ddf4SEric Dumazet 		char haddr[MAX_ADDR_LEN];
21890ed8ddf4SEric Dumazet 
21900ed8ddf4SEric Dumazet 		neigh_ha_snapshot(haddr, neigh, neigh->dev);
21910ed8ddf4SEric Dumazet 		if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
21928b8aec50SThomas Graf 			read_unlock_bh(&neigh->lock);
21938b8aec50SThomas Graf 			goto nla_put_failure;
21948b8aec50SThomas Graf 		}
21950ed8ddf4SEric Dumazet 	}
21968b8aec50SThomas Graf 
2197b9f5f52cSStephen Hemminger 	ci.ndm_used	 = jiffies_to_clock_t(now - neigh->used);
2198b9f5f52cSStephen Hemminger 	ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2199b9f5f52cSStephen Hemminger 	ci.ndm_updated	 = jiffies_to_clock_t(now - neigh->updated);
22008b8aec50SThomas Graf 	ci.ndm_refcnt	 = atomic_read(&neigh->refcnt) - 1;
22018b8aec50SThomas Graf 	read_unlock_bh(&neigh->lock);
22028b8aec50SThomas Graf 
22039a6308d7SDavid S. Miller 	if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
22049a6308d7SDavid S. Miller 	    nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
22059a6308d7SDavid S. Miller 		goto nla_put_failure;
22068b8aec50SThomas Graf 
2207053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2208053c095aSJohannes Berg 	return 0;
22098b8aec50SThomas Graf 
22108b8aec50SThomas Graf nla_put_failure:
221126932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
221226932566SPatrick McHardy 	return -EMSGSIZE;
22131da177e4SLinus Torvalds }
22141da177e4SLinus Torvalds 
221584920c14STony Zelenoff static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
221684920c14STony Zelenoff 			    u32 pid, u32 seq, int type, unsigned int flags,
221784920c14STony Zelenoff 			    struct neigh_table *tbl)
221884920c14STony Zelenoff {
221984920c14STony Zelenoff 	struct nlmsghdr *nlh;
222084920c14STony Zelenoff 	struct ndmsg *ndm;
222184920c14STony Zelenoff 
222284920c14STony Zelenoff 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
222384920c14STony Zelenoff 	if (nlh == NULL)
222484920c14STony Zelenoff 		return -EMSGSIZE;
222584920c14STony Zelenoff 
222684920c14STony Zelenoff 	ndm = nlmsg_data(nlh);
222784920c14STony Zelenoff 	ndm->ndm_family	 = tbl->family;
222884920c14STony Zelenoff 	ndm->ndm_pad1    = 0;
222984920c14STony Zelenoff 	ndm->ndm_pad2    = 0;
223084920c14STony Zelenoff 	ndm->ndm_flags	 = pn->flags | NTF_PROXY;
2231545469f7SJun Zhao 	ndm->ndm_type	 = RTN_UNICAST;
223284920c14STony Zelenoff 	ndm->ndm_ifindex = pn->dev->ifindex;
223384920c14STony Zelenoff 	ndm->ndm_state	 = NUD_NONE;
223484920c14STony Zelenoff 
22359a6308d7SDavid S. Miller 	if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
22369a6308d7SDavid S. Miller 		goto nla_put_failure;
223784920c14STony Zelenoff 
2238053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2239053c095aSJohannes Berg 	return 0;
224084920c14STony Zelenoff 
224184920c14STony Zelenoff nla_put_failure:
224284920c14STony Zelenoff 	nlmsg_cancel(skb, nlh);
224384920c14STony Zelenoff 	return -EMSGSIZE;
224484920c14STony Zelenoff }
224584920c14STony Zelenoff 
2246d961db35SThomas Graf static void neigh_update_notify(struct neighbour *neigh)
2247d961db35SThomas Graf {
2248d961db35SThomas Graf 	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
2249d961db35SThomas Graf 	__neigh_notify(neigh, RTM_NEWNEIGH, 0);
2250d961db35SThomas Graf }
22511da177e4SLinus Torvalds 
22521da177e4SLinus Torvalds static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
22531da177e4SLinus Torvalds 			    struct netlink_callback *cb)
22541da177e4SLinus Torvalds {
22553b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
22561da177e4SLinus Torvalds 	struct neighbour *n;
22571da177e4SLinus Torvalds 	int rc, h, s_h = cb->args[1];
22581da177e4SLinus Torvalds 	int idx, s_idx = idx = cb->args[2];
2259d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
22601da177e4SLinus Torvalds 
2261d6bf7817SEric Dumazet 	rcu_read_lock_bh();
2262d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
2263d6bf7817SEric Dumazet 
22644bd6683bSEric Dumazet 	for (h = s_h; h < (1 << nht->hash_shift); h++) {
22651da177e4SLinus Torvalds 		if (h > s_h)
22661da177e4SLinus Torvalds 			s_idx = 0;
2267767e97e1SEric Dumazet 		for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2268767e97e1SEric Dumazet 		     n != NULL;
2269767e97e1SEric Dumazet 		     n = rcu_dereference_bh(n->next)) {
227009ad9bc7SOctavian Purdila 			if (!net_eq(dev_net(n->dev), net))
2271426b5303SEric W. Biederman 				continue;
2272efc683fcSGautam Kachroo 			if (idx < s_idx)
2273efc683fcSGautam Kachroo 				goto next;
227415e47304SEric W. Biederman 			if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
22751da177e4SLinus Torvalds 					    cb->nlh->nlmsg_seq,
2276b6544c0bSJamal Hadi Salim 					    RTM_NEWNEIGH,
2277b6544c0bSJamal Hadi Salim 					    NLM_F_MULTI) <= 0) {
22781da177e4SLinus Torvalds 				rc = -1;
22791da177e4SLinus Torvalds 				goto out;
22801da177e4SLinus Torvalds 			}
2281efc683fcSGautam Kachroo next:
2282efc683fcSGautam Kachroo 			idx++;
22831da177e4SLinus Torvalds 		}
22841da177e4SLinus Torvalds 	}
22851da177e4SLinus Torvalds 	rc = skb->len;
22861da177e4SLinus Torvalds out:
2287d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
22881da177e4SLinus Torvalds 	cb->args[1] = h;
22891da177e4SLinus Torvalds 	cb->args[2] = idx;
22901da177e4SLinus Torvalds 	return rc;
22911da177e4SLinus Torvalds }
22921da177e4SLinus Torvalds 
229384920c14STony Zelenoff static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
229484920c14STony Zelenoff 			     struct netlink_callback *cb)
229584920c14STony Zelenoff {
229684920c14STony Zelenoff 	struct pneigh_entry *n;
229784920c14STony Zelenoff 	struct net *net = sock_net(skb->sk);
229884920c14STony Zelenoff 	int rc, h, s_h = cb->args[3];
229984920c14STony Zelenoff 	int idx, s_idx = idx = cb->args[4];
230084920c14STony Zelenoff 
230184920c14STony Zelenoff 	read_lock_bh(&tbl->lock);
230284920c14STony Zelenoff 
23034bd6683bSEric Dumazet 	for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
230484920c14STony Zelenoff 		if (h > s_h)
230584920c14STony Zelenoff 			s_idx = 0;
230684920c14STony Zelenoff 		for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
230784920c14STony Zelenoff 			if (dev_net(n->dev) != net)
230884920c14STony Zelenoff 				continue;
230984920c14STony Zelenoff 			if (idx < s_idx)
231084920c14STony Zelenoff 				goto next;
231115e47304SEric W. Biederman 			if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
231284920c14STony Zelenoff 					    cb->nlh->nlmsg_seq,
231384920c14STony Zelenoff 					    RTM_NEWNEIGH,
231484920c14STony Zelenoff 					    NLM_F_MULTI, tbl) <= 0) {
231584920c14STony Zelenoff 				read_unlock_bh(&tbl->lock);
231684920c14STony Zelenoff 				rc = -1;
231784920c14STony Zelenoff 				goto out;
231884920c14STony Zelenoff 			}
231984920c14STony Zelenoff 		next:
232084920c14STony Zelenoff 			idx++;
232184920c14STony Zelenoff 		}
232284920c14STony Zelenoff 	}
232384920c14STony Zelenoff 
232484920c14STony Zelenoff 	read_unlock_bh(&tbl->lock);
232584920c14STony Zelenoff 	rc = skb->len;
232684920c14STony Zelenoff out:
232784920c14STony Zelenoff 	cb->args[3] = h;
232884920c14STony Zelenoff 	cb->args[4] = idx;
232984920c14STony Zelenoff 	return rc;
233084920c14STony Zelenoff 
233184920c14STony Zelenoff }
233284920c14STony Zelenoff 
2333c8822a4eSThomas Graf static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
23341da177e4SLinus Torvalds {
23351da177e4SLinus Torvalds 	struct neigh_table *tbl;
23361da177e4SLinus Torvalds 	int t, family, s_t;
233784920c14STony Zelenoff 	int proxy = 0;
23384bd6683bSEric Dumazet 	int err;
23391da177e4SLinus Torvalds 
23408b8aec50SThomas Graf 	family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
234184920c14STony Zelenoff 
234284920c14STony Zelenoff 	/* check for full ndmsg structure presence, family member is
234384920c14STony Zelenoff 	 * the same for both structures
234484920c14STony Zelenoff 	 */
234584920c14STony Zelenoff 	if (nlmsg_len(cb->nlh) >= sizeof(struct ndmsg) &&
234684920c14STony Zelenoff 	    ((struct ndmsg *) nlmsg_data(cb->nlh))->ndm_flags == NTF_PROXY)
234784920c14STony Zelenoff 		proxy = 1;
234884920c14STony Zelenoff 
23491da177e4SLinus Torvalds 	s_t = cb->args[0];
23501da177e4SLinus Torvalds 
2351d7480fd3SWANG Cong 	for (t = 0; t < NEIGH_NR_TABLES; t++) {
2352d7480fd3SWANG Cong 		tbl = neigh_tables[t];
2353d7480fd3SWANG Cong 
2354d7480fd3SWANG Cong 		if (!tbl)
2355d7480fd3SWANG Cong 			continue;
23561da177e4SLinus Torvalds 		if (t < s_t || (family && tbl->family != family))
23571da177e4SLinus Torvalds 			continue;
23581da177e4SLinus Torvalds 		if (t > s_t)
23591da177e4SLinus Torvalds 			memset(&cb->args[1], 0, sizeof(cb->args) -
23601da177e4SLinus Torvalds 						sizeof(cb->args[0]));
236184920c14STony Zelenoff 		if (proxy)
236284920c14STony Zelenoff 			err = pneigh_dump_table(tbl, skb, cb);
236384920c14STony Zelenoff 		else
236484920c14STony Zelenoff 			err = neigh_dump_table(tbl, skb, cb);
23654bd6683bSEric Dumazet 		if (err < 0)
23664bd6683bSEric Dumazet 			break;
23671da177e4SLinus Torvalds 	}
23681da177e4SLinus Torvalds 
23691da177e4SLinus Torvalds 	cb->args[0] = t;
23701da177e4SLinus Torvalds 	return skb->len;
23711da177e4SLinus Torvalds }
23721da177e4SLinus Torvalds 
23731da177e4SLinus Torvalds void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
23741da177e4SLinus Torvalds {
23751da177e4SLinus Torvalds 	int chain;
2376d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
23771da177e4SLinus Torvalds 
2378d6bf7817SEric Dumazet 	rcu_read_lock_bh();
2379d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
2380d6bf7817SEric Dumazet 
2381767e97e1SEric Dumazet 	read_lock(&tbl->lock); /* avoid resizes */
2382cd089336SDavid S. Miller 	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
23831da177e4SLinus Torvalds 		struct neighbour *n;
23841da177e4SLinus Torvalds 
2385767e97e1SEric Dumazet 		for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
2386767e97e1SEric Dumazet 		     n != NULL;
2387767e97e1SEric Dumazet 		     n = rcu_dereference_bh(n->next))
23881da177e4SLinus Torvalds 			cb(n, cookie);
23891da177e4SLinus Torvalds 	}
2390d6bf7817SEric Dumazet 	read_unlock(&tbl->lock);
2391d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
23921da177e4SLinus Torvalds }
23931da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_for_each);
23941da177e4SLinus Torvalds 
23951da177e4SLinus Torvalds /* The tbl->lock must be held as a writer and BH disabled. */
23961da177e4SLinus Torvalds void __neigh_for_each_release(struct neigh_table *tbl,
23971da177e4SLinus Torvalds 			      int (*cb)(struct neighbour *))
23981da177e4SLinus Torvalds {
23991da177e4SLinus Torvalds 	int chain;
2400d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
24011da177e4SLinus Torvalds 
2402d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
2403d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
2404cd089336SDavid S. Miller 	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
2405767e97e1SEric Dumazet 		struct neighbour *n;
2406767e97e1SEric Dumazet 		struct neighbour __rcu **np;
24071da177e4SLinus Torvalds 
2408d6bf7817SEric Dumazet 		np = &nht->hash_buckets[chain];
2409767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
2410767e97e1SEric Dumazet 					lockdep_is_held(&tbl->lock))) != NULL) {
24111da177e4SLinus Torvalds 			int release;
24121da177e4SLinus Torvalds 
24131da177e4SLinus Torvalds 			write_lock(&n->lock);
24141da177e4SLinus Torvalds 			release = cb(n);
24151da177e4SLinus Torvalds 			if (release) {
2416767e97e1SEric Dumazet 				rcu_assign_pointer(*np,
2417767e97e1SEric Dumazet 					rcu_dereference_protected(n->next,
2418767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
24191da177e4SLinus Torvalds 				n->dead = 1;
24201da177e4SLinus Torvalds 			} else
24211da177e4SLinus Torvalds 				np = &n->next;
24221da177e4SLinus Torvalds 			write_unlock(&n->lock);
24234f494554SThomas Graf 			if (release)
24244f494554SThomas Graf 				neigh_cleanup_and_release(n);
24251da177e4SLinus Torvalds 		}
24261da177e4SLinus Torvalds 	}
2427ecbb4169SAlexey Kuznetsov }
24281da177e4SLinus Torvalds EXPORT_SYMBOL(__neigh_for_each_release);
24291da177e4SLinus Torvalds 
24301da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
24311da177e4SLinus Torvalds 
24321da177e4SLinus Torvalds static struct neighbour *neigh_get_first(struct seq_file *seq)
24331da177e4SLinus Torvalds {
24341da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
24351218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
2436d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = state->nht;
24371da177e4SLinus Torvalds 	struct neighbour *n = NULL;
24381da177e4SLinus Torvalds 	int bucket = state->bucket;
24391da177e4SLinus Torvalds 
24401da177e4SLinus Torvalds 	state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
2441cd089336SDavid S. Miller 	for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
2442767e97e1SEric Dumazet 		n = rcu_dereference_bh(nht->hash_buckets[bucket]);
24431da177e4SLinus Torvalds 
24441da177e4SLinus Torvalds 		while (n) {
2445878628fbSYOSHIFUJI Hideaki 			if (!net_eq(dev_net(n->dev), net))
2446426b5303SEric W. Biederman 				goto next;
24471da177e4SLinus Torvalds 			if (state->neigh_sub_iter) {
24481da177e4SLinus Torvalds 				loff_t fakep = 0;
24491da177e4SLinus Torvalds 				void *v;
24501da177e4SLinus Torvalds 
24511da177e4SLinus Torvalds 				v = state->neigh_sub_iter(state, n, &fakep);
24521da177e4SLinus Torvalds 				if (!v)
24531da177e4SLinus Torvalds 					goto next;
24541da177e4SLinus Torvalds 			}
24551da177e4SLinus Torvalds 			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
24561da177e4SLinus Torvalds 				break;
24571da177e4SLinus Torvalds 			if (n->nud_state & ~NUD_NOARP)
24581da177e4SLinus Torvalds 				break;
24591da177e4SLinus Torvalds next:
2460767e97e1SEric Dumazet 			n = rcu_dereference_bh(n->next);
24611da177e4SLinus Torvalds 		}
24621da177e4SLinus Torvalds 
24631da177e4SLinus Torvalds 		if (n)
24641da177e4SLinus Torvalds 			break;
24651da177e4SLinus Torvalds 	}
24661da177e4SLinus Torvalds 	state->bucket = bucket;
24671da177e4SLinus Torvalds 
24681da177e4SLinus Torvalds 	return n;
24691da177e4SLinus Torvalds }
24701da177e4SLinus Torvalds 
24711da177e4SLinus Torvalds static struct neighbour *neigh_get_next(struct seq_file *seq,
24721da177e4SLinus Torvalds 					struct neighbour *n,
24731da177e4SLinus Torvalds 					loff_t *pos)
24741da177e4SLinus Torvalds {
24751da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
24761218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
2477d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = state->nht;
24781da177e4SLinus Torvalds 
24791da177e4SLinus Torvalds 	if (state->neigh_sub_iter) {
24801da177e4SLinus Torvalds 		void *v = state->neigh_sub_iter(state, n, pos);
24811da177e4SLinus Torvalds 		if (v)
24821da177e4SLinus Torvalds 			return n;
24831da177e4SLinus Torvalds 	}
2484767e97e1SEric Dumazet 	n = rcu_dereference_bh(n->next);
24851da177e4SLinus Torvalds 
24861da177e4SLinus Torvalds 	while (1) {
24871da177e4SLinus Torvalds 		while (n) {
2488878628fbSYOSHIFUJI Hideaki 			if (!net_eq(dev_net(n->dev), net))
2489426b5303SEric W. Biederman 				goto next;
24901da177e4SLinus Torvalds 			if (state->neigh_sub_iter) {
24911da177e4SLinus Torvalds 				void *v = state->neigh_sub_iter(state, n, pos);
24921da177e4SLinus Torvalds 				if (v)
24931da177e4SLinus Torvalds 					return n;
24941da177e4SLinus Torvalds 				goto next;
24951da177e4SLinus Torvalds 			}
24961da177e4SLinus Torvalds 			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
24971da177e4SLinus Torvalds 				break;
24981da177e4SLinus Torvalds 
24991da177e4SLinus Torvalds 			if (n->nud_state & ~NUD_NOARP)
25001da177e4SLinus Torvalds 				break;
25011da177e4SLinus Torvalds next:
2502767e97e1SEric Dumazet 			n = rcu_dereference_bh(n->next);
25031da177e4SLinus Torvalds 		}
25041da177e4SLinus Torvalds 
25051da177e4SLinus Torvalds 		if (n)
25061da177e4SLinus Torvalds 			break;
25071da177e4SLinus Torvalds 
2508cd089336SDavid S. Miller 		if (++state->bucket >= (1 << nht->hash_shift))
25091da177e4SLinus Torvalds 			break;
25101da177e4SLinus Torvalds 
2511767e97e1SEric Dumazet 		n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
25121da177e4SLinus Torvalds 	}
25131da177e4SLinus Torvalds 
25141da177e4SLinus Torvalds 	if (n && pos)
25151da177e4SLinus Torvalds 		--(*pos);
25161da177e4SLinus Torvalds 	return n;
25171da177e4SLinus Torvalds }
25181da177e4SLinus Torvalds 
25191da177e4SLinus Torvalds static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
25201da177e4SLinus Torvalds {
25211da177e4SLinus Torvalds 	struct neighbour *n = neigh_get_first(seq);
25221da177e4SLinus Torvalds 
25231da177e4SLinus Torvalds 	if (n) {
2524745e2031SChris Larson 		--(*pos);
25251da177e4SLinus Torvalds 		while (*pos) {
25261da177e4SLinus Torvalds 			n = neigh_get_next(seq, n, pos);
25271da177e4SLinus Torvalds 			if (!n)
25281da177e4SLinus Torvalds 				break;
25291da177e4SLinus Torvalds 		}
25301da177e4SLinus Torvalds 	}
25311da177e4SLinus Torvalds 	return *pos ? NULL : n;
25321da177e4SLinus Torvalds }
25331da177e4SLinus Torvalds 
25341da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
25351da177e4SLinus Torvalds {
25361da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
25371218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
25381da177e4SLinus Torvalds 	struct neigh_table *tbl = state->tbl;
25391da177e4SLinus Torvalds 	struct pneigh_entry *pn = NULL;
25401da177e4SLinus Torvalds 	int bucket = state->bucket;
25411da177e4SLinus Torvalds 
25421da177e4SLinus Torvalds 	state->flags |= NEIGH_SEQ_IS_PNEIGH;
25431da177e4SLinus Torvalds 	for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
25441da177e4SLinus Torvalds 		pn = tbl->phash_buckets[bucket];
2545878628fbSYOSHIFUJI Hideaki 		while (pn && !net_eq(pneigh_net(pn), net))
2546426b5303SEric W. Biederman 			pn = pn->next;
25471da177e4SLinus Torvalds 		if (pn)
25481da177e4SLinus Torvalds 			break;
25491da177e4SLinus Torvalds 	}
25501da177e4SLinus Torvalds 	state->bucket = bucket;
25511da177e4SLinus Torvalds 
25521da177e4SLinus Torvalds 	return pn;
25531da177e4SLinus Torvalds }
25541da177e4SLinus Torvalds 
25551da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
25561da177e4SLinus Torvalds 					    struct pneigh_entry *pn,
25571da177e4SLinus Torvalds 					    loff_t *pos)
25581da177e4SLinus Torvalds {
25591da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
25601218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
25611da177e4SLinus Torvalds 	struct neigh_table *tbl = state->tbl;
25621da177e4SLinus Torvalds 
2563df07a94cSJorge Boncompte [DTI2] 	do {
25641da177e4SLinus Torvalds 		pn = pn->next;
2565df07a94cSJorge Boncompte [DTI2] 	} while (pn && !net_eq(pneigh_net(pn), net));
2566df07a94cSJorge Boncompte [DTI2] 
25671da177e4SLinus Torvalds 	while (!pn) {
25681da177e4SLinus Torvalds 		if (++state->bucket > PNEIGH_HASHMASK)
25691da177e4SLinus Torvalds 			break;
25701da177e4SLinus Torvalds 		pn = tbl->phash_buckets[state->bucket];
2571878628fbSYOSHIFUJI Hideaki 		while (pn && !net_eq(pneigh_net(pn), net))
2572426b5303SEric W. Biederman 			pn = pn->next;
25731da177e4SLinus Torvalds 		if (pn)
25741da177e4SLinus Torvalds 			break;
25751da177e4SLinus Torvalds 	}
25761da177e4SLinus Torvalds 
25771da177e4SLinus Torvalds 	if (pn && pos)
25781da177e4SLinus Torvalds 		--(*pos);
25791da177e4SLinus Torvalds 
25801da177e4SLinus Torvalds 	return pn;
25811da177e4SLinus Torvalds }
25821da177e4SLinus Torvalds 
25831da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
25841da177e4SLinus Torvalds {
25851da177e4SLinus Torvalds 	struct pneigh_entry *pn = pneigh_get_first(seq);
25861da177e4SLinus Torvalds 
25871da177e4SLinus Torvalds 	if (pn) {
2588745e2031SChris Larson 		--(*pos);
25891da177e4SLinus Torvalds 		while (*pos) {
25901da177e4SLinus Torvalds 			pn = pneigh_get_next(seq, pn, pos);
25911da177e4SLinus Torvalds 			if (!pn)
25921da177e4SLinus Torvalds 				break;
25931da177e4SLinus Torvalds 		}
25941da177e4SLinus Torvalds 	}
25951da177e4SLinus Torvalds 	return *pos ? NULL : pn;
25961da177e4SLinus Torvalds }
25971da177e4SLinus Torvalds 
25981da177e4SLinus Torvalds static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
25991da177e4SLinus Torvalds {
26001da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
26011da177e4SLinus Torvalds 	void *rc;
2602745e2031SChris Larson 	loff_t idxpos = *pos;
26031da177e4SLinus Torvalds 
2604745e2031SChris Larson 	rc = neigh_get_idx(seq, &idxpos);
26051da177e4SLinus Torvalds 	if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
2606745e2031SChris Larson 		rc = pneigh_get_idx(seq, &idxpos);
26071da177e4SLinus Torvalds 
26081da177e4SLinus Torvalds 	return rc;
26091da177e4SLinus Torvalds }
26101da177e4SLinus Torvalds 
26111da177e4SLinus Torvalds void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags)
2612d6bf7817SEric Dumazet 	__acquires(rcu_bh)
26131da177e4SLinus Torvalds {
26141da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
26151da177e4SLinus Torvalds 
26161da177e4SLinus Torvalds 	state->tbl = tbl;
26171da177e4SLinus Torvalds 	state->bucket = 0;
26181da177e4SLinus Torvalds 	state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
26191da177e4SLinus Torvalds 
2620d6bf7817SEric Dumazet 	rcu_read_lock_bh();
2621d6bf7817SEric Dumazet 	state->nht = rcu_dereference_bh(tbl->nht);
2622767e97e1SEric Dumazet 
2623745e2031SChris Larson 	return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
26241da177e4SLinus Torvalds }
26251da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_start);
26261da177e4SLinus Torvalds 
26271da177e4SLinus Torvalds void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
26281da177e4SLinus Torvalds {
26291da177e4SLinus Torvalds 	struct neigh_seq_state *state;
26301da177e4SLinus Torvalds 	void *rc;
26311da177e4SLinus Torvalds 
26321da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN) {
2633bff69732SChris Larson 		rc = neigh_get_first(seq);
26341da177e4SLinus Torvalds 		goto out;
26351da177e4SLinus Torvalds 	}
26361da177e4SLinus Torvalds 
26371da177e4SLinus Torvalds 	state = seq->private;
26381da177e4SLinus Torvalds 	if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
26391da177e4SLinus Torvalds 		rc = neigh_get_next(seq, v, NULL);
26401da177e4SLinus Torvalds 		if (rc)
26411da177e4SLinus Torvalds 			goto out;
26421da177e4SLinus Torvalds 		if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
26431da177e4SLinus Torvalds 			rc = pneigh_get_first(seq);
26441da177e4SLinus Torvalds 	} else {
26451da177e4SLinus Torvalds 		BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
26461da177e4SLinus Torvalds 		rc = pneigh_get_next(seq, v, NULL);
26471da177e4SLinus Torvalds 	}
26481da177e4SLinus Torvalds out:
26491da177e4SLinus Torvalds 	++(*pos);
26501da177e4SLinus Torvalds 	return rc;
26511da177e4SLinus Torvalds }
26521da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_next);
26531da177e4SLinus Torvalds 
26541da177e4SLinus Torvalds void neigh_seq_stop(struct seq_file *seq, void *v)
2655d6bf7817SEric Dumazet 	__releases(rcu_bh)
26561da177e4SLinus Torvalds {
2657d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
26581da177e4SLinus Torvalds }
26591da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_stop);
26601da177e4SLinus Torvalds 
26611da177e4SLinus Torvalds /* statistics via seq_file */
26621da177e4SLinus Torvalds 
26631da177e4SLinus Torvalds static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
26641da177e4SLinus Torvalds {
266581c1ebfcSAlexey Dobriyan 	struct neigh_table *tbl = seq->private;
26661da177e4SLinus Torvalds 	int cpu;
26671da177e4SLinus Torvalds 
26681da177e4SLinus Torvalds 	if (*pos == 0)
26691da177e4SLinus Torvalds 		return SEQ_START_TOKEN;
26701da177e4SLinus Torvalds 
26710f23174aSRusty Russell 	for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
26721da177e4SLinus Torvalds 		if (!cpu_possible(cpu))
26731da177e4SLinus Torvalds 			continue;
26741da177e4SLinus Torvalds 		*pos = cpu+1;
26751da177e4SLinus Torvalds 		return per_cpu_ptr(tbl->stats, cpu);
26761da177e4SLinus Torvalds 	}
26771da177e4SLinus Torvalds 	return NULL;
26781da177e4SLinus Torvalds }
26791da177e4SLinus Torvalds 
26801da177e4SLinus Torvalds static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
26811da177e4SLinus Torvalds {
268281c1ebfcSAlexey Dobriyan 	struct neigh_table *tbl = seq->private;
26831da177e4SLinus Torvalds 	int cpu;
26841da177e4SLinus Torvalds 
26850f23174aSRusty Russell 	for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
26861da177e4SLinus Torvalds 		if (!cpu_possible(cpu))
26871da177e4SLinus Torvalds 			continue;
26881da177e4SLinus Torvalds 		*pos = cpu+1;
26891da177e4SLinus Torvalds 		return per_cpu_ptr(tbl->stats, cpu);
26901da177e4SLinus Torvalds 	}
26911da177e4SLinus Torvalds 	return NULL;
26921da177e4SLinus Torvalds }
26931da177e4SLinus Torvalds 
26941da177e4SLinus Torvalds static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
26951da177e4SLinus Torvalds {
26961da177e4SLinus Torvalds 
26971da177e4SLinus Torvalds }
26981da177e4SLinus Torvalds 
26991da177e4SLinus Torvalds static int neigh_stat_seq_show(struct seq_file *seq, void *v)
27001da177e4SLinus Torvalds {
270181c1ebfcSAlexey Dobriyan 	struct neigh_table *tbl = seq->private;
27021da177e4SLinus Torvalds 	struct neigh_statistics *st = v;
27031da177e4SLinus Torvalds 
27041da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN) {
27059a6d276eSNeil Horman 		seq_printf(seq, "entries  allocs destroys hash_grows  lookups hits  res_failed  rcv_probes_mcast rcv_probes_ucast  periodic_gc_runs forced_gc_runs unresolved_discards\n");
27061da177e4SLinus Torvalds 		return 0;
27071da177e4SLinus Torvalds 	}
27081da177e4SLinus Torvalds 
27091da177e4SLinus Torvalds 	seq_printf(seq, "%08x  %08lx %08lx %08lx  %08lx %08lx  %08lx  "
27109a6d276eSNeil Horman 			"%08lx %08lx  %08lx %08lx %08lx\n",
27111da177e4SLinus Torvalds 		   atomic_read(&tbl->entries),
27121da177e4SLinus Torvalds 
27131da177e4SLinus Torvalds 		   st->allocs,
27141da177e4SLinus Torvalds 		   st->destroys,
27151da177e4SLinus Torvalds 		   st->hash_grows,
27161da177e4SLinus Torvalds 
27171da177e4SLinus Torvalds 		   st->lookups,
27181da177e4SLinus Torvalds 		   st->hits,
27191da177e4SLinus Torvalds 
27201da177e4SLinus Torvalds 		   st->res_failed,
27211da177e4SLinus Torvalds 
27221da177e4SLinus Torvalds 		   st->rcv_probes_mcast,
27231da177e4SLinus Torvalds 		   st->rcv_probes_ucast,
27241da177e4SLinus Torvalds 
27251da177e4SLinus Torvalds 		   st->periodic_gc_runs,
27269a6d276eSNeil Horman 		   st->forced_gc_runs,
27279a6d276eSNeil Horman 		   st->unres_discards
27281da177e4SLinus Torvalds 		   );
27291da177e4SLinus Torvalds 
27301da177e4SLinus Torvalds 	return 0;
27311da177e4SLinus Torvalds }
27321da177e4SLinus Torvalds 
2733f690808eSStephen Hemminger static const struct seq_operations neigh_stat_seq_ops = {
27341da177e4SLinus Torvalds 	.start	= neigh_stat_seq_start,
27351da177e4SLinus Torvalds 	.next	= neigh_stat_seq_next,
27361da177e4SLinus Torvalds 	.stop	= neigh_stat_seq_stop,
27371da177e4SLinus Torvalds 	.show	= neigh_stat_seq_show,
27381da177e4SLinus Torvalds };
27391da177e4SLinus Torvalds 
27401da177e4SLinus Torvalds static int neigh_stat_seq_open(struct inode *inode, struct file *file)
27411da177e4SLinus Torvalds {
27421da177e4SLinus Torvalds 	int ret = seq_open(file, &neigh_stat_seq_ops);
27431da177e4SLinus Torvalds 
27441da177e4SLinus Torvalds 	if (!ret) {
27451da177e4SLinus Torvalds 		struct seq_file *sf = file->private_data;
2746d9dda78bSAl Viro 		sf->private = PDE_DATA(inode);
27471da177e4SLinus Torvalds 	}
27481da177e4SLinus Torvalds 	return ret;
27491da177e4SLinus Torvalds };
27501da177e4SLinus Torvalds 
27519a32144eSArjan van de Ven static const struct file_operations neigh_stat_seq_fops = {
27521da177e4SLinus Torvalds 	.owner	 = THIS_MODULE,
27531da177e4SLinus Torvalds 	.open 	 = neigh_stat_seq_open,
27541da177e4SLinus Torvalds 	.read	 = seq_read,
27551da177e4SLinus Torvalds 	.llseek	 = seq_lseek,
27561da177e4SLinus Torvalds 	.release = seq_release,
27571da177e4SLinus Torvalds };
27581da177e4SLinus Torvalds 
27591da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */
27601da177e4SLinus Torvalds 
2761339bf98fSThomas Graf static inline size_t neigh_nlmsg_size(void)
2762339bf98fSThomas Graf {
2763339bf98fSThomas Graf 	return NLMSG_ALIGN(sizeof(struct ndmsg))
2764339bf98fSThomas Graf 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
2765339bf98fSThomas Graf 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
2766339bf98fSThomas Graf 	       + nla_total_size(sizeof(struct nda_cacheinfo))
2767339bf98fSThomas Graf 	       + nla_total_size(4); /* NDA_PROBES */
2768339bf98fSThomas Graf }
2769339bf98fSThomas Graf 
2770b8673311SThomas Graf static void __neigh_notify(struct neighbour *n, int type, int flags)
27711da177e4SLinus Torvalds {
2772c346dca1SYOSHIFUJI Hideaki 	struct net *net = dev_net(n->dev);
27738b8aec50SThomas Graf 	struct sk_buff *skb;
2774b8673311SThomas Graf 	int err = -ENOBUFS;
27751da177e4SLinus Torvalds 
2776339bf98fSThomas Graf 	skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
27778b8aec50SThomas Graf 	if (skb == NULL)
2778b8673311SThomas Graf 		goto errout;
27791da177e4SLinus Torvalds 
2780b8673311SThomas Graf 	err = neigh_fill_info(skb, n, 0, 0, type, flags);
278126932566SPatrick McHardy 	if (err < 0) {
278226932566SPatrick McHardy 		/* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
278326932566SPatrick McHardy 		WARN_ON(err == -EMSGSIZE);
278426932566SPatrick McHardy 		kfree_skb(skb);
278526932566SPatrick McHardy 		goto errout;
278626932566SPatrick McHardy 	}
27871ce85fe4SPablo Neira Ayuso 	rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
27881ce85fe4SPablo Neira Ayuso 	return;
2789b8673311SThomas Graf errout:
2790b8673311SThomas Graf 	if (err < 0)
2791426b5303SEric W. Biederman 		rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
2792b8673311SThomas Graf }
2793b8673311SThomas Graf 
2794b8673311SThomas Graf void neigh_app_ns(struct neighbour *n)
2795b8673311SThomas Graf {
2796b8673311SThomas Graf 	__neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);
27978b8aec50SThomas Graf }
27980a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_app_ns);
27991da177e4SLinus Torvalds 
28001da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL
2801b93196dcSCong Wang static int zero;
2802555445cdSFrancesco Fusco static int int_max = INT_MAX;
2803b93196dcSCong Wang static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
28041da177e4SLinus Torvalds 
2805fe2c6338SJoe Perches static int proc_unres_qlen(struct ctl_table *ctl, int write,
2806fe2c6338SJoe Perches 			   void __user *buffer, size_t *lenp, loff_t *ppos)
28078b5c171bSEric Dumazet {
28088b5c171bSEric Dumazet 	int size, ret;
2809fe2c6338SJoe Perches 	struct ctl_table tmp = *ctl;
28108b5c171bSEric Dumazet 
2811ce46cc64SShan Wei 	tmp.extra1 = &zero;
2812ce46cc64SShan Wei 	tmp.extra2 = &unres_qlen_max;
28138b5c171bSEric Dumazet 	tmp.data = &size;
2814ce46cc64SShan Wei 
2815ce46cc64SShan Wei 	size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN);
2816ce46cc64SShan Wei 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
2817ce46cc64SShan Wei 
28188b5c171bSEric Dumazet 	if (write && !ret)
28198b5c171bSEric Dumazet 		*(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
28208b5c171bSEric Dumazet 	return ret;
28218b5c171bSEric Dumazet }
28228b5c171bSEric Dumazet 
28231d4c8c29SJiri Pirko static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
28241d4c8c29SJiri Pirko 						   int family)
28251d4c8c29SJiri Pirko {
2826bba24896SJiri Pirko 	switch (family) {
2827bba24896SJiri Pirko 	case AF_INET:
28281d4c8c29SJiri Pirko 		return __in_dev_arp_parms_get_rcu(dev);
2829bba24896SJiri Pirko 	case AF_INET6:
2830bba24896SJiri Pirko 		return __in6_dev_nd_parms_get_rcu(dev);
2831bba24896SJiri Pirko 	}
28321d4c8c29SJiri Pirko 	return NULL;
28331d4c8c29SJiri Pirko }
28341d4c8c29SJiri Pirko 
28351d4c8c29SJiri Pirko static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
28361d4c8c29SJiri Pirko 				  int index)
28371d4c8c29SJiri Pirko {
28381d4c8c29SJiri Pirko 	struct net_device *dev;
28391d4c8c29SJiri Pirko 	int family = neigh_parms_family(p);
28401d4c8c29SJiri Pirko 
28411d4c8c29SJiri Pirko 	rcu_read_lock();
28421d4c8c29SJiri Pirko 	for_each_netdev_rcu(net, dev) {
28431d4c8c29SJiri Pirko 		struct neigh_parms *dst_p =
28441d4c8c29SJiri Pirko 				neigh_get_dev_parms_rcu(dev, family);
28451d4c8c29SJiri Pirko 
28461d4c8c29SJiri Pirko 		if (dst_p && !test_bit(index, dst_p->data_state))
28471d4c8c29SJiri Pirko 			dst_p->data[index] = p->data[index];
28481d4c8c29SJiri Pirko 	}
28491d4c8c29SJiri Pirko 	rcu_read_unlock();
28501d4c8c29SJiri Pirko }
28511d4c8c29SJiri Pirko 
28521d4c8c29SJiri Pirko static void neigh_proc_update(struct ctl_table *ctl, int write)
28531d4c8c29SJiri Pirko {
28541d4c8c29SJiri Pirko 	struct net_device *dev = ctl->extra1;
28551d4c8c29SJiri Pirko 	struct neigh_parms *p = ctl->extra2;
285677d47afbSJiri Pirko 	struct net *net = neigh_parms_net(p);
28571d4c8c29SJiri Pirko 	int index = (int *) ctl->data - p->data;
28581d4c8c29SJiri Pirko 
28591d4c8c29SJiri Pirko 	if (!write)
28601d4c8c29SJiri Pirko 		return;
28611d4c8c29SJiri Pirko 
28621d4c8c29SJiri Pirko 	set_bit(index, p->data_state);
28631d4c8c29SJiri Pirko 	if (!dev) /* NULL dev means this is default value */
28641d4c8c29SJiri Pirko 		neigh_copy_dflt_parms(net, p, index);
28651d4c8c29SJiri Pirko }
28661d4c8c29SJiri Pirko 
28671f9248e5SJiri Pirko static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
28681f9248e5SJiri Pirko 					   void __user *buffer,
28691f9248e5SJiri Pirko 					   size_t *lenp, loff_t *ppos)
28701f9248e5SJiri Pirko {
28711f9248e5SJiri Pirko 	struct ctl_table tmp = *ctl;
28721d4c8c29SJiri Pirko 	int ret;
28731f9248e5SJiri Pirko 
28741f9248e5SJiri Pirko 	tmp.extra1 = &zero;
28751f9248e5SJiri Pirko 	tmp.extra2 = &int_max;
28761f9248e5SJiri Pirko 
28771d4c8c29SJiri Pirko 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
28781d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
28791d4c8c29SJiri Pirko 	return ret;
28801f9248e5SJiri Pirko }
28811f9248e5SJiri Pirko 
2882cb5b09c1SJiri Pirko int neigh_proc_dointvec(struct ctl_table *ctl, int write,
2883cb5b09c1SJiri Pirko 			void __user *buffer, size_t *lenp, loff_t *ppos)
2884cb5b09c1SJiri Pirko {
28851d4c8c29SJiri Pirko 	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
28861d4c8c29SJiri Pirko 
28871d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
28881d4c8c29SJiri Pirko 	return ret;
2889cb5b09c1SJiri Pirko }
2890cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec);
2891cb5b09c1SJiri Pirko 
2892cb5b09c1SJiri Pirko int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write,
2893cb5b09c1SJiri Pirko 				void __user *buffer,
2894cb5b09c1SJiri Pirko 				size_t *lenp, loff_t *ppos)
2895cb5b09c1SJiri Pirko {
28961d4c8c29SJiri Pirko 	int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
28971d4c8c29SJiri Pirko 
28981d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
28991d4c8c29SJiri Pirko 	return ret;
2900cb5b09c1SJiri Pirko }
2901cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
2902cb5b09c1SJiri Pirko 
2903cb5b09c1SJiri Pirko static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write,
2904cb5b09c1SJiri Pirko 					      void __user *buffer,
2905cb5b09c1SJiri Pirko 					      size_t *lenp, loff_t *ppos)
2906cb5b09c1SJiri Pirko {
29071d4c8c29SJiri Pirko 	int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
29081d4c8c29SJiri Pirko 
29091d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
29101d4c8c29SJiri Pirko 	return ret;
2911cb5b09c1SJiri Pirko }
2912cb5b09c1SJiri Pirko 
2913cb5b09c1SJiri Pirko int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
2914cb5b09c1SJiri Pirko 				   void __user *buffer,
2915cb5b09c1SJiri Pirko 				   size_t *lenp, loff_t *ppos)
2916cb5b09c1SJiri Pirko {
29171d4c8c29SJiri Pirko 	int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
29181d4c8c29SJiri Pirko 
29191d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
29201d4c8c29SJiri Pirko 	return ret;
2921cb5b09c1SJiri Pirko }
2922cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
2923cb5b09c1SJiri Pirko 
2924cb5b09c1SJiri Pirko static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
2925cb5b09c1SJiri Pirko 					  void __user *buffer,
2926cb5b09c1SJiri Pirko 					  size_t *lenp, loff_t *ppos)
2927cb5b09c1SJiri Pirko {
29281d4c8c29SJiri Pirko 	int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
29291d4c8c29SJiri Pirko 
29301d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
29311d4c8c29SJiri Pirko 	return ret;
2932cb5b09c1SJiri Pirko }
2933cb5b09c1SJiri Pirko 
29344bf6980dSJean-Francois Remy static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write,
29354bf6980dSJean-Francois Remy 					  void __user *buffer,
29364bf6980dSJean-Francois Remy 					  size_t *lenp, loff_t *ppos)
29374bf6980dSJean-Francois Remy {
29384bf6980dSJean-Francois Remy 	struct neigh_parms *p = ctl->extra2;
29394bf6980dSJean-Francois Remy 	int ret;
29404bf6980dSJean-Francois Remy 
29414bf6980dSJean-Francois Remy 	if (strcmp(ctl->procname, "base_reachable_time") == 0)
29424bf6980dSJean-Francois Remy 		ret = neigh_proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
29434bf6980dSJean-Francois Remy 	else if (strcmp(ctl->procname, "base_reachable_time_ms") == 0)
29444bf6980dSJean-Francois Remy 		ret = neigh_proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
29454bf6980dSJean-Francois Remy 	else
29464bf6980dSJean-Francois Remy 		ret = -1;
29474bf6980dSJean-Francois Remy 
29484bf6980dSJean-Francois Remy 	if (write && ret == 0) {
29494bf6980dSJean-Francois Remy 		/* update reachable_time as well, otherwise, the change will
29504bf6980dSJean-Francois Remy 		 * only be effective after the next time neigh_periodic_work
29514bf6980dSJean-Francois Remy 		 * decides to recompute it
29524bf6980dSJean-Francois Remy 		 */
29534bf6980dSJean-Francois Remy 		p->reachable_time =
29544bf6980dSJean-Francois Remy 			neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
29554bf6980dSJean-Francois Remy 	}
29564bf6980dSJean-Francois Remy 	return ret;
29574bf6980dSJean-Francois Remy }
29584bf6980dSJean-Francois Remy 
29591f9248e5SJiri Pirko #define NEIGH_PARMS_DATA_OFFSET(index)	\
29601f9248e5SJiri Pirko 	(&((struct neigh_parms *) 0)->data[index])
29611f9248e5SJiri Pirko 
29621f9248e5SJiri Pirko #define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \
29631f9248e5SJiri Pirko 	[NEIGH_VAR_ ## attr] = { \
29641f9248e5SJiri Pirko 		.procname	= name, \
29651f9248e5SJiri Pirko 		.data		= NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \
29661f9248e5SJiri Pirko 		.maxlen		= sizeof(int), \
29671f9248e5SJiri Pirko 		.mode		= mval, \
29681f9248e5SJiri Pirko 		.proc_handler	= proc, \
29691f9248e5SJiri Pirko 	}
29701f9248e5SJiri Pirko 
29711f9248e5SJiri Pirko #define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \
29721f9248e5SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax)
29731f9248e5SJiri Pirko 
29741f9248e5SJiri Pirko #define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \
2975cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies)
29761f9248e5SJiri Pirko 
29771f9248e5SJiri Pirko #define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
2978cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)
29791f9248e5SJiri Pirko 
29801f9248e5SJiri Pirko #define NEIGH_SYSCTL_MS_JIFFIES_ENTRY(attr, name) \
2981cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
29821f9248e5SJiri Pirko 
29831f9248e5SJiri Pirko #define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \
2984cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
29851f9248e5SJiri Pirko 
29861f9248e5SJiri Pirko #define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \
2987cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_unres_qlen)
298854716e3bSEric W. Biederman 
29891da177e4SLinus Torvalds static struct neigh_sysctl_table {
29901da177e4SLinus Torvalds 	struct ctl_table_header *sysctl_header;
29918b5c171bSEric Dumazet 	struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
2992ab32ea5dSBrian Haley } neigh_sysctl_template __read_mostly = {
29931da177e4SLinus Torvalds 	.neigh_vars = {
29941f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"),
29951f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"),
29961f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"),
29971f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),
29981f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),
29991f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"),
30001f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"),
30011f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"),
30021f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"),
30031f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"),
30041f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"),
30051f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"),
30061f9248e5SJiri Pirko 		NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"),
30071f9248e5SJiri Pirko 		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"),
30081f9248e5SJiri Pirko 		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"),
30098b5c171bSEric Dumazet 		[NEIGH_VAR_GC_INTERVAL] = {
30101da177e4SLinus Torvalds 			.procname	= "gc_interval",
30111da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
30121da177e4SLinus Torvalds 			.mode		= 0644,
30136d9f239aSAlexey Dobriyan 			.proc_handler	= proc_dointvec_jiffies,
30141da177e4SLinus Torvalds 		},
30158b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH1] = {
30161da177e4SLinus Torvalds 			.procname	= "gc_thresh1",
30171da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
30181da177e4SLinus Torvalds 			.mode		= 0644,
3019555445cdSFrancesco Fusco 			.extra1 	= &zero,
3020555445cdSFrancesco Fusco 			.extra2		= &int_max,
3021555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
30221da177e4SLinus Torvalds 		},
30238b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH2] = {
30241da177e4SLinus Torvalds 			.procname	= "gc_thresh2",
30251da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
30261da177e4SLinus Torvalds 			.mode		= 0644,
3027555445cdSFrancesco Fusco 			.extra1 	= &zero,
3028555445cdSFrancesco Fusco 			.extra2		= &int_max,
3029555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
30301da177e4SLinus Torvalds 		},
30318b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH3] = {
30321da177e4SLinus Torvalds 			.procname	= "gc_thresh3",
30331da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
30341da177e4SLinus Torvalds 			.mode		= 0644,
3035555445cdSFrancesco Fusco 			.extra1 	= &zero,
3036555445cdSFrancesco Fusco 			.extra2		= &int_max,
3037555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
30381da177e4SLinus Torvalds 		},
3039c3bac5a7SPavel Emelyanov 		{},
30401da177e4SLinus Torvalds 	},
30411da177e4SLinus Torvalds };
30421da177e4SLinus Torvalds 
30431da177e4SLinus Torvalds int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
304473af614aSJiri Pirko 			  proc_handler *handler)
30451da177e4SLinus Torvalds {
30461f9248e5SJiri Pirko 	int i;
30473c607bbbSPavel Emelyanov 	struct neigh_sysctl_table *t;
30481f9248e5SJiri Pirko 	const char *dev_name_source;
30498f40a1f9SEric W. Biederman 	char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
305073af614aSJiri Pirko 	char *p_name;
30511da177e4SLinus Torvalds 
30523c607bbbSPavel Emelyanov 	t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
30531da177e4SLinus Torvalds 	if (!t)
30543c607bbbSPavel Emelyanov 		goto err;
30553c607bbbSPavel Emelyanov 
3056b194c1f1SJiri Pirko 	for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
30571f9248e5SJiri Pirko 		t->neigh_vars[i].data += (long) p;
3058cb5b09c1SJiri Pirko 		t->neigh_vars[i].extra1 = dev;
30591d4c8c29SJiri Pirko 		t->neigh_vars[i].extra2 = p;
3060cb5b09c1SJiri Pirko 	}
30611da177e4SLinus Torvalds 
30621da177e4SLinus Torvalds 	if (dev) {
30631da177e4SLinus Torvalds 		dev_name_source = dev->name;
3064d12af679SEric W. Biederman 		/* Terminate the table early */
30658b5c171bSEric Dumazet 		memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
30668b5c171bSEric Dumazet 		       sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
30671da177e4SLinus Torvalds 	} else {
30689ecf07a1SMathias Krause 		struct neigh_table *tbl = p->tbl;
30698f40a1f9SEric W. Biederman 		dev_name_source = "default";
30709ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = &tbl->gc_interval;
30719ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = &tbl->gc_thresh1;
30729ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = &tbl->gc_thresh2;
30739ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = &tbl->gc_thresh3;
30741da177e4SLinus Torvalds 	}
30751da177e4SLinus Torvalds 
3076f8572d8fSEric W. Biederman 	if (handler) {
30771da177e4SLinus Torvalds 		/* RetransTime */
30788b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
30791da177e4SLinus Torvalds 		/* ReachableTime */
30808b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
30811da177e4SLinus Torvalds 		/* RetransTime (in milliseconds)*/
30828b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
30831da177e4SLinus Torvalds 		/* ReachableTime (in milliseconds) */
30848b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
30854bf6980dSJean-Francois Remy 	} else {
30864bf6980dSJean-Francois Remy 		/* Those handlers will update p->reachable_time after
30874bf6980dSJean-Francois Remy 		 * base_reachable_time(_ms) is set to ensure the new timer starts being
30884bf6980dSJean-Francois Remy 		 * applied after the next neighbour update instead of waiting for
30894bf6980dSJean-Francois Remy 		 * neigh_periodic_work to update its value (can be multiple minutes)
30904bf6980dSJean-Francois Remy 		 * So any handler that replaces them should do this as well
30914bf6980dSJean-Francois Remy 		 */
30924bf6980dSJean-Francois Remy 		/* ReachableTime */
30934bf6980dSJean-Francois Remy 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler =
30944bf6980dSJean-Francois Remy 			neigh_proc_base_reachable_time;
30954bf6980dSJean-Francois Remy 		/* ReachableTime (in milliseconds) */
30964bf6980dSJean-Francois Remy 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler =
30974bf6980dSJean-Francois Remy 			neigh_proc_base_reachable_time;
30981da177e4SLinus Torvalds 	}
30991da177e4SLinus Torvalds 
3100464dc801SEric W. Biederman 	/* Don't export sysctls to unprivileged users */
3101464dc801SEric W. Biederman 	if (neigh_parms_net(p)->user_ns != &init_user_ns)
3102464dc801SEric W. Biederman 		t->neigh_vars[0].procname = NULL;
3103464dc801SEric W. Biederman 
310473af614aSJiri Pirko 	switch (neigh_parms_family(p)) {
310573af614aSJiri Pirko 	case AF_INET:
310673af614aSJiri Pirko 	      p_name = "ipv4";
310773af614aSJiri Pirko 	      break;
310873af614aSJiri Pirko 	case AF_INET6:
310973af614aSJiri Pirko 	      p_name = "ipv6";
311073af614aSJiri Pirko 	      break;
311173af614aSJiri Pirko 	default:
311273af614aSJiri Pirko 	      BUG();
311373af614aSJiri Pirko 	}
311473af614aSJiri Pirko 
31158f40a1f9SEric W. Biederman 	snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
31168f40a1f9SEric W. Biederman 		p_name, dev_name_source);
31174ab438fcSDenis V. Lunev 	t->sysctl_header =
31188f40a1f9SEric W. Biederman 		register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
31193c607bbbSPavel Emelyanov 	if (!t->sysctl_header)
31208f40a1f9SEric W. Biederman 		goto free;
31213c607bbbSPavel Emelyanov 
31221da177e4SLinus Torvalds 	p->sysctl_table = t;
31231da177e4SLinus Torvalds 	return 0;
31241da177e4SLinus Torvalds 
31251da177e4SLinus Torvalds free:
31261da177e4SLinus Torvalds 	kfree(t);
31273c607bbbSPavel Emelyanov err:
31283c607bbbSPavel Emelyanov 	return -ENOBUFS;
31291da177e4SLinus Torvalds }
31300a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_sysctl_register);
31311da177e4SLinus Torvalds 
31321da177e4SLinus Torvalds void neigh_sysctl_unregister(struct neigh_parms *p)
31331da177e4SLinus Torvalds {
31341da177e4SLinus Torvalds 	if (p->sysctl_table) {
31351da177e4SLinus Torvalds 		struct neigh_sysctl_table *t = p->sysctl_table;
31361da177e4SLinus Torvalds 		p->sysctl_table = NULL;
31375dd3df10SEric W. Biederman 		unregister_net_sysctl_table(t->sysctl_header);
31381da177e4SLinus Torvalds 		kfree(t);
31391da177e4SLinus Torvalds 	}
31401da177e4SLinus Torvalds }
31410a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_sysctl_unregister);
31421da177e4SLinus Torvalds 
31431da177e4SLinus Torvalds #endif	/* CONFIG_SYSCTL */
31441da177e4SLinus Torvalds 
3145c8822a4eSThomas Graf static int __init neigh_init(void)
3146c8822a4eSThomas Graf {
3147c7ac8679SGreg Rose 	rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, NULL);
3148c7ac8679SGreg Rose 	rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, NULL);
3149c7ac8679SGreg Rose 	rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, NULL);
3150c8822a4eSThomas Graf 
3151c7ac8679SGreg Rose 	rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
3152c7ac8679SGreg Rose 		      NULL);
3153c7ac8679SGreg Rose 	rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, NULL);
3154c8822a4eSThomas Graf 
3155c8822a4eSThomas Graf 	return 0;
3156c8822a4eSThomas Graf }
3157c8822a4eSThomas Graf 
3158c8822a4eSThomas Graf subsys_initcall(neigh_init);
3159c8822a4eSThomas Graf 
3160