xref: /openbmc/linux/net/core/neighbour.c (revision b071af52)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *	Generic address resolution entity
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *	Authors:
61da177e4SLinus Torvalds  *	Pedro Roque		<roque@di.fc.ul.pt>
71da177e4SLinus Torvalds  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *	Fixes:
101da177e4SLinus Torvalds  *	Vitaly E. Lavrov	releasing NULL neighbor in neigh_add.
111da177e4SLinus Torvalds  *	Harald Welte		Add neighbour cache statistics like rtstat
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
14e005d193SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15e005d193SJoe Perches 
165a0e3ad6STejun Heo #include <linux/slab.h>
1785704cb8SKonstantin Khlebnikov #include <linux/kmemleak.h>
181da177e4SLinus Torvalds #include <linux/types.h>
191da177e4SLinus Torvalds #include <linux/kernel.h>
201da177e4SLinus Torvalds #include <linux/module.h>
211da177e4SLinus Torvalds #include <linux/socket.h>
221da177e4SLinus Torvalds #include <linux/netdevice.h>
231da177e4SLinus Torvalds #include <linux/proc_fs.h>
241da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL
251da177e4SLinus Torvalds #include <linux/sysctl.h>
261da177e4SLinus Torvalds #endif
271da177e4SLinus Torvalds #include <linux/times.h>
28457c4cbcSEric W. Biederman #include <net/net_namespace.h>
291da177e4SLinus Torvalds #include <net/neighbour.h>
304b2a2bfeSDavid Ahern #include <net/arp.h>
311da177e4SLinus Torvalds #include <net/dst.h>
321da177e4SLinus Torvalds #include <net/sock.h>
338d71740cSTom Tucker #include <net/netevent.h>
34a14a49d2SThomas Graf #include <net/netlink.h>
351da177e4SLinus Torvalds #include <linux/rtnetlink.h>
361da177e4SLinus Torvalds #include <linux/random.h>
37543537bdSPaulo Marques #include <linux/string.h>
38c3609d51Svignesh babu #include <linux/log2.h>
391d4c8c29SJiri Pirko #include <linux/inetdevice.h>
40bba24896SJiri Pirko #include <net/addrconf.h>
411da177e4SLinus Torvalds 
4256dd18a4SRoopa Prabhu #include <trace/events/neigh.h>
4356dd18a4SRoopa Prabhu 
441da177e4SLinus Torvalds #define NEIGH_DEBUG 1
45d5d427cdSJoe Perches #define neigh_dbg(level, fmt, ...)		\
46d5d427cdSJoe Perches do {						\
47d5d427cdSJoe Perches 	if (level <= NEIGH_DEBUG)		\
48d5d427cdSJoe Perches 		pr_debug(fmt, ##__VA_ARGS__);	\
49d5d427cdSJoe Perches } while (0)
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds #define PNEIGH_HASHMASK		0xF
521da177e4SLinus Torvalds 
53e99e88a9SKees Cook static void neigh_timer_handler(struct timer_list *t);
547b8f7a40SRoopa Prabhu static void __neigh_notify(struct neighbour *n, int type, int flags,
557b8f7a40SRoopa Prabhu 			   u32 pid);
567b8f7a40SRoopa Prabhu static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid);
5753b76cdfSWolfgang Bumiller static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
5853b76cdfSWolfgang Bumiller 				    struct net_device *dev);
591da177e4SLinus Torvalds 
6045fc3b11SAmos Waterland #ifdef CONFIG_PROC_FS
6171a5053aSChristoph Hellwig static const struct seq_operations neigh_stat_seq_ops;
6245fc3b11SAmos Waterland #endif
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds /*
651da177e4SLinus Torvalds    Neighbour hash table buckets are protected with rwlock tbl->lock.
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds    - All the scans/updates to hash buckets MUST be made under this lock.
681da177e4SLinus Torvalds    - NOTHING clever should be made under this lock: no callbacks
691da177e4SLinus Torvalds      to protocol backends, no attempts to send something to network.
701da177e4SLinus Torvalds      It will result in deadlocks, if backend/driver wants to use neighbour
711da177e4SLinus Torvalds      cache.
721da177e4SLinus Torvalds    - If the entry requires some non-trivial actions, increase
731da177e4SLinus Torvalds      its reference count and release table lock.
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds    Neighbour entries are protected:
761da177e4SLinus Torvalds    - with reference count.
771da177e4SLinus Torvalds    - with rwlock neigh->lock
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds    Reference count prevents destruction.
801da177e4SLinus Torvalds 
811da177e4SLinus Torvalds    neigh->lock mainly serializes ll address data and its validity state.
821da177e4SLinus Torvalds    However, the same lock is used to protect another entry fields:
831da177e4SLinus Torvalds     - timer
841da177e4SLinus Torvalds     - resolution queue
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds    Again, nothing clever shall be made under neigh->lock,
871da177e4SLinus Torvalds    the most complicated procedure, which we allow is dev->hard_header.
881da177e4SLinus Torvalds    It is supposed, that dev->hard_header is simplistic and does
891da177e4SLinus Torvalds    not make callbacks to neighbour tables.
901da177e4SLinus Torvalds  */
911da177e4SLinus Torvalds 
928f40b161SDavid S. Miller static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
931da177e4SLinus Torvalds {
941da177e4SLinus Torvalds 	kfree_skb(skb);
951da177e4SLinus Torvalds 	return -ENETDOWN;
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds 
984f494554SThomas Graf static void neigh_cleanup_and_release(struct neighbour *neigh)
994f494554SThomas Graf {
10056dd18a4SRoopa Prabhu 	trace_neigh_cleanup_and_release(neigh, 0);
1017b8f7a40SRoopa Prabhu 	__neigh_notify(neigh, RTM_DELNEIGH, 0, 0);
10253f800e3SIdo Schimmel 	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
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 {
1148032bf12SJason A. Donenfeld 	return base ? get_random_u32_below(base) + (base >> 1) : 0;
1151da177e4SLinus Torvalds }
1160a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_rand_reach_time);
1171da177e4SLinus Torvalds 
11858956317SDavid Ahern static void neigh_mark_dead(struct neighbour *n)
11958956317SDavid Ahern {
12058956317SDavid Ahern 	n->dead = 1;
12158956317SDavid Ahern 	if (!list_empty(&n->gc_list)) {
12258956317SDavid Ahern 		list_del_init(&n->gc_list);
12358956317SDavid Ahern 		atomic_dec(&n->tbl->gc_entries);
12458956317SDavid Ahern 	}
1257482e384SDaniel Borkmann 	if (!list_empty(&n->managed_list))
1267482e384SDaniel Borkmann 		list_del_init(&n->managed_list);
12758956317SDavid Ahern }
12858956317SDavid Ahern 
1299c29a2f5SDavid Ahern static void neigh_update_gc_list(struct neighbour *n)
13058956317SDavid Ahern {
131e997f8a2SDavid Ahern 	bool on_gc_list, exempt_from_gc;
13258956317SDavid Ahern 
1339c29a2f5SDavid Ahern 	write_lock_bh(&n->tbl->lock);
1349c29a2f5SDavid Ahern 	write_lock(&n->lock);
135eefb45eeSChinmay Agarwal 	if (n->dead)
136eefb45eeSChinmay Agarwal 		goto out;
137eefb45eeSChinmay Agarwal 
138e997f8a2SDavid Ahern 	/* remove from the gc list if new state is permanent or if neighbor
139e997f8a2SDavid Ahern 	 * is externally learned; otherwise entry should be on the gc list
14058956317SDavid Ahern 	 */
141e997f8a2SDavid Ahern 	exempt_from_gc = n->nud_state & NUD_PERMANENT ||
142e997f8a2SDavid Ahern 			 n->flags & NTF_EXT_LEARNED;
1439c29a2f5SDavid Ahern 	on_gc_list = !list_empty(&n->gc_list);
1448cc196d6SDavid Ahern 
145e997f8a2SDavid Ahern 	if (exempt_from_gc && on_gc_list) {
1469c29a2f5SDavid Ahern 		list_del_init(&n->gc_list);
14758956317SDavid Ahern 		atomic_dec(&n->tbl->gc_entries);
148e997f8a2SDavid Ahern 	} else if (!exempt_from_gc && !on_gc_list) {
14958956317SDavid Ahern 		/* add entries to the tail; cleaning removes from the front */
15058956317SDavid Ahern 		list_add_tail(&n->gc_list, &n->tbl->gc_list);
15158956317SDavid Ahern 		atomic_inc(&n->tbl->gc_entries);
15258956317SDavid Ahern 	}
153eefb45eeSChinmay Agarwal out:
1549c29a2f5SDavid Ahern 	write_unlock(&n->lock);
1559c29a2f5SDavid Ahern 	write_unlock_bh(&n->tbl->lock);
15658956317SDavid Ahern }
1571da177e4SLinus Torvalds 
1587482e384SDaniel Borkmann static void neigh_update_managed_list(struct neighbour *n)
159526f1b58SDavid Ahern {
1607482e384SDaniel Borkmann 	bool on_managed_list, add_to_managed;
1617482e384SDaniel Borkmann 
1627482e384SDaniel Borkmann 	write_lock_bh(&n->tbl->lock);
1637482e384SDaniel Borkmann 	write_lock(&n->lock);
1647482e384SDaniel Borkmann 	if (n->dead)
1657482e384SDaniel Borkmann 		goto out;
1667482e384SDaniel Borkmann 
1677482e384SDaniel Borkmann 	add_to_managed = n->flags & NTF_MANAGED;
1687482e384SDaniel Borkmann 	on_managed_list = !list_empty(&n->managed_list);
1697482e384SDaniel Borkmann 
1707482e384SDaniel Borkmann 	if (!add_to_managed && on_managed_list)
1717482e384SDaniel Borkmann 		list_del_init(&n->managed_list);
1727482e384SDaniel Borkmann 	else if (add_to_managed && !on_managed_list)
1737482e384SDaniel Borkmann 		list_add_tail(&n->managed_list, &n->tbl->managed_list);
1747482e384SDaniel Borkmann out:
1757482e384SDaniel Borkmann 	write_unlock(&n->lock);
1767482e384SDaniel Borkmann 	write_unlock_bh(&n->tbl->lock);
1777482e384SDaniel Borkmann }
1787482e384SDaniel Borkmann 
1797482e384SDaniel Borkmann static void neigh_update_flags(struct neighbour *neigh, u32 flags, int *notify,
1807482e384SDaniel Borkmann 			       bool *gc_update, bool *managed_update)
1817482e384SDaniel Borkmann {
1827482e384SDaniel Borkmann 	u32 ndm_flags, old_flags = neigh->flags;
183526f1b58SDavid Ahern 
184526f1b58SDavid Ahern 	if (!(flags & NEIGH_UPDATE_F_ADMIN))
1857482e384SDaniel Borkmann 		return;
186526f1b58SDavid Ahern 
187526f1b58SDavid Ahern 	ndm_flags  = (flags & NEIGH_UPDATE_F_EXT_LEARNED) ? NTF_EXT_LEARNED : 0;
1887482e384SDaniel Borkmann 	ndm_flags |= (flags & NEIGH_UPDATE_F_MANAGED) ? NTF_MANAGED : 0;
1897482e384SDaniel Borkmann 
1907482e384SDaniel Borkmann 	if ((old_flags ^ ndm_flags) & NTF_EXT_LEARNED) {
191526f1b58SDavid Ahern 		if (ndm_flags & NTF_EXT_LEARNED)
192526f1b58SDavid Ahern 			neigh->flags |= NTF_EXT_LEARNED;
193526f1b58SDavid Ahern 		else
194526f1b58SDavid Ahern 			neigh->flags &= ~NTF_EXT_LEARNED;
195526f1b58SDavid Ahern 		*notify = 1;
1967482e384SDaniel Borkmann 		*gc_update = true;
197526f1b58SDavid Ahern 	}
1987482e384SDaniel Borkmann 	if ((old_flags ^ ndm_flags) & NTF_MANAGED) {
1997482e384SDaniel Borkmann 		if (ndm_flags & NTF_MANAGED)
2007482e384SDaniel Borkmann 			neigh->flags |= NTF_MANAGED;
2017482e384SDaniel Borkmann 		else
2027482e384SDaniel Borkmann 			neigh->flags &= ~NTF_MANAGED;
2037482e384SDaniel Borkmann 		*notify = 1;
2047482e384SDaniel Borkmann 		*managed_update = true;
2057482e384SDaniel Borkmann 	}
206526f1b58SDavid Ahern }
207526f1b58SDavid Ahern 
2087e6f182bSDavid Ahern static bool neigh_del(struct neighbour *n, struct neighbour __rcu **np,
2097e6f182bSDavid Ahern 		      struct neigh_table *tbl)
2105071034eSSowmini Varadhan {
2115071034eSSowmini Varadhan 	bool retval = false;
2125071034eSSowmini Varadhan 
2135071034eSSowmini Varadhan 	write_lock(&n->lock);
2147e6f182bSDavid Ahern 	if (refcount_read(&n->refcnt) == 1) {
2155071034eSSowmini Varadhan 		struct neighbour *neigh;
2165071034eSSowmini Varadhan 
2175071034eSSowmini Varadhan 		neigh = rcu_dereference_protected(n->next,
2185071034eSSowmini Varadhan 						  lockdep_is_held(&tbl->lock));
2195071034eSSowmini Varadhan 		rcu_assign_pointer(*np, neigh);
22058956317SDavid Ahern 		neigh_mark_dead(n);
2215071034eSSowmini Varadhan 		retval = true;
2225071034eSSowmini Varadhan 	}
2235071034eSSowmini Varadhan 	write_unlock(&n->lock);
2245071034eSSowmini Varadhan 	if (retval)
2255071034eSSowmini Varadhan 		neigh_cleanup_and_release(n);
2265071034eSSowmini Varadhan 	return retval;
2275071034eSSowmini Varadhan }
2285071034eSSowmini Varadhan 
2295071034eSSowmini Varadhan bool neigh_remove_one(struct neighbour *ndel, struct neigh_table *tbl)
2305071034eSSowmini Varadhan {
2315071034eSSowmini Varadhan 	struct neigh_hash_table *nht;
2325071034eSSowmini Varadhan 	void *pkey = ndel->primary_key;
2335071034eSSowmini Varadhan 	u32 hash_val;
2345071034eSSowmini Varadhan 	struct neighbour *n;
2355071034eSSowmini Varadhan 	struct neighbour __rcu **np;
2365071034eSSowmini Varadhan 
2375071034eSSowmini Varadhan 	nht = rcu_dereference_protected(tbl->nht,
2385071034eSSowmini Varadhan 					lockdep_is_held(&tbl->lock));
2395071034eSSowmini Varadhan 	hash_val = tbl->hash(pkey, ndel->dev, nht->hash_rnd);
2405071034eSSowmini Varadhan 	hash_val = hash_val >> (32 - nht->hash_shift);
2415071034eSSowmini Varadhan 
2425071034eSSowmini Varadhan 	np = &nht->hash_buckets[hash_val];
2435071034eSSowmini Varadhan 	while ((n = rcu_dereference_protected(*np,
2445071034eSSowmini Varadhan 					      lockdep_is_held(&tbl->lock)))) {
2455071034eSSowmini Varadhan 		if (n == ndel)
2467e6f182bSDavid Ahern 			return neigh_del(n, np, tbl);
2475071034eSSowmini Varadhan 		np = &n->next;
2485071034eSSowmini Varadhan 	}
2495071034eSSowmini Varadhan 	return false;
2505071034eSSowmini Varadhan }
2515071034eSSowmini Varadhan 
2521da177e4SLinus Torvalds static int neigh_forced_gc(struct neigh_table *tbl)
2531da177e4SLinus Torvalds {
25458956317SDavid Ahern 	int max_clean = atomic_read(&tbl->gc_entries) - tbl->gc_thresh2;
25558956317SDavid Ahern 	unsigned long tref = jiffies - 5 * HZ;
25658956317SDavid Ahern 	struct neighbour *n, *tmp;
2571da177e4SLinus Torvalds 	int shrunk = 0;
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
2601da177e4SLinus Torvalds 
2611da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
2621da177e4SLinus Torvalds 
26358956317SDavid Ahern 	list_for_each_entry_safe(n, tmp, &tbl->gc_list, gc_list) {
26458956317SDavid Ahern 		if (refcount_read(&n->refcnt) == 1) {
26558956317SDavid Ahern 			bool remove = false;
26658956317SDavid Ahern 
26758956317SDavid Ahern 			write_lock(&n->lock);
268758a7f0bSDavid Ahern 			if ((n->nud_state == NUD_FAILED) ||
2697a6b1ab7SDavid Ahern 			    (n->nud_state == NUD_NOARP) ||
2708cf8821eSJeff Dike 			    (tbl->is_multicast &&
2718cf8821eSJeff Dike 			     tbl->is_multicast(n->primary_key)) ||
272c1d2ecdfSJulian Anastasov 			    !time_in_range(n->updated, tref, jiffies))
27358956317SDavid Ahern 				remove = true;
27458956317SDavid Ahern 			write_unlock(&n->lock);
27558956317SDavid Ahern 
27658956317SDavid Ahern 			if (remove && neigh_remove_one(n, tbl))
27758956317SDavid Ahern 				shrunk++;
27858956317SDavid Ahern 			if (shrunk >= max_clean)
27958956317SDavid Ahern 				break;
2801da177e4SLinus Torvalds 		}
2811da177e4SLinus Torvalds 	}
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds 	tbl->last_flush = jiffies;
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 	return shrunk;
2881da177e4SLinus Torvalds }
2891da177e4SLinus Torvalds 
290a43d8994SPavel Emelyanov static void neigh_add_timer(struct neighbour *n, unsigned long when)
291a43d8994SPavel Emelyanov {
292c1d2ecdfSJulian Anastasov 	/* Use safe distance from the jiffies - LONG_MAX point while timer
293c1d2ecdfSJulian Anastasov 	 * is running in DELAY/PROBE state but still show to user space
294c1d2ecdfSJulian Anastasov 	 * large times in the past.
295c1d2ecdfSJulian Anastasov 	 */
296c1d2ecdfSJulian Anastasov 	unsigned long mint = jiffies - (LONG_MAX - 86400 * HZ);
297c1d2ecdfSJulian Anastasov 
298a43d8994SPavel Emelyanov 	neigh_hold(n);
299c1d2ecdfSJulian Anastasov 	if (!time_in_range(n->confirmed, mint, jiffies))
300c1d2ecdfSJulian Anastasov 		n->confirmed = mint;
301c1d2ecdfSJulian Anastasov 	if (time_before(n->used, n->confirmed))
302c1d2ecdfSJulian Anastasov 		n->used = n->confirmed;
303a43d8994SPavel Emelyanov 	if (unlikely(mod_timer(&n->timer, when))) {
304a43d8994SPavel Emelyanov 		printk("NEIGH: BUG, double timer add, state is %x\n",
305a43d8994SPavel Emelyanov 		       n->nud_state);
306a43d8994SPavel Emelyanov 		dump_stack();
307a43d8994SPavel Emelyanov 	}
308a43d8994SPavel Emelyanov }
309a43d8994SPavel Emelyanov 
3101da177e4SLinus Torvalds static int neigh_del_timer(struct neighbour *n)
3111da177e4SLinus Torvalds {
3121da177e4SLinus Torvalds 	if ((n->nud_state & NUD_IN_TIMER) &&
3131da177e4SLinus Torvalds 	    del_timer(&n->timer)) {
3141da177e4SLinus Torvalds 		neigh_release(n);
3151da177e4SLinus Torvalds 		return 1;
3161da177e4SLinus Torvalds 	}
3171da177e4SLinus Torvalds 	return 0;
3181da177e4SLinus Torvalds }
3191da177e4SLinus Torvalds 
3208207f253SThomas Zeitlhofer static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
3218207f253SThomas Zeitlhofer 						   int family)
3228207f253SThomas Zeitlhofer {
3238207f253SThomas Zeitlhofer 	switch (family) {
3248207f253SThomas Zeitlhofer 	case AF_INET:
3258207f253SThomas Zeitlhofer 		return __in_dev_arp_parms_get_rcu(dev);
3268207f253SThomas Zeitlhofer 	case AF_INET6:
3278207f253SThomas Zeitlhofer 		return __in6_dev_nd_parms_get_rcu(dev);
3288207f253SThomas Zeitlhofer 	}
3298207f253SThomas Zeitlhofer 	return NULL;
3308207f253SThomas Zeitlhofer }
3318207f253SThomas Zeitlhofer 
3328207f253SThomas Zeitlhofer static void neigh_parms_qlen_dec(struct net_device *dev, int family)
3338207f253SThomas Zeitlhofer {
3348207f253SThomas Zeitlhofer 	struct neigh_parms *p;
3358207f253SThomas Zeitlhofer 
3368207f253SThomas Zeitlhofer 	rcu_read_lock();
3378207f253SThomas Zeitlhofer 	p = neigh_get_dev_parms_rcu(dev, family);
3388207f253SThomas Zeitlhofer 	if (p)
3398207f253SThomas Zeitlhofer 		p->qlen--;
3408207f253SThomas Zeitlhofer 	rcu_read_unlock();
3418207f253SThomas Zeitlhofer }
3428207f253SThomas Zeitlhofer 
3438207f253SThomas Zeitlhofer static void pneigh_queue_purge(struct sk_buff_head *list, struct net *net,
3448207f253SThomas Zeitlhofer 			       int family)
3451da177e4SLinus Torvalds {
346d5485d9dSYang Yingliang 	struct sk_buff_head tmp;
34766ba215cSDenis V. Lunev 	unsigned long flags;
3481da177e4SLinus Torvalds 	struct sk_buff *skb;
3491da177e4SLinus Torvalds 
350d5485d9dSYang Yingliang 	skb_queue_head_init(&tmp);
35166ba215cSDenis V. Lunev 	spin_lock_irqsave(&list->lock, flags);
35266ba215cSDenis V. Lunev 	skb = skb_peek(list);
35366ba215cSDenis V. Lunev 	while (skb != NULL) {
35466ba215cSDenis V. Lunev 		struct sk_buff *skb_next = skb_peek_next(skb, list);
3550ff4eb3dSAlexander Mikhalitsyn 		struct net_device *dev = skb->dev;
356d5485d9dSYang Yingliang 
3570ff4eb3dSAlexander Mikhalitsyn 		if (net == NULL || net_eq(dev_net(dev), net)) {
3588207f253SThomas Zeitlhofer 			neigh_parms_qlen_dec(dev, family);
35966ba215cSDenis V. Lunev 			__skb_unlink(skb, list);
360d5485d9dSYang Yingliang 			__skb_queue_tail(&tmp, skb);
3611da177e4SLinus Torvalds 		}
36266ba215cSDenis V. Lunev 		skb = skb_next;
36366ba215cSDenis V. Lunev 	}
36466ba215cSDenis V. Lunev 	spin_unlock_irqrestore(&list->lock, flags);
365d5485d9dSYang Yingliang 
366d5485d9dSYang Yingliang 	while ((skb = __skb_dequeue(&tmp))) {
367d5485d9dSYang Yingliang 		dev_put(skb->dev);
368d5485d9dSYang Yingliang 		kfree_skb(skb);
369d5485d9dSYang Yingliang 	}
3701da177e4SLinus Torvalds }
3711da177e4SLinus Torvalds 
372859bd2efSDavid Ahern static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev,
373859bd2efSDavid Ahern 			    bool skip_perm)
3741da177e4SLinus Torvalds {
3751da177e4SLinus Torvalds 	int i;
376d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
3771da177e4SLinus Torvalds 
378d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
379d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
380d6bf7817SEric Dumazet 
381cd089336SDavid S. Miller 	for (i = 0; i < (1 << nht->hash_shift); i++) {
382767e97e1SEric Dumazet 		struct neighbour *n;
383767e97e1SEric Dumazet 		struct neighbour __rcu **np = &nht->hash_buckets[i];
3841da177e4SLinus Torvalds 
385767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
386767e97e1SEric Dumazet 					lockdep_is_held(&tbl->lock))) != NULL) {
3871da177e4SLinus Torvalds 			if (dev && n->dev != dev) {
3881da177e4SLinus Torvalds 				np = &n->next;
3891da177e4SLinus Torvalds 				continue;
3901da177e4SLinus Torvalds 			}
391859bd2efSDavid Ahern 			if (skip_perm && n->nud_state & NUD_PERMANENT) {
392859bd2efSDavid Ahern 				np = &n->next;
393859bd2efSDavid Ahern 				continue;
394859bd2efSDavid Ahern 			}
395767e97e1SEric Dumazet 			rcu_assign_pointer(*np,
396767e97e1SEric Dumazet 				   rcu_dereference_protected(n->next,
397767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
3981da177e4SLinus Torvalds 			write_lock(&n->lock);
3991da177e4SLinus Torvalds 			neigh_del_timer(n);
40058956317SDavid Ahern 			neigh_mark_dead(n);
4019f237430SReshetova, Elena 			if (refcount_read(&n->refcnt) != 1) {
4021da177e4SLinus Torvalds 				/* The most unpleasant situation.
4031da177e4SLinus Torvalds 				   We must destroy neighbour entry,
4041da177e4SLinus Torvalds 				   but someone still uses it.
4051da177e4SLinus Torvalds 
4061da177e4SLinus Torvalds 				   The destroy will be delayed until
4071da177e4SLinus Torvalds 				   the last user releases us, but
4081da177e4SLinus Torvalds 				   we must kill timers etc. and move
4091da177e4SLinus Torvalds 				   it to safe state.
4101da177e4SLinus Torvalds 				 */
411c9ab4d85SEric Dumazet 				__skb_queue_purge(&n->arp_queue);
4128b5c171bSEric Dumazet 				n->arp_queue_len_bytes = 0;
4131da177e4SLinus Torvalds 				n->output = neigh_blackhole;
4141da177e4SLinus Torvalds 				if (n->nud_state & NUD_VALID)
4151da177e4SLinus Torvalds 					n->nud_state = NUD_NOARP;
4161da177e4SLinus Torvalds 				else
4171da177e4SLinus Torvalds 					n->nud_state = NUD_NONE;
418d5d427cdSJoe Perches 				neigh_dbg(2, "neigh %p is stray\n", n);
4191da177e4SLinus Torvalds 			}
4201da177e4SLinus Torvalds 			write_unlock(&n->lock);
4214f494554SThomas Graf 			neigh_cleanup_and_release(n);
4221da177e4SLinus Torvalds 		}
4231da177e4SLinus Torvalds 	}
42449636bb1SHerbert Xu }
4251da177e4SLinus Torvalds 
42649636bb1SHerbert Xu void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
42749636bb1SHerbert Xu {
42849636bb1SHerbert Xu 	write_lock_bh(&tbl->lock);
429859bd2efSDavid Ahern 	neigh_flush_dev(tbl, dev, false);
43049636bb1SHerbert Xu 	write_unlock_bh(&tbl->lock);
43149636bb1SHerbert Xu }
4320a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_changeaddr);
43349636bb1SHerbert Xu 
434859bd2efSDavid Ahern static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
435859bd2efSDavid Ahern 			  bool skip_perm)
43649636bb1SHerbert Xu {
43749636bb1SHerbert Xu 	write_lock_bh(&tbl->lock);
438859bd2efSDavid Ahern 	neigh_flush_dev(tbl, dev, skip_perm);
43953b76cdfSWolfgang Bumiller 	pneigh_ifdown_and_unlock(tbl, dev);
4408207f253SThomas Zeitlhofer 	pneigh_queue_purge(&tbl->proxy_queue, dev ? dev_net(dev) : NULL,
4418207f253SThomas Zeitlhofer 			   tbl->family);
44266ba215cSDenis V. Lunev 	if (skb_queue_empty_lockless(&tbl->proxy_queue))
4431da177e4SLinus Torvalds 		del_timer_sync(&tbl->proxy_timer);
4441da177e4SLinus Torvalds 	return 0;
4451da177e4SLinus Torvalds }
446859bd2efSDavid Ahern 
447859bd2efSDavid Ahern int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev)
448859bd2efSDavid Ahern {
449859bd2efSDavid Ahern 	__neigh_ifdown(tbl, dev, true);
450859bd2efSDavid Ahern 	return 0;
451859bd2efSDavid Ahern }
452859bd2efSDavid Ahern EXPORT_SYMBOL(neigh_carrier_down);
453859bd2efSDavid Ahern 
454859bd2efSDavid Ahern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
455859bd2efSDavid Ahern {
456859bd2efSDavid Ahern 	__neigh_ifdown(tbl, dev, false);
457859bd2efSDavid Ahern 	return 0;
458859bd2efSDavid Ahern }
4590a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_ifdown);
4601da177e4SLinus Torvalds 
46158956317SDavid Ahern static struct neighbour *neigh_alloc(struct neigh_table *tbl,
46258956317SDavid Ahern 				     struct net_device *dev,
4632c611ad9SRoopa Prabhu 				     u32 flags, bool exempt_from_gc)
4641da177e4SLinus Torvalds {
4651da177e4SLinus Torvalds 	struct neighbour *n = NULL;
4661da177e4SLinus Torvalds 	unsigned long now = jiffies;
4671da177e4SLinus Torvalds 	int entries;
4681da177e4SLinus Torvalds 
469e997f8a2SDavid Ahern 	if (exempt_from_gc)
47058956317SDavid Ahern 		goto do_alloc;
47158956317SDavid Ahern 
47258956317SDavid Ahern 	entries = atomic_inc_return(&tbl->gc_entries) - 1;
4731da177e4SLinus Torvalds 	if (entries >= tbl->gc_thresh3 ||
4741da177e4SLinus Torvalds 	    (entries >= tbl->gc_thresh2 &&
4751da177e4SLinus Torvalds 	     time_after(now, tbl->last_flush + 5 * HZ))) {
4761da177e4SLinus Torvalds 		if (!neigh_forced_gc(tbl) &&
477fb811395SRick Jones 		    entries >= tbl->gc_thresh3) {
478fb811395SRick Jones 			net_info_ratelimited("%s: neighbor table overflow!\n",
479fb811395SRick Jones 					     tbl->id);
480fb811395SRick Jones 			NEIGH_CACHE_STAT_INC(tbl, table_fulls);
4811da177e4SLinus Torvalds 			goto out_entries;
4821da177e4SLinus Torvalds 		}
483fb811395SRick Jones 	}
4841da177e4SLinus Torvalds 
48558956317SDavid Ahern do_alloc:
48608433effSYOSHIFUJI Hideaki / 吉藤英明 	n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
4871da177e4SLinus Torvalds 	if (!n)
4881da177e4SLinus Torvalds 		goto out_entries;
4891da177e4SLinus Torvalds 
490c9ab4d85SEric Dumazet 	__skb_queue_head_init(&n->arp_queue);
4911da177e4SLinus Torvalds 	rwlock_init(&n->lock);
4920ed8ddf4SEric Dumazet 	seqlock_init(&n->ha_lock);
4931da177e4SLinus Torvalds 	n->updated	  = n->used = now;
4941da177e4SLinus Torvalds 	n->nud_state	  = NUD_NONE;
4951da177e4SLinus Torvalds 	n->output	  = neigh_blackhole;
496e4400bbfSDaniel Borkmann 	n->flags	  = flags;
497f6b72b62SDavid S. Miller 	seqlock_init(&n->hh.hh_lock);
4981da177e4SLinus Torvalds 	n->parms	  = neigh_parms_clone(&tbl->parms);
499e99e88a9SKees Cook 	timer_setup(&n->timer, neigh_timer_handler, 0);
5001da177e4SLinus Torvalds 
5011da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, allocs);
5021da177e4SLinus Torvalds 	n->tbl		  = tbl;
5039f237430SReshetova, Elena 	refcount_set(&n->refcnt, 1);
5041da177e4SLinus Torvalds 	n->dead		  = 1;
50558956317SDavid Ahern 	INIT_LIST_HEAD(&n->gc_list);
5067482e384SDaniel Borkmann 	INIT_LIST_HEAD(&n->managed_list);
50758956317SDavid Ahern 
50858956317SDavid Ahern 	atomic_inc(&tbl->entries);
5091da177e4SLinus Torvalds out:
5101da177e4SLinus Torvalds 	return n;
5111da177e4SLinus Torvalds 
5121da177e4SLinus Torvalds out_entries:
513e997f8a2SDavid Ahern 	if (!exempt_from_gc)
51458956317SDavid Ahern 		atomic_dec(&tbl->gc_entries);
5151da177e4SLinus Torvalds 	goto out;
5161da177e4SLinus Torvalds }
5171da177e4SLinus Torvalds 
5182c2aba6cSDavid S. Miller static void neigh_get_hash_rnd(u32 *x)
5192c2aba6cSDavid S. Miller {
520b3d0f789SJason A. Donenfeld 	*x = get_random_u32() | 1;
5212c2aba6cSDavid S. Miller }
5222c2aba6cSDavid S. Miller 
523cd089336SDavid S. Miller static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
5241da177e4SLinus Torvalds {
525cd089336SDavid S. Miller 	size_t size = (1 << shift) * sizeof(struct neighbour *);
526d6bf7817SEric Dumazet 	struct neigh_hash_table *ret;
5276193d2beSEric Dumazet 	struct neighbour __rcu **buckets;
5282c2aba6cSDavid S. Miller 	int i;
5291da177e4SLinus Torvalds 
530d6bf7817SEric Dumazet 	ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
531d6bf7817SEric Dumazet 	if (!ret)
532d6bf7817SEric Dumazet 		return NULL;
53385704cb8SKonstantin Khlebnikov 	if (size <= PAGE_SIZE) {
534d6bf7817SEric Dumazet 		buckets = kzalloc(size, GFP_ATOMIC);
53585704cb8SKonstantin Khlebnikov 	} else {
5366193d2beSEric Dumazet 		buckets = (struct neighbour __rcu **)
537d6bf7817SEric Dumazet 			  __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
538d6bf7817SEric Dumazet 					   get_order(size));
53901b833abSKonstantin Khlebnikov 		kmemleak_alloc(buckets, size, 1, GFP_ATOMIC);
54085704cb8SKonstantin Khlebnikov 	}
541d6bf7817SEric Dumazet 	if (!buckets) {
542d6bf7817SEric Dumazet 		kfree(ret);
543d6bf7817SEric Dumazet 		return NULL;
5441da177e4SLinus Torvalds 	}
5456193d2beSEric Dumazet 	ret->hash_buckets = buckets;
546cd089336SDavid S. Miller 	ret->hash_shift = shift;
5472c2aba6cSDavid S. Miller 	for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
5482c2aba6cSDavid S. Miller 		neigh_get_hash_rnd(&ret->hash_rnd[i]);
5491da177e4SLinus Torvalds 	return ret;
5501da177e4SLinus Torvalds }
5511da177e4SLinus Torvalds 
552d6bf7817SEric Dumazet static void neigh_hash_free_rcu(struct rcu_head *head)
5531da177e4SLinus Torvalds {
554d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = container_of(head,
555d6bf7817SEric Dumazet 						    struct neigh_hash_table,
556d6bf7817SEric Dumazet 						    rcu);
557cd089336SDavid S. Miller 	size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
5586193d2beSEric Dumazet 	struct neighbour __rcu **buckets = nht->hash_buckets;
5591da177e4SLinus Torvalds 
56085704cb8SKonstantin Khlebnikov 	if (size <= PAGE_SIZE) {
561d6bf7817SEric Dumazet 		kfree(buckets);
56285704cb8SKonstantin Khlebnikov 	} else {
56385704cb8SKonstantin Khlebnikov 		kmemleak_free(buckets);
564d6bf7817SEric Dumazet 		free_pages((unsigned long)buckets, get_order(size));
56585704cb8SKonstantin Khlebnikov 	}
566d6bf7817SEric Dumazet 	kfree(nht);
5671da177e4SLinus Torvalds }
5681da177e4SLinus Torvalds 
569d6bf7817SEric Dumazet static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
570cd089336SDavid S. Miller 						unsigned long new_shift)
5711da177e4SLinus Torvalds {
572d6bf7817SEric Dumazet 	unsigned int i, hash;
573d6bf7817SEric Dumazet 	struct neigh_hash_table *new_nht, *old_nht;
5741da177e4SLinus Torvalds 
5751da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, hash_grows);
5761da177e4SLinus Torvalds 
577d6bf7817SEric Dumazet 	old_nht = rcu_dereference_protected(tbl->nht,
578d6bf7817SEric Dumazet 					    lockdep_is_held(&tbl->lock));
579cd089336SDavid S. Miller 	new_nht = neigh_hash_alloc(new_shift);
580d6bf7817SEric Dumazet 	if (!new_nht)
581d6bf7817SEric Dumazet 		return old_nht;
5821da177e4SLinus Torvalds 
583cd089336SDavid S. Miller 	for (i = 0; i < (1 << old_nht->hash_shift); i++) {
5841da177e4SLinus Torvalds 		struct neighbour *n, *next;
5851da177e4SLinus Torvalds 
586767e97e1SEric Dumazet 		for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
587767e97e1SEric Dumazet 						   lockdep_is_held(&tbl->lock));
588d6bf7817SEric Dumazet 		     n != NULL;
589d6bf7817SEric Dumazet 		     n = next) {
590d6bf7817SEric Dumazet 			hash = tbl->hash(n->primary_key, n->dev,
591d6bf7817SEric Dumazet 					 new_nht->hash_rnd);
5921da177e4SLinus Torvalds 
593cd089336SDavid S. Miller 			hash >>= (32 - new_nht->hash_shift);
594767e97e1SEric Dumazet 			next = rcu_dereference_protected(n->next,
595767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock));
5961da177e4SLinus Torvalds 
597767e97e1SEric Dumazet 			rcu_assign_pointer(n->next,
598767e97e1SEric Dumazet 					   rcu_dereference_protected(
599767e97e1SEric Dumazet 						new_nht->hash_buckets[hash],
600767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
601767e97e1SEric Dumazet 			rcu_assign_pointer(new_nht->hash_buckets[hash], n);
6021da177e4SLinus Torvalds 		}
6031da177e4SLinus Torvalds 	}
6041da177e4SLinus Torvalds 
605d6bf7817SEric Dumazet 	rcu_assign_pointer(tbl->nht, new_nht);
606d6bf7817SEric Dumazet 	call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
607d6bf7817SEric Dumazet 	return new_nht;
6081da177e4SLinus Torvalds }
6091da177e4SLinus Torvalds 
6101da177e4SLinus Torvalds struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
6111da177e4SLinus Torvalds 			       struct net_device *dev)
6121da177e4SLinus Torvalds {
6131da177e4SLinus Torvalds 	struct neighbour *n;
6141da177e4SLinus Torvalds 
6151da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, lookups);
6161da177e4SLinus Torvalds 
617d6bf7817SEric Dumazet 	rcu_read_lock_bh();
61860395a20SEric W. Biederman 	n = __neigh_lookup_noref(tbl, pkey, dev);
61960395a20SEric W. Biederman 	if (n) {
6209f237430SReshetova, Elena 		if (!refcount_inc_not_zero(&n->refcnt))
621767e97e1SEric Dumazet 			n = NULL;
6221da177e4SLinus Torvalds 		NEIGH_CACHE_STAT_INC(tbl, hits);
6231da177e4SLinus Torvalds 	}
624767e97e1SEric Dumazet 
625d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
6261da177e4SLinus Torvalds 	return n;
6271da177e4SLinus Torvalds }
6280a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_lookup);
6291da177e4SLinus Torvalds 
630e4400bbfSDaniel Borkmann static struct neighbour *
631e4400bbfSDaniel Borkmann ___neigh_create(struct neigh_table *tbl, const void *pkey,
6322c611ad9SRoopa Prabhu 		struct net_device *dev, u32 flags,
633e997f8a2SDavid Ahern 		bool exempt_from_gc, bool want_ref)
6341da177e4SLinus Torvalds {
635e4400bbfSDaniel Borkmann 	u32 hash_val, key_len = tbl->key_len;
636e4400bbfSDaniel Borkmann 	struct neighbour *n1, *rc, *n;
637d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
638e4400bbfSDaniel Borkmann 	int error;
6391da177e4SLinus Torvalds 
640e4400bbfSDaniel Borkmann 	n = neigh_alloc(tbl, dev, flags, exempt_from_gc);
641fc651001SDavid Ahern 	trace_neigh_create(tbl, dev, pkey, n, exempt_from_gc);
6421da177e4SLinus Torvalds 	if (!n) {
6431da177e4SLinus Torvalds 		rc = ERR_PTR(-ENOBUFS);
6441da177e4SLinus Torvalds 		goto out;
6451da177e4SLinus Torvalds 	}
6461da177e4SLinus Torvalds 
6471da177e4SLinus Torvalds 	memcpy(n->primary_key, pkey, key_len);
6481da177e4SLinus Torvalds 	n->dev = dev;
649d62607c3SJakub Kicinski 	netdev_hold(dev, &n->dev_tracker, GFP_ATOMIC);
6501da177e4SLinus Torvalds 
6511da177e4SLinus Torvalds 	/* Protocol specific setup. */
6521da177e4SLinus Torvalds 	if (tbl->constructor &&	(error = tbl->constructor(n)) < 0) {
6531da177e4SLinus Torvalds 		rc = ERR_PTR(error);
6541da177e4SLinus Torvalds 		goto out_neigh_release;
6551da177e4SLinus Torvalds 	}
6561da177e4SLinus Torvalds 
657da6a8fa0SDavid Miller 	if (dev->netdev_ops->ndo_neigh_construct) {
658503eebc2SJiri Pirko 		error = dev->netdev_ops->ndo_neigh_construct(dev, n);
659da6a8fa0SDavid Miller 		if (error < 0) {
660da6a8fa0SDavid Miller 			rc = ERR_PTR(error);
661da6a8fa0SDavid Miller 			goto out_neigh_release;
662da6a8fa0SDavid Miller 		}
663da6a8fa0SDavid Miller 	}
664da6a8fa0SDavid Miller 
665447f2191SDavid S. Miller 	/* Device specific setup. */
666447f2191SDavid S. Miller 	if (n->parms->neigh_setup &&
667447f2191SDavid S. Miller 	    (error = n->parms->neigh_setup(n)) < 0) {
668447f2191SDavid S. Miller 		rc = ERR_PTR(error);
669447f2191SDavid S. Miller 		goto out_neigh_release;
670447f2191SDavid S. Miller 	}
671447f2191SDavid S. Miller 
6721f9248e5SJiri Pirko 	n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1);
6731da177e4SLinus Torvalds 
6741da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
675d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
676d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
6771da177e4SLinus Torvalds 
678cd089336SDavid S. Miller 	if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
679cd089336SDavid S. Miller 		nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
6801da177e4SLinus Torvalds 
681096b9854SJim Westfall 	hash_val = tbl->hash(n->primary_key, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
6821da177e4SLinus Torvalds 
6831da177e4SLinus Torvalds 	if (n->parms->dead) {
6841da177e4SLinus Torvalds 		rc = ERR_PTR(-EINVAL);
6851da177e4SLinus Torvalds 		goto out_tbl_unlock;
6861da177e4SLinus Torvalds 	}
6871da177e4SLinus Torvalds 
688767e97e1SEric Dumazet 	for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
689767e97e1SEric Dumazet 					    lockdep_is_held(&tbl->lock));
690767e97e1SEric Dumazet 	     n1 != NULL;
691767e97e1SEric Dumazet 	     n1 = rcu_dereference_protected(n1->next,
692767e97e1SEric Dumazet 			lockdep_is_held(&tbl->lock))) {
693096b9854SJim Westfall 		if (dev == n1->dev && !memcmp(n1->primary_key, n->primary_key, key_len)) {
694a263b309SDavid S. Miller 			if (want_ref)
6951da177e4SLinus Torvalds 				neigh_hold(n1);
6961da177e4SLinus Torvalds 			rc = n1;
6971da177e4SLinus Torvalds 			goto out_tbl_unlock;
6981da177e4SLinus Torvalds 		}
6991da177e4SLinus Torvalds 	}
7001da177e4SLinus Torvalds 
7011da177e4SLinus Torvalds 	n->dead = 0;
702e997f8a2SDavid Ahern 	if (!exempt_from_gc)
7038cc196d6SDavid Ahern 		list_add_tail(&n->gc_list, &n->tbl->gc_list);
7047482e384SDaniel Borkmann 	if (n->flags & NTF_MANAGED)
7057482e384SDaniel Borkmann 		list_add_tail(&n->managed_list, &n->tbl->managed_list);
706a263b309SDavid S. Miller 	if (want_ref)
7071da177e4SLinus Torvalds 		neigh_hold(n);
708767e97e1SEric Dumazet 	rcu_assign_pointer(n->next,
709767e97e1SEric Dumazet 			   rcu_dereference_protected(nht->hash_buckets[hash_val],
710767e97e1SEric Dumazet 						     lockdep_is_held(&tbl->lock)));
711767e97e1SEric Dumazet 	rcu_assign_pointer(nht->hash_buckets[hash_val], n);
7121da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
713d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is created\n", n);
7141da177e4SLinus Torvalds 	rc = n;
7151da177e4SLinus Torvalds out:
7161da177e4SLinus Torvalds 	return rc;
7171da177e4SLinus Torvalds out_tbl_unlock:
7181da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
7191da177e4SLinus Torvalds out_neigh_release:
72064c6f4bbSDavid Ahern 	if (!exempt_from_gc)
72164c6f4bbSDavid Ahern 		atomic_dec(&tbl->gc_entries);
7221da177e4SLinus Torvalds 	neigh_release(n);
7231da177e4SLinus Torvalds 	goto out;
7241da177e4SLinus Torvalds }
72558956317SDavid Ahern 
72658956317SDavid Ahern struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
72758956317SDavid Ahern 				 struct net_device *dev, bool want_ref)
72858956317SDavid Ahern {
729e4400bbfSDaniel Borkmann 	return ___neigh_create(tbl, pkey, dev, 0, false, want_ref);
73058956317SDavid Ahern }
731a263b309SDavid S. Miller EXPORT_SYMBOL(__neigh_create);
7321da177e4SLinus Torvalds 
73301ccdf12SAlexey Dobriyan static u32 pneigh_hash(const void *pkey, unsigned int key_len)
734fa86d322SPavel Emelyanov {
735fa86d322SPavel Emelyanov 	u32 hash_val = *(u32 *)(pkey + key_len - 4);
736fa86d322SPavel Emelyanov 	hash_val ^= (hash_val >> 16);
737fa86d322SPavel Emelyanov 	hash_val ^= hash_val >> 8;
738fa86d322SPavel Emelyanov 	hash_val ^= hash_val >> 4;
739fa86d322SPavel Emelyanov 	hash_val &= PNEIGH_HASHMASK;
740be01d655SYOSHIFUJI Hideaki 	return hash_val;
741fa86d322SPavel Emelyanov }
742fa86d322SPavel Emelyanov 
743be01d655SYOSHIFUJI Hideaki static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
744be01d655SYOSHIFUJI Hideaki 					      struct net *net,
745be01d655SYOSHIFUJI Hideaki 					      const void *pkey,
74601ccdf12SAlexey Dobriyan 					      unsigned int key_len,
747be01d655SYOSHIFUJI Hideaki 					      struct net_device *dev)
748be01d655SYOSHIFUJI Hideaki {
749be01d655SYOSHIFUJI Hideaki 	while (n) {
750be01d655SYOSHIFUJI Hideaki 		if (!memcmp(n->key, pkey, key_len) &&
751be01d655SYOSHIFUJI Hideaki 		    net_eq(pneigh_net(n), net) &&
752be01d655SYOSHIFUJI Hideaki 		    (n->dev == dev || !n->dev))
753fa86d322SPavel Emelyanov 			return n;
754be01d655SYOSHIFUJI Hideaki 		n = n->next;
755be01d655SYOSHIFUJI Hideaki 	}
756be01d655SYOSHIFUJI Hideaki 	return NULL;
757be01d655SYOSHIFUJI Hideaki }
758be01d655SYOSHIFUJI Hideaki 
759be01d655SYOSHIFUJI Hideaki struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
760be01d655SYOSHIFUJI Hideaki 		struct net *net, const void *pkey, struct net_device *dev)
761be01d655SYOSHIFUJI Hideaki {
76201ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
763be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
764be01d655SYOSHIFUJI Hideaki 
765be01d655SYOSHIFUJI Hideaki 	return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
766be01d655SYOSHIFUJI Hideaki 				 net, pkey, key_len, dev);
767fa86d322SPavel Emelyanov }
7680a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL_GPL(__pneigh_lookup);
769fa86d322SPavel Emelyanov 
770426b5303SEric W. Biederman struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
771426b5303SEric W. Biederman 				    struct net *net, const void *pkey,
7721da177e4SLinus Torvalds 				    struct net_device *dev, int creat)
7731da177e4SLinus Torvalds {
7741da177e4SLinus Torvalds 	struct pneigh_entry *n;
77501ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
776be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
7771da177e4SLinus Torvalds 
7781da177e4SLinus Torvalds 	read_lock_bh(&tbl->lock);
779be01d655SYOSHIFUJI Hideaki 	n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
780be01d655SYOSHIFUJI Hideaki 			      net, pkey, key_len, dev);
781be01d655SYOSHIFUJI Hideaki 	read_unlock_bh(&tbl->lock);
7821da177e4SLinus Torvalds 
783be01d655SYOSHIFUJI Hideaki 	if (n || !creat)
7841da177e4SLinus Torvalds 		goto out;
7851da177e4SLinus Torvalds 
7864ae28944SPavel Emelyanov 	ASSERT_RTNL();
7874ae28944SPavel Emelyanov 
788e195e9b5SEric Dumazet 	n = kzalloc(sizeof(*n) + key_len, GFP_KERNEL);
7891da177e4SLinus Torvalds 	if (!n)
7901da177e4SLinus Torvalds 		goto out;
7911da177e4SLinus Torvalds 
792efd7ef1cSEric W. Biederman 	write_pnet(&n->net, net);
7931da177e4SLinus Torvalds 	memcpy(n->key, pkey, key_len);
7941da177e4SLinus Torvalds 	n->dev = dev;
795d62607c3SJakub Kicinski 	netdev_hold(dev, &n->dev_tracker, GFP_KERNEL);
7961da177e4SLinus Torvalds 
7971da177e4SLinus Torvalds 	if (tbl->pconstructor && tbl->pconstructor(n)) {
798d62607c3SJakub Kicinski 		netdev_put(dev, &n->dev_tracker);
7991da177e4SLinus Torvalds 		kfree(n);
8001da177e4SLinus Torvalds 		n = NULL;
8011da177e4SLinus Torvalds 		goto out;
8021da177e4SLinus Torvalds 	}
8031da177e4SLinus Torvalds 
8041da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
8051da177e4SLinus Torvalds 	n->next = tbl->phash_buckets[hash_val];
8061da177e4SLinus Torvalds 	tbl->phash_buckets[hash_val] = n;
8071da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
8081da177e4SLinus Torvalds out:
8091da177e4SLinus Torvalds 	return n;
8101da177e4SLinus Torvalds }
8110a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(pneigh_lookup);
8121da177e4SLinus Torvalds 
8131da177e4SLinus Torvalds 
814426b5303SEric W. Biederman int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
8151da177e4SLinus Torvalds 		  struct net_device *dev)
8161da177e4SLinus Torvalds {
8171da177e4SLinus Torvalds 	struct pneigh_entry *n, **np;
81801ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
819be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
8201da177e4SLinus Torvalds 
8211da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
8221da177e4SLinus Torvalds 	for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
8231da177e4SLinus Torvalds 	     np = &n->next) {
824426b5303SEric W. Biederman 		if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
825878628fbSYOSHIFUJI Hideaki 		    net_eq(pneigh_net(n), net)) {
8261da177e4SLinus Torvalds 			*np = n->next;
8271da177e4SLinus Torvalds 			write_unlock_bh(&tbl->lock);
8281da177e4SLinus Torvalds 			if (tbl->pdestructor)
8291da177e4SLinus Torvalds 				tbl->pdestructor(n);
830d62607c3SJakub Kicinski 			netdev_put(n->dev, &n->dev_tracker);
8311da177e4SLinus Torvalds 			kfree(n);
8321da177e4SLinus Torvalds 			return 0;
8331da177e4SLinus Torvalds 		}
8341da177e4SLinus Torvalds 	}
8351da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
8361da177e4SLinus Torvalds 	return -ENOENT;
8371da177e4SLinus Torvalds }
8381da177e4SLinus Torvalds 
83953b76cdfSWolfgang Bumiller static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
84053b76cdfSWolfgang Bumiller 				    struct net_device *dev)
8411da177e4SLinus Torvalds {
84253b76cdfSWolfgang Bumiller 	struct pneigh_entry *n, **np, *freelist = NULL;
8431da177e4SLinus Torvalds 	u32 h;
8441da177e4SLinus Torvalds 
8451da177e4SLinus Torvalds 	for (h = 0; h <= PNEIGH_HASHMASK; h++) {
8461da177e4SLinus Torvalds 		np = &tbl->phash_buckets[h];
8471da177e4SLinus Torvalds 		while ((n = *np) != NULL) {
8481da177e4SLinus Torvalds 			if (!dev || n->dev == dev) {
8491da177e4SLinus Torvalds 				*np = n->next;
85053b76cdfSWolfgang Bumiller 				n->next = freelist;
85153b76cdfSWolfgang Bumiller 				freelist = n;
85253b76cdfSWolfgang Bumiller 				continue;
85353b76cdfSWolfgang Bumiller 			}
85453b76cdfSWolfgang Bumiller 			np = &n->next;
85553b76cdfSWolfgang Bumiller 		}
85653b76cdfSWolfgang Bumiller 	}
85753b76cdfSWolfgang Bumiller 	write_unlock_bh(&tbl->lock);
85853b76cdfSWolfgang Bumiller 	while ((n = freelist)) {
85953b76cdfSWolfgang Bumiller 		freelist = n->next;
86053b76cdfSWolfgang Bumiller 		n->next = NULL;
8611da177e4SLinus Torvalds 		if (tbl->pdestructor)
8621da177e4SLinus Torvalds 			tbl->pdestructor(n);
863d62607c3SJakub Kicinski 		netdev_put(n->dev, &n->dev_tracker);
8641da177e4SLinus Torvalds 		kfree(n);
8651da177e4SLinus Torvalds 	}
8661da177e4SLinus Torvalds 	return -ENOENT;
8671da177e4SLinus Torvalds }
8681da177e4SLinus Torvalds 
86906f0511dSDenis V. Lunev static void neigh_parms_destroy(struct neigh_parms *parms);
87006f0511dSDenis V. Lunev 
87106f0511dSDenis V. Lunev static inline void neigh_parms_put(struct neigh_parms *parms)
87206f0511dSDenis V. Lunev {
8736343944bSReshetova, Elena 	if (refcount_dec_and_test(&parms->refcnt))
87406f0511dSDenis V. Lunev 		neigh_parms_destroy(parms);
87506f0511dSDenis V. Lunev }
8761da177e4SLinus Torvalds 
8771da177e4SLinus Torvalds /*
8781da177e4SLinus Torvalds  *	neighbour must already be out of the table;
8791da177e4SLinus Torvalds  *
8801da177e4SLinus Torvalds  */
8811da177e4SLinus Torvalds void neigh_destroy(struct neighbour *neigh)
8821da177e4SLinus Torvalds {
883da6a8fa0SDavid Miller 	struct net_device *dev = neigh->dev;
884da6a8fa0SDavid Miller 
8851da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
8861da177e4SLinus Torvalds 
8871da177e4SLinus Torvalds 	if (!neigh->dead) {
888e005d193SJoe Perches 		pr_warn("Destroying alive neighbour %p\n", neigh);
8891da177e4SLinus Torvalds 		dump_stack();
8901da177e4SLinus Torvalds 		return;
8911da177e4SLinus Torvalds 	}
8921da177e4SLinus Torvalds 
8931da177e4SLinus Torvalds 	if (neigh_del_timer(neigh))
894e005d193SJoe Perches 		pr_warn("Impossible event\n");
8951da177e4SLinus Torvalds 
896c9ab4d85SEric Dumazet 	write_lock_bh(&neigh->lock);
897c9ab4d85SEric Dumazet 	__skb_queue_purge(&neigh->arp_queue);
898c9ab4d85SEric Dumazet 	write_unlock_bh(&neigh->lock);
8998b5c171bSEric Dumazet 	neigh->arp_queue_len_bytes = 0;
9001da177e4SLinus Torvalds 
901447f2191SDavid S. Miller 	if (dev->netdev_ops->ndo_neigh_destroy)
902503eebc2SJiri Pirko 		dev->netdev_ops->ndo_neigh_destroy(dev, neigh);
903447f2191SDavid S. Miller 
904d62607c3SJakub Kicinski 	netdev_put(dev, &neigh->dev_tracker);
9051da177e4SLinus Torvalds 	neigh_parms_put(neigh->parms);
9061da177e4SLinus Torvalds 
907d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is destroyed\n", neigh);
9081da177e4SLinus Torvalds 
9091da177e4SLinus Torvalds 	atomic_dec(&neigh->tbl->entries);
9105b8b0060SDavid Miller 	kfree_rcu(neigh, rcu);
9111da177e4SLinus Torvalds }
9120a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_destroy);
9131da177e4SLinus Torvalds 
9141da177e4SLinus Torvalds /* Neighbour state is suspicious;
9151da177e4SLinus Torvalds    disable fast path.
9161da177e4SLinus Torvalds 
9171da177e4SLinus Torvalds    Called with write_locked neigh.
9181da177e4SLinus Torvalds  */
9191da177e4SLinus Torvalds static void neigh_suspect(struct neighbour *neigh)
9201da177e4SLinus Torvalds {
921d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is suspected\n", neigh);
9221da177e4SLinus Torvalds 
9231da177e4SLinus Torvalds 	neigh->output = neigh->ops->output;
9241da177e4SLinus Torvalds }
9251da177e4SLinus Torvalds 
9261da177e4SLinus Torvalds /* Neighbour state is OK;
9271da177e4SLinus Torvalds    enable fast path.
9281da177e4SLinus Torvalds 
9291da177e4SLinus Torvalds    Called with write_locked neigh.
9301da177e4SLinus Torvalds  */
9311da177e4SLinus Torvalds static void neigh_connect(struct neighbour *neigh)
9321da177e4SLinus Torvalds {
933d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is connected\n", neigh);
9341da177e4SLinus Torvalds 
9351da177e4SLinus Torvalds 	neigh->output = neigh->ops->connected_output;
9361da177e4SLinus Torvalds }
9371da177e4SLinus Torvalds 
938e4c4e448SEric Dumazet static void neigh_periodic_work(struct work_struct *work)
9391da177e4SLinus Torvalds {
940e4c4e448SEric Dumazet 	struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
941767e97e1SEric Dumazet 	struct neighbour *n;
942767e97e1SEric Dumazet 	struct neighbour __rcu **np;
943e4c4e448SEric Dumazet 	unsigned int i;
944d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
9451da177e4SLinus Torvalds 
9461da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
9471da177e4SLinus Torvalds 
948e4c4e448SEric Dumazet 	write_lock_bh(&tbl->lock);
949d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
950d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
9511da177e4SLinus Torvalds 
9521da177e4SLinus Torvalds 	/*
9531da177e4SLinus Torvalds 	 *	periodically recompute ReachableTime from random function
9541da177e4SLinus Torvalds 	 */
9551da177e4SLinus Torvalds 
956e4c4e448SEric Dumazet 	if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
9571da177e4SLinus Torvalds 		struct neigh_parms *p;
958e4c4e448SEric Dumazet 		tbl->last_rand = jiffies;
95975fbfd33SNicolas Dichtel 		list_for_each_entry(p, &tbl->parms_list, list)
9601da177e4SLinus Torvalds 			p->reachable_time =
9611f9248e5SJiri Pirko 				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
9621da177e4SLinus Torvalds 	}
9631da177e4SLinus Torvalds 
964feff9ab2SDuan Jiong 	if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
965feff9ab2SDuan Jiong 		goto out;
966feff9ab2SDuan Jiong 
967cd089336SDavid S. Miller 	for (i = 0 ; i < (1 << nht->hash_shift); i++) {
968d6bf7817SEric Dumazet 		np = &nht->hash_buckets[i];
9691da177e4SLinus Torvalds 
970767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
971767e97e1SEric Dumazet 				lockdep_is_held(&tbl->lock))) != NULL) {
9721da177e4SLinus Torvalds 			unsigned int state;
9731da177e4SLinus Torvalds 
9741da177e4SLinus Torvalds 			write_lock(&n->lock);
9751da177e4SLinus Torvalds 
9761da177e4SLinus Torvalds 			state = n->nud_state;
9779ce33e46SRoopa Prabhu 			if ((state & (NUD_PERMANENT | NUD_IN_TIMER)) ||
9789ce33e46SRoopa Prabhu 			    (n->flags & NTF_EXT_LEARNED)) {
9791da177e4SLinus Torvalds 				write_unlock(&n->lock);
9801da177e4SLinus Torvalds 				goto next_elt;
9811da177e4SLinus Torvalds 			}
9821da177e4SLinus Torvalds 
983c1d2ecdfSJulian Anastasov 			if (time_before(n->used, n->confirmed) &&
984c1d2ecdfSJulian Anastasov 			    time_is_before_eq_jiffies(n->confirmed))
9851da177e4SLinus Torvalds 				n->used = n->confirmed;
9861da177e4SLinus Torvalds 
9879f237430SReshetova, Elena 			if (refcount_read(&n->refcnt) == 1 &&
9881da177e4SLinus Torvalds 			    (state == NUD_FAILED ||
989c1d2ecdfSJulian Anastasov 			     !time_in_range_open(jiffies, n->used,
990c1d2ecdfSJulian Anastasov 						 n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
9911da177e4SLinus Torvalds 				*np = n->next;
99258956317SDavid Ahern 				neigh_mark_dead(n);
9931da177e4SLinus Torvalds 				write_unlock(&n->lock);
9944f494554SThomas Graf 				neigh_cleanup_and_release(n);
9951da177e4SLinus Torvalds 				continue;
9961da177e4SLinus Torvalds 			}
9971da177e4SLinus Torvalds 			write_unlock(&n->lock);
9981da177e4SLinus Torvalds 
9991da177e4SLinus Torvalds next_elt:
10001da177e4SLinus Torvalds 			np = &n->next;
10011da177e4SLinus Torvalds 		}
1002e4c4e448SEric Dumazet 		/*
1003e4c4e448SEric Dumazet 		 * It's fine to release lock here, even if hash table
1004e4c4e448SEric Dumazet 		 * grows while we are preempted.
1005e4c4e448SEric Dumazet 		 */
1006e4c4e448SEric Dumazet 		write_unlock_bh(&tbl->lock);
1007e4c4e448SEric Dumazet 		cond_resched();
1008e4c4e448SEric Dumazet 		write_lock_bh(&tbl->lock);
100984338a6cSMichel Machado 		nht = rcu_dereference_protected(tbl->nht,
101084338a6cSMichel Machado 						lockdep_is_held(&tbl->lock));
1011e4c4e448SEric Dumazet 	}
10122724680bSYOSHIFUJI Hideaki / 吉藤英明 out:
10131f9248e5SJiri Pirko 	/* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks.
10141f9248e5SJiri Pirko 	 * ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2
10151f9248e5SJiri Pirko 	 * BASE_REACHABLE_TIME.
10161da177e4SLinus Torvalds 	 */
1017f618002bSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
10181f9248e5SJiri Pirko 			      NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1);
1019e4c4e448SEric Dumazet 	write_unlock_bh(&tbl->lock);
10201da177e4SLinus Torvalds }
10211da177e4SLinus Torvalds 
10221da177e4SLinus Torvalds static __inline__ int neigh_max_probes(struct neighbour *n)
10231da177e4SLinus Torvalds {
10241da177e4SLinus Torvalds 	struct neigh_parms *p = n->parms;
10258da86466SYOSHIFUJI Hideaki/吉藤英明 	return NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) +
10268da86466SYOSHIFUJI Hideaki/吉藤英明 	       (n->nud_state & NUD_PROBE ? NEIGH_VAR(p, MCAST_REPROBES) :
10278da86466SYOSHIFUJI Hideaki/吉藤英明 	        NEIGH_VAR(p, MCAST_PROBES));
10281da177e4SLinus Torvalds }
10291da177e4SLinus Torvalds 
10305ef12d98STimo Teras static void neigh_invalidate(struct neighbour *neigh)
10310a141509SEric Dumazet 	__releases(neigh->lock)
10320a141509SEric Dumazet 	__acquires(neigh->lock)
10335ef12d98STimo Teras {
10345ef12d98STimo Teras 	struct sk_buff *skb;
10355ef12d98STimo Teras 
10365ef12d98STimo Teras 	NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
1037d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is failed\n", neigh);
10385ef12d98STimo Teras 	neigh->updated = jiffies;
10395ef12d98STimo Teras 
10405ef12d98STimo Teras 	/* It is very thin place. report_unreachable is very complicated
10415ef12d98STimo Teras 	   routine. Particularly, it can hit the same neighbour entry!
10425ef12d98STimo Teras 
10435ef12d98STimo Teras 	   So that, we try to be accurate and avoid dead loop. --ANK
10445ef12d98STimo Teras 	 */
10455ef12d98STimo Teras 	while (neigh->nud_state == NUD_FAILED &&
10465ef12d98STimo Teras 	       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
10475ef12d98STimo Teras 		write_unlock(&neigh->lock);
10485ef12d98STimo Teras 		neigh->ops->error_report(neigh, skb);
10495ef12d98STimo Teras 		write_lock(&neigh->lock);
10505ef12d98STimo Teras 	}
1051c9ab4d85SEric Dumazet 	__skb_queue_purge(&neigh->arp_queue);
10528b5c171bSEric Dumazet 	neigh->arp_queue_len_bytes = 0;
10535ef12d98STimo Teras }
10545ef12d98STimo Teras 
1055cd28ca0aSEric Dumazet static void neigh_probe(struct neighbour *neigh)
1056cd28ca0aSEric Dumazet 	__releases(neigh->lock)
1057cd28ca0aSEric Dumazet {
10584ed377e3SHannes Frederic Sowa 	struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);
1059cd28ca0aSEric Dumazet 	/* keep skb alive even if arp_queue overflows */
1060cd28ca0aSEric Dumazet 	if (skb)
106119125c1aSMartin Zhang 		skb = skb_clone(skb, GFP_ATOMIC);
1062cd28ca0aSEric Dumazet 	write_unlock(&neigh->lock);
106348481c8fSEric Dumazet 	if (neigh->ops->solicit)
1064cd28ca0aSEric Dumazet 		neigh->ops->solicit(neigh, skb);
1065cd28ca0aSEric Dumazet 	atomic_inc(&neigh->probes);
106687fff3caSYang Wei 	consume_skb(skb);
1067cd28ca0aSEric Dumazet }
1068cd28ca0aSEric Dumazet 
10691da177e4SLinus Torvalds /* Called when a timer expires for a neighbour entry. */
10701da177e4SLinus Torvalds 
1071e99e88a9SKees Cook static void neigh_timer_handler(struct timer_list *t)
10721da177e4SLinus Torvalds {
10731da177e4SLinus Torvalds 	unsigned long now, next;
1074e99e88a9SKees Cook 	struct neighbour *neigh = from_timer(neigh, t, timer);
107595c96174SEric Dumazet 	unsigned int state;
10761da177e4SLinus Torvalds 	int notify = 0;
10771da177e4SLinus Torvalds 
10781da177e4SLinus Torvalds 	write_lock(&neigh->lock);
10791da177e4SLinus Torvalds 
10801da177e4SLinus Torvalds 	state = neigh->nud_state;
10811da177e4SLinus Torvalds 	now = jiffies;
10821da177e4SLinus Torvalds 	next = now + HZ;
10831da177e4SLinus Torvalds 
1084045f7b3bSDavid S. Miller 	if (!(state & NUD_IN_TIMER))
10851da177e4SLinus Torvalds 		goto out;
10861da177e4SLinus Torvalds 
10871da177e4SLinus Torvalds 	if (state & NUD_REACHABLE) {
10881da177e4SLinus Torvalds 		if (time_before_eq(now,
10891da177e4SLinus Torvalds 				   neigh->confirmed + neigh->parms->reachable_time)) {
1090d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is still alive\n", neigh);
10911da177e4SLinus Torvalds 			next = neigh->confirmed + neigh->parms->reachable_time;
10921da177e4SLinus Torvalds 		} else if (time_before_eq(now,
10931f9248e5SJiri Pirko 					  neigh->used +
10941f9248e5SJiri Pirko 					  NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
1095d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is delayed\n", neigh);
1096*b071af52SEric Dumazet 			WRITE_ONCE(neigh->nud_state, NUD_DELAY);
1097955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10981da177e4SLinus Torvalds 			neigh_suspect(neigh);
10991f9248e5SJiri Pirko 			next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME);
11001da177e4SLinus Torvalds 		} else {
1101d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is suspected\n", neigh);
1102*b071af52SEric Dumazet 			WRITE_ONCE(neigh->nud_state, NUD_STALE);
1103955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
11041da177e4SLinus Torvalds 			neigh_suspect(neigh);
11058d71740cSTom Tucker 			notify = 1;
11061da177e4SLinus Torvalds 		}
11071da177e4SLinus Torvalds 	} else if (state & NUD_DELAY) {
11081da177e4SLinus Torvalds 		if (time_before_eq(now,
11091f9248e5SJiri Pirko 				   neigh->confirmed +
11101f9248e5SJiri Pirko 				   NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
1111d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is now reachable\n", neigh);
1112*b071af52SEric Dumazet 			WRITE_ONCE(neigh->nud_state, NUD_REACHABLE);
1113955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
11141da177e4SLinus Torvalds 			neigh_connect(neigh);
11158d71740cSTom Tucker 			notify = 1;
11161da177e4SLinus Torvalds 			next = neigh->confirmed + neigh->parms->reachable_time;
11171da177e4SLinus Torvalds 		} else {
1118d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is probed\n", neigh);
1119*b071af52SEric Dumazet 			WRITE_ONCE(neigh->nud_state, NUD_PROBE);
1120955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
11211da177e4SLinus Torvalds 			atomic_set(&neigh->probes, 0);
1122765c9c63SErik Kline 			notify = 1;
112319e16d22SHangbin Liu 			next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
112419e16d22SHangbin Liu 					 HZ/100);
11251da177e4SLinus Torvalds 		}
11261da177e4SLinus Torvalds 	} else {
11271da177e4SLinus Torvalds 		/* NUD_PROBE|NUD_INCOMPLETE */
112819e16d22SHangbin Liu 		next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME), HZ/100);
11291da177e4SLinus Torvalds 	}
11301da177e4SLinus Torvalds 
11311da177e4SLinus Torvalds 	if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
11321da177e4SLinus Torvalds 	    atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
1133*b071af52SEric Dumazet 		WRITE_ONCE(neigh->nud_state, NUD_FAILED);
11341da177e4SLinus Torvalds 		notify = 1;
11355ef12d98STimo Teras 		neigh_invalidate(neigh);
11365e2c21dcSDuan Jiong 		goto out;
11371da177e4SLinus Torvalds 	}
11381da177e4SLinus Torvalds 
11391da177e4SLinus Torvalds 	if (neigh->nud_state & NUD_IN_TIMER) {
114096d10d5bSHangbin Liu 		if (time_before(next, jiffies + HZ/100))
114196d10d5bSHangbin Liu 			next = jiffies + HZ/100;
11426fb9974fSHerbert Xu 		if (!mod_timer(&neigh->timer, next))
11436fb9974fSHerbert Xu 			neigh_hold(neigh);
11441da177e4SLinus Torvalds 	}
11451da177e4SLinus Torvalds 	if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
1146cd28ca0aSEric Dumazet 		neigh_probe(neigh);
11479ff56607SDavid S. Miller 	} else {
11481da177e4SLinus Torvalds out:
11491da177e4SLinus Torvalds 		write_unlock(&neigh->lock);
11509ff56607SDavid S. Miller 	}
11511da177e4SLinus Torvalds 
1152d961db35SThomas Graf 	if (notify)
11537b8f7a40SRoopa Prabhu 		neigh_update_notify(neigh, 0);
1154d961db35SThomas Graf 
115556dd18a4SRoopa Prabhu 	trace_neigh_timer_handler(neigh, 0);
115656dd18a4SRoopa Prabhu 
11571da177e4SLinus Torvalds 	neigh_release(neigh);
11581da177e4SLinus Torvalds }
11591da177e4SLinus Torvalds 
11604a81f6daSDaniel Borkmann int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb,
11614a81f6daSDaniel Borkmann 		       const bool immediate_ok)
11621da177e4SLinus Torvalds {
11631da177e4SLinus Torvalds 	int rc;
1164cd28ca0aSEric Dumazet 	bool immediate_probe = false;
11651da177e4SLinus Torvalds 
11661da177e4SLinus Torvalds 	write_lock_bh(&neigh->lock);
11671da177e4SLinus Torvalds 
11681da177e4SLinus Torvalds 	rc = 0;
11691da177e4SLinus Torvalds 	if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
11701da177e4SLinus Torvalds 		goto out_unlock_bh;
11712c51a97fSJulian Anastasov 	if (neigh->dead)
11722c51a97fSJulian Anastasov 		goto out_dead;
11731da177e4SLinus Torvalds 
11741da177e4SLinus Torvalds 	if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
11751f9248e5SJiri Pirko 		if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
11761f9248e5SJiri Pirko 		    NEIGH_VAR(neigh->parms, APP_PROBES)) {
1177cd28ca0aSEric Dumazet 			unsigned long next, now = jiffies;
1178cd28ca0aSEric Dumazet 
11791f9248e5SJiri Pirko 			atomic_set(&neigh->probes,
11801f9248e5SJiri Pirko 				   NEIGH_VAR(neigh->parms, UCAST_PROBES));
1181071c3798SLorenzo Bianconi 			neigh_del_timer(neigh);
1182*b071af52SEric Dumazet 			WRITE_ONCE(neigh->nud_state, NUD_INCOMPLETE);
1183cd28ca0aSEric Dumazet 			neigh->updated = now;
11844a81f6daSDaniel Borkmann 			if (!immediate_ok) {
11854a81f6daSDaniel Borkmann 				next = now + 1;
11864a81f6daSDaniel Borkmann 			} else {
1187cd28ca0aSEric Dumazet 				immediate_probe = true;
11884a81f6daSDaniel Borkmann 				next = now + max(NEIGH_VAR(neigh->parms,
11894a81f6daSDaniel Borkmann 							   RETRANS_TIME),
11904a81f6daSDaniel Borkmann 						 HZ / 100);
11914a81f6daSDaniel Borkmann 			}
11924a81f6daSDaniel Borkmann 			neigh_add_timer(neigh, next);
11931da177e4SLinus Torvalds 		} else {
1194*b071af52SEric Dumazet 			WRITE_ONCE(neigh->nud_state, NUD_FAILED);
1195955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
11961da177e4SLinus Torvalds 			write_unlock_bh(&neigh->lock);
11971da177e4SLinus Torvalds 
1198a5736eddSMenglong Dong 			kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_FAILED);
11991da177e4SLinus Torvalds 			return 1;
12001da177e4SLinus Torvalds 		}
12011da177e4SLinus Torvalds 	} else if (neigh->nud_state & NUD_STALE) {
1202d5d427cdSJoe Perches 		neigh_dbg(2, "neigh %p is delayed\n", neigh);
1203071c3798SLorenzo Bianconi 		neigh_del_timer(neigh);
1204*b071af52SEric Dumazet 		WRITE_ONCE(neigh->nud_state, NUD_DELAY);
1205955aaa2fSYOSHIFUJI Hideaki 		neigh->updated = jiffies;
12061f9248e5SJiri Pirko 		neigh_add_timer(neigh, jiffies +
12071f9248e5SJiri Pirko 				NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME));
12081da177e4SLinus Torvalds 	}
12091da177e4SLinus Torvalds 
12101da177e4SLinus Torvalds 	if (neigh->nud_state == NUD_INCOMPLETE) {
12111da177e4SLinus Torvalds 		if (skb) {
12128b5c171bSEric Dumazet 			while (neigh->arp_queue_len_bytes + skb->truesize >
12131f9248e5SJiri Pirko 			       NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) {
12141da177e4SLinus Torvalds 				struct sk_buff *buff;
12158b5c171bSEric Dumazet 
1216f72051b0SDavid S. Miller 				buff = __skb_dequeue(&neigh->arp_queue);
12178b5c171bSEric Dumazet 				if (!buff)
12188b5c171bSEric Dumazet 					break;
12198b5c171bSEric Dumazet 				neigh->arp_queue_len_bytes -= buff->truesize;
1220a5736eddSMenglong Dong 				kfree_skb_reason(buff, SKB_DROP_REASON_NEIGH_QUEUEFULL);
12219a6d276eSNeil Horman 				NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
12221da177e4SLinus Torvalds 			}
1223a4731138SEric Dumazet 			skb_dst_force(skb);
12241da177e4SLinus Torvalds 			__skb_queue_tail(&neigh->arp_queue, skb);
12258b5c171bSEric Dumazet 			neigh->arp_queue_len_bytes += skb->truesize;
12261da177e4SLinus Torvalds 		}
12271da177e4SLinus Torvalds 		rc = 1;
12281da177e4SLinus Torvalds 	}
12291da177e4SLinus Torvalds out_unlock_bh:
1230cd28ca0aSEric Dumazet 	if (immediate_probe)
1231cd28ca0aSEric Dumazet 		neigh_probe(neigh);
1232cd28ca0aSEric Dumazet 	else
1233cd28ca0aSEric Dumazet 		write_unlock(&neigh->lock);
1234cd28ca0aSEric Dumazet 	local_bh_enable();
123556dd18a4SRoopa Prabhu 	trace_neigh_event_send_done(neigh, rc);
12361da177e4SLinus Torvalds 	return rc;
12372c51a97fSJulian Anastasov 
12382c51a97fSJulian Anastasov out_dead:
12392c51a97fSJulian Anastasov 	if (neigh->nud_state & NUD_STALE)
12402c51a97fSJulian Anastasov 		goto out_unlock_bh;
12412c51a97fSJulian Anastasov 	write_unlock_bh(&neigh->lock);
1242a5736eddSMenglong Dong 	kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_DEAD);
124356dd18a4SRoopa Prabhu 	trace_neigh_event_send_dead(neigh, 1);
12442c51a97fSJulian Anastasov 	return 1;
12451da177e4SLinus Torvalds }
12460a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(__neigh_event_send);
12471da177e4SLinus Torvalds 
1248f6b72b62SDavid S. Miller static void neigh_update_hhs(struct neighbour *neigh)
12491da177e4SLinus Torvalds {
12501da177e4SLinus Torvalds 	struct hh_cache *hh;
12513b04dddeSStephen Hemminger 	void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
125291a72a70SDoug Kehn 		= NULL;
125391a72a70SDoug Kehn 
125491a72a70SDoug Kehn 	if (neigh->dev->header_ops)
125591a72a70SDoug Kehn 		update = neigh->dev->header_ops->cache_update;
12561da177e4SLinus Torvalds 
12571da177e4SLinus Torvalds 	if (update) {
1258f6b72b62SDavid S. Miller 		hh = &neigh->hh;
1259c305c6aeSEric Dumazet 		if (READ_ONCE(hh->hh_len)) {
12603644f0ceSStephen Hemminger 			write_seqlock_bh(&hh->hh_lock);
12611da177e4SLinus Torvalds 			update(hh, neigh->dev, neigh->ha);
12623644f0ceSStephen Hemminger 			write_sequnlock_bh(&hh->hh_lock);
12631da177e4SLinus Torvalds 		}
12641da177e4SLinus Torvalds 	}
12651da177e4SLinus Torvalds }
12661da177e4SLinus Torvalds 
12671da177e4SLinus Torvalds /* Generic update routine.
12681da177e4SLinus Torvalds    -- lladdr is new lladdr or NULL, if it is not supplied.
12691da177e4SLinus Torvalds    -- new    is new state.
12701da177e4SLinus Torvalds    -- flags
12711da177e4SLinus Torvalds 	NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
12721da177e4SLinus Torvalds 				if it is different.
12731da177e4SLinus Torvalds 	NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
12741da177e4SLinus Torvalds 				lladdr instead of overriding it
12751da177e4SLinus Torvalds 				if it is different.
12761da177e4SLinus Torvalds 	NEIGH_UPDATE_F_ADMIN	means that the change is administrative.
12773dc20f47SDaniel Borkmann 	NEIGH_UPDATE_F_USE	means that the entry is user triggered.
12787482e384SDaniel Borkmann 	NEIGH_UPDATE_F_MANAGED	means that the entry will be auto-refreshed.
12791da177e4SLinus Torvalds 	NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
12801da177e4SLinus Torvalds 				NTF_ROUTER flag.
12811da177e4SLinus Torvalds 	NEIGH_UPDATE_F_ISROUTER	indicates if the neighbour is known as
12821da177e4SLinus Torvalds 				a router.
12831da177e4SLinus Torvalds 
12841da177e4SLinus Torvalds    Caller MUST hold reference count on the entry.
12851da177e4SLinus Torvalds  */
12867a35a50dSDavid Ahern static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
12877a35a50dSDavid Ahern 			  u8 new, u32 flags, u32 nlmsg_pid,
12887a35a50dSDavid Ahern 			  struct netlink_ext_ack *extack)
12891da177e4SLinus Torvalds {
12907482e384SDaniel Borkmann 	bool gc_update = false, managed_update = false;
12911da177e4SLinus Torvalds 	int update_isrouter = 0;
12927482e384SDaniel Borkmann 	struct net_device *dev;
12937482e384SDaniel Borkmann 	int err, notify = 0;
12947482e384SDaniel Borkmann 	u8 old;
12951da177e4SLinus Torvalds 
129656dd18a4SRoopa Prabhu 	trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid);
129756dd18a4SRoopa Prabhu 
12981da177e4SLinus Torvalds 	write_lock_bh(&neigh->lock);
12991da177e4SLinus Torvalds 
13001da177e4SLinus Torvalds 	dev    = neigh->dev;
13011da177e4SLinus Torvalds 	old    = neigh->nud_state;
13021da177e4SLinus Torvalds 	err    = -EPERM;
13031da177e4SLinus Torvalds 
1304eb4e8facSChinmay Agarwal 	if (neigh->dead) {
1305eb4e8facSChinmay Agarwal 		NL_SET_ERR_MSG(extack, "Neighbor entry is now dead");
1306eb4e8facSChinmay Agarwal 		new = old;
1307eb4e8facSChinmay Agarwal 		goto out;
1308eb4e8facSChinmay Agarwal 	}
13091da177e4SLinus Torvalds 	if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
13101da177e4SLinus Torvalds 	    (old & (NUD_NOARP | NUD_PERMANENT)))
13111da177e4SLinus Torvalds 		goto out;
13121da177e4SLinus Torvalds 
13137482e384SDaniel Borkmann 	neigh_update_flags(neigh, flags, &notify, &gc_update, &managed_update);
13147482e384SDaniel Borkmann 	if (flags & (NEIGH_UPDATE_F_USE | NEIGH_UPDATE_F_MANAGED)) {
13153dc20f47SDaniel Borkmann 		new = old & ~NUD_PERMANENT;
1316*b071af52SEric Dumazet 		WRITE_ONCE(neigh->nud_state, new);
13173dc20f47SDaniel Borkmann 		err = 0;
13183dc20f47SDaniel Borkmann 		goto out;
13193dc20f47SDaniel Borkmann 	}
13209ce33e46SRoopa Prabhu 
13211da177e4SLinus Torvalds 	if (!(new & NUD_VALID)) {
13221da177e4SLinus Torvalds 		neigh_del_timer(neigh);
13231da177e4SLinus Torvalds 		if (old & NUD_CONNECTED)
13241da177e4SLinus Torvalds 			neigh_suspect(neigh);
1325*b071af52SEric Dumazet 		WRITE_ONCE(neigh->nud_state, new);
13261da177e4SLinus Torvalds 		err = 0;
13271da177e4SLinus Torvalds 		notify = old & NUD_VALID;
1328d2fb4fb8SRoopa Prabhu 		if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
13295ef12d98STimo Teras 		    (new & NUD_FAILED)) {
13305ef12d98STimo Teras 			neigh_invalidate(neigh);
13315ef12d98STimo Teras 			notify = 1;
13325ef12d98STimo Teras 		}
13331da177e4SLinus Torvalds 		goto out;
13341da177e4SLinus Torvalds 	}
13351da177e4SLinus Torvalds 
13361da177e4SLinus Torvalds 	/* Compare new lladdr with cached one */
13371da177e4SLinus Torvalds 	if (!dev->addr_len) {
13381da177e4SLinus Torvalds 		/* First case: device needs no address. */
13391da177e4SLinus Torvalds 		lladdr = neigh->ha;
13401da177e4SLinus Torvalds 	} else if (lladdr) {
13411da177e4SLinus Torvalds 		/* The second case: if something is already cached
13421da177e4SLinus Torvalds 		   and a new address is proposed:
13431da177e4SLinus Torvalds 		   - compare new & old
13441da177e4SLinus Torvalds 		   - if they are different, check override flag
13451da177e4SLinus Torvalds 		 */
13461da177e4SLinus Torvalds 		if ((old & NUD_VALID) &&
13471da177e4SLinus Torvalds 		    !memcmp(lladdr, neigh->ha, dev->addr_len))
13481da177e4SLinus Torvalds 			lladdr = neigh->ha;
13491da177e4SLinus Torvalds 	} else {
13501da177e4SLinus Torvalds 		/* No address is supplied; if we know something,
13511da177e4SLinus Torvalds 		   use it, otherwise discard the request.
13521da177e4SLinus Torvalds 		 */
13531da177e4SLinus Torvalds 		err = -EINVAL;
13547a35a50dSDavid Ahern 		if (!(old & NUD_VALID)) {
13557a35a50dSDavid Ahern 			NL_SET_ERR_MSG(extack, "No link layer address given");
13561da177e4SLinus Torvalds 			goto out;
13577a35a50dSDavid Ahern 		}
13581da177e4SLinus Torvalds 		lladdr = neigh->ha;
13591da177e4SLinus Torvalds 	}
13601da177e4SLinus Torvalds 
1361f0e0d044SVasily Khoruzhick 	/* Update confirmed timestamp for neighbour entry after we
1362f0e0d044SVasily Khoruzhick 	 * received ARP packet even if it doesn't change IP to MAC binding.
1363f0e0d044SVasily Khoruzhick 	 */
1364f0e0d044SVasily Khoruzhick 	if (new & NUD_CONNECTED)
1365f0e0d044SVasily Khoruzhick 		neigh->confirmed = jiffies;
1366f0e0d044SVasily Khoruzhick 
13671da177e4SLinus Torvalds 	/* If entry was valid and address is not changed,
13681da177e4SLinus Torvalds 	   do not change entry state, if new one is STALE.
13691da177e4SLinus Torvalds 	 */
13701da177e4SLinus Torvalds 	err = 0;
13711da177e4SLinus Torvalds 	update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
13721da177e4SLinus Torvalds 	if (old & NUD_VALID) {
13731da177e4SLinus Torvalds 		if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
13741da177e4SLinus Torvalds 			update_isrouter = 0;
13751da177e4SLinus Torvalds 			if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
13761da177e4SLinus Torvalds 			    (old & NUD_CONNECTED)) {
13771da177e4SLinus Torvalds 				lladdr = neigh->ha;
13781da177e4SLinus Torvalds 				new = NUD_STALE;
13791da177e4SLinus Torvalds 			} else
13801da177e4SLinus Torvalds 				goto out;
13811da177e4SLinus Torvalds 		} else {
13820e7bbcc1SJulian Anastasov 			if (lladdr == neigh->ha && new == NUD_STALE &&
13830e7bbcc1SJulian Anastasov 			    !(flags & NEIGH_UPDATE_F_ADMIN))
13841da177e4SLinus Torvalds 				new = old;
13851da177e4SLinus Torvalds 		}
13861da177e4SLinus Torvalds 	}
13871da177e4SLinus Torvalds 
1388f0e0d044SVasily Khoruzhick 	/* Update timestamp only once we know we will make a change to the
138977d71233SIhar Hrachyshka 	 * neighbour entry. Otherwise we risk to move the locktime window with
139077d71233SIhar Hrachyshka 	 * noop updates and ignore relevant ARP updates.
139177d71233SIhar Hrachyshka 	 */
1392f0e0d044SVasily Khoruzhick 	if (new != old || lladdr != neigh->ha)
139377d71233SIhar Hrachyshka 		neigh->updated = jiffies;
139477d71233SIhar Hrachyshka 
13951da177e4SLinus Torvalds 	if (new != old) {
13961da177e4SLinus Torvalds 		neigh_del_timer(neigh);
1397765c9c63SErik Kline 		if (new & NUD_PROBE)
1398765c9c63SErik Kline 			atomic_set(&neigh->probes, 0);
1399a43d8994SPavel Emelyanov 		if (new & NUD_IN_TIMER)
1400667347f1SDavid S. Miller 			neigh_add_timer(neigh, (jiffies +
14011da177e4SLinus Torvalds 						((new & NUD_REACHABLE) ?
1402667347f1SDavid S. Miller 						 neigh->parms->reachable_time :
1403667347f1SDavid S. Miller 						 0)));
1404*b071af52SEric Dumazet 		WRITE_ONCE(neigh->nud_state, new);
140553385d2dSBob Gilligan 		notify = 1;
14061da177e4SLinus Torvalds 	}
14071da177e4SLinus Torvalds 
14081da177e4SLinus Torvalds 	if (lladdr != neigh->ha) {
14090ed8ddf4SEric Dumazet 		write_seqlock(&neigh->ha_lock);
14101da177e4SLinus Torvalds 		memcpy(&neigh->ha, lladdr, dev->addr_len);
14110ed8ddf4SEric Dumazet 		write_sequnlock(&neigh->ha_lock);
14121da177e4SLinus Torvalds 		neigh_update_hhs(neigh);
14131da177e4SLinus Torvalds 		if (!(new & NUD_CONNECTED))
14141da177e4SLinus Torvalds 			neigh->confirmed = jiffies -
14151f9248e5SJiri Pirko 				      (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1);
14161da177e4SLinus Torvalds 		notify = 1;
14171da177e4SLinus Torvalds 	}
14181da177e4SLinus Torvalds 	if (new == old)
14191da177e4SLinus Torvalds 		goto out;
14201da177e4SLinus Torvalds 	if (new & NUD_CONNECTED)
14211da177e4SLinus Torvalds 		neigh_connect(neigh);
14221da177e4SLinus Torvalds 	else
14231da177e4SLinus Torvalds 		neigh_suspect(neigh);
14241da177e4SLinus Torvalds 	if (!(old & NUD_VALID)) {
14251da177e4SLinus Torvalds 		struct sk_buff *skb;
14261da177e4SLinus Torvalds 
14271da177e4SLinus Torvalds 		/* Again: avoid dead loop if something went wrong */
14281da177e4SLinus Torvalds 
14291da177e4SLinus Torvalds 		while (neigh->nud_state & NUD_VALID &&
14301da177e4SLinus Torvalds 		       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
143169cce1d1SDavid S. Miller 			struct dst_entry *dst = skb_dst(skb);
143269cce1d1SDavid S. Miller 			struct neighbour *n2, *n1 = neigh;
14331da177e4SLinus Torvalds 			write_unlock_bh(&neigh->lock);
1434e049f288Sroy.qing.li@gmail.com 
1435e049f288Sroy.qing.li@gmail.com 			rcu_read_lock();
143613a43d94SDavid S. Miller 
143713a43d94SDavid S. Miller 			/* Why not just use 'neigh' as-is?  The problem is that
143813a43d94SDavid S. Miller 			 * things such as shaper, eql, and sch_teql can end up
143913a43d94SDavid S. Miller 			 * using alternative, different, neigh objects to output
144013a43d94SDavid S. Miller 			 * the packet in the output path.  So what we need to do
144113a43d94SDavid S. Miller 			 * here is re-lookup the top-level neigh in the path so
144213a43d94SDavid S. Miller 			 * we can reinject the packet there.
144313a43d94SDavid S. Miller 			 */
144413a43d94SDavid S. Miller 			n2 = NULL;
1445d47ec7a0STong Zhu 			if (dst && dst->obsolete != DST_OBSOLETE_DEAD) {
144613a43d94SDavid S. Miller 				n2 = dst_neigh_lookup_skb(dst, skb);
144713a43d94SDavid S. Miller 				if (n2)
144869cce1d1SDavid S. Miller 					n1 = n2;
144913a43d94SDavid S. Miller 			}
14508f40b161SDavid S. Miller 			n1->output(n1, skb);
145113a43d94SDavid S. Miller 			if (n2)
145213a43d94SDavid S. Miller 				neigh_release(n2);
1453e049f288Sroy.qing.li@gmail.com 			rcu_read_unlock();
1454e049f288Sroy.qing.li@gmail.com 
14551da177e4SLinus Torvalds 			write_lock_bh(&neigh->lock);
14561da177e4SLinus Torvalds 		}
1457c9ab4d85SEric Dumazet 		__skb_queue_purge(&neigh->arp_queue);
14588b5c171bSEric Dumazet 		neigh->arp_queue_len_bytes = 0;
14591da177e4SLinus Torvalds 	}
14601da177e4SLinus Torvalds out:
1461fc6e8073SRoopa Prabhu 	if (update_isrouter)
1462fc6e8073SRoopa Prabhu 		neigh_update_is_router(neigh, flags, &notify);
14631da177e4SLinus Torvalds 	write_unlock_bh(&neigh->lock);
14647482e384SDaniel Borkmann 	if (((new ^ old) & NUD_PERMANENT) || gc_update)
14659c29a2f5SDavid Ahern 		neigh_update_gc_list(neigh);
14667482e384SDaniel Borkmann 	if (managed_update)
14677482e384SDaniel Borkmann 		neigh_update_managed_list(neigh);
14688d71740cSTom Tucker 	if (notify)
14697b8f7a40SRoopa Prabhu 		neigh_update_notify(neigh, nlmsg_pid);
147056dd18a4SRoopa Prabhu 	trace_neigh_update_done(neigh, err);
14711da177e4SLinus Torvalds 	return err;
14721da177e4SLinus Torvalds }
14737a35a50dSDavid Ahern 
14747a35a50dSDavid Ahern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
14757a35a50dSDavid Ahern 		 u32 flags, u32 nlmsg_pid)
14767a35a50dSDavid Ahern {
14777a35a50dSDavid Ahern 	return __neigh_update(neigh, lladdr, new, flags, nlmsg_pid, NULL);
14787a35a50dSDavid Ahern }
14790a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_update);
14801da177e4SLinus Torvalds 
14817e980569SJiri Benc /* Update the neigh to listen temporarily for probe responses, even if it is
14827e980569SJiri Benc  * in a NUD_FAILED state. The caller has to hold neigh->lock for writing.
14837e980569SJiri Benc  */
14847e980569SJiri Benc void __neigh_set_probe_once(struct neighbour *neigh)
14857e980569SJiri Benc {
14862c51a97fSJulian Anastasov 	if (neigh->dead)
14872c51a97fSJulian Anastasov 		return;
14887e980569SJiri Benc 	neigh->updated = jiffies;
14897e980569SJiri Benc 	if (!(neigh->nud_state & NUD_FAILED))
14907e980569SJiri Benc 		return;
1491*b071af52SEric Dumazet 	WRITE_ONCE(neigh->nud_state, NUD_INCOMPLETE);
14922176d5d4SDuan Jiong 	atomic_set(&neigh->probes, neigh_max_probes(neigh));
14937e980569SJiri Benc 	neigh_add_timer(neigh,
149419e16d22SHangbin Liu 			jiffies + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
149519e16d22SHangbin Liu 				      HZ/100));
14967e980569SJiri Benc }
14977e980569SJiri Benc EXPORT_SYMBOL(__neigh_set_probe_once);
14987e980569SJiri Benc 
14991da177e4SLinus Torvalds struct neighbour *neigh_event_ns(struct neigh_table *tbl,
15001da177e4SLinus Torvalds 				 u8 *lladdr, void *saddr,
15011da177e4SLinus Torvalds 				 struct net_device *dev)
15021da177e4SLinus Torvalds {
15031da177e4SLinus Torvalds 	struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
15041da177e4SLinus Torvalds 						 lladdr || !dev->addr_len);
15051da177e4SLinus Torvalds 	if (neigh)
15061da177e4SLinus Torvalds 		neigh_update(neigh, lladdr, NUD_STALE,
15077b8f7a40SRoopa Prabhu 			     NEIGH_UPDATE_F_OVERRIDE, 0);
15081da177e4SLinus Torvalds 	return neigh;
15091da177e4SLinus Torvalds }
15100a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_event_ns);
15111da177e4SLinus Torvalds 
151234d101ddSEric Dumazet /* called with read_lock_bh(&n->lock); */
1513bdf53c58SEric W. Biederman static void neigh_hh_init(struct neighbour *n)
15141da177e4SLinus Torvalds {
1515bdf53c58SEric W. Biederman 	struct net_device *dev = n->dev;
1516bdf53c58SEric W. Biederman 	__be16 prot = n->tbl->protocol;
1517f6b72b62SDavid S. Miller 	struct hh_cache	*hh = &n->hh;
15180ed8ddf4SEric Dumazet 
15190ed8ddf4SEric Dumazet 	write_lock_bh(&n->lock);
152034d101ddSEric Dumazet 
1521f6b72b62SDavid S. Miller 	/* Only one thread can come in here and initialize the
1522f6b72b62SDavid S. Miller 	 * hh_cache entry.
1523f6b72b62SDavid S. Miller 	 */
1524b23b5455SDavid S. Miller 	if (!hh->hh_len)
1525b23b5455SDavid S. Miller 		dev->header_ops->cache(n, hh, prot);
1526f6b72b62SDavid S. Miller 
15270ed8ddf4SEric Dumazet 	write_unlock_bh(&n->lock);
15281da177e4SLinus Torvalds }
15291da177e4SLinus Torvalds 
15301da177e4SLinus Torvalds /* Slow and careful. */
15311da177e4SLinus Torvalds 
15328f40b161SDavid S. Miller int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
15331da177e4SLinus Torvalds {
15341da177e4SLinus Torvalds 	int rc = 0;
15351da177e4SLinus Torvalds 
15361da177e4SLinus Torvalds 	if (!neigh_event_send(neigh, skb)) {
15371da177e4SLinus Torvalds 		int err;
15381da177e4SLinus Torvalds 		struct net_device *dev = neigh->dev;
15390ed8ddf4SEric Dumazet 		unsigned int seq;
154034d101ddSEric Dumazet 
1541c305c6aeSEric Dumazet 		if (dev->header_ops->cache && !READ_ONCE(neigh->hh.hh_len))
1542bdf53c58SEric W. Biederman 			neigh_hh_init(neigh);
154334d101ddSEric Dumazet 
15440ed8ddf4SEric Dumazet 		do {
1545e1f16503Sramesh.nagappa@gmail.com 			__skb_pull(skb, skb_network_offset(skb));
15460ed8ddf4SEric Dumazet 			seq = read_seqbegin(&neigh->ha_lock);
15470c4e8581SStephen Hemminger 			err = dev_hard_header(skb, dev, ntohs(skb->protocol),
15481da177e4SLinus Torvalds 					      neigh->ha, NULL, skb->len);
15490ed8ddf4SEric Dumazet 		} while (read_seqretry(&neigh->ha_lock, seq));
155034d101ddSEric Dumazet 
15511da177e4SLinus Torvalds 		if (err >= 0)
1552542d4d68SDavid S. Miller 			rc = dev_queue_xmit(skb);
15531da177e4SLinus Torvalds 		else
15541da177e4SLinus Torvalds 			goto out_kfree_skb;
15551da177e4SLinus Torvalds 	}
15561da177e4SLinus Torvalds out:
15571da177e4SLinus Torvalds 	return rc;
15581da177e4SLinus Torvalds out_kfree_skb:
15591da177e4SLinus Torvalds 	rc = -EINVAL;
15601da177e4SLinus Torvalds 	kfree_skb(skb);
15611da177e4SLinus Torvalds 	goto out;
15621da177e4SLinus Torvalds }
15630a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_resolve_output);
15641da177e4SLinus Torvalds 
15651da177e4SLinus Torvalds /* As fast as possible without hh cache */
15661da177e4SLinus Torvalds 
15678f40b161SDavid S. Miller int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
15681da177e4SLinus Torvalds {
15691da177e4SLinus Torvalds 	struct net_device *dev = neigh->dev;
15700ed8ddf4SEric Dumazet 	unsigned int seq;
15718f40b161SDavid S. Miller 	int err;
15721da177e4SLinus Torvalds 
15730ed8ddf4SEric Dumazet 	do {
1574e1f16503Sramesh.nagappa@gmail.com 		__skb_pull(skb, skb_network_offset(skb));
15750ed8ddf4SEric Dumazet 		seq = read_seqbegin(&neigh->ha_lock);
15760c4e8581SStephen Hemminger 		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
15771da177e4SLinus Torvalds 				      neigh->ha, NULL, skb->len);
15780ed8ddf4SEric Dumazet 	} while (read_seqretry(&neigh->ha_lock, seq));
15790ed8ddf4SEric Dumazet 
15801da177e4SLinus Torvalds 	if (err >= 0)
1581542d4d68SDavid S. Miller 		err = dev_queue_xmit(skb);
15821da177e4SLinus Torvalds 	else {
15831da177e4SLinus Torvalds 		err = -EINVAL;
15841da177e4SLinus Torvalds 		kfree_skb(skb);
15851da177e4SLinus Torvalds 	}
15861da177e4SLinus Torvalds 	return err;
15871da177e4SLinus Torvalds }
15880a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_connected_output);
15891da177e4SLinus Torvalds 
15908f40b161SDavid S. Miller int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
15918f40b161SDavid S. Miller {
15928f40b161SDavid S. Miller 	return dev_queue_xmit(skb);
15938f40b161SDavid S. Miller }
15948f40b161SDavid S. Miller EXPORT_SYMBOL(neigh_direct_output);
15958f40b161SDavid S. Miller 
15967482e384SDaniel Borkmann static void neigh_managed_work(struct work_struct *work)
15977482e384SDaniel Borkmann {
15987482e384SDaniel Borkmann 	struct neigh_table *tbl = container_of(work, struct neigh_table,
15997482e384SDaniel Borkmann 					       managed_work.work);
16007482e384SDaniel Borkmann 	struct neighbour *neigh;
16017482e384SDaniel Borkmann 
16027482e384SDaniel Borkmann 	write_lock_bh(&tbl->lock);
16037482e384SDaniel Borkmann 	list_for_each_entry(neigh, &tbl->managed_list, managed_list)
16044a81f6daSDaniel Borkmann 		neigh_event_send_probe(neigh, NULL, false);
16057482e384SDaniel Borkmann 	queue_delayed_work(system_power_efficient_wq, &tbl->managed_work,
1606211da42eSYuwei Wang 			   NEIGH_VAR(&tbl->parms, INTERVAL_PROBE_TIME_MS));
16077482e384SDaniel Borkmann 	write_unlock_bh(&tbl->lock);
16087482e384SDaniel Borkmann }
16097482e384SDaniel Borkmann 
1610e99e88a9SKees Cook static void neigh_proxy_process(struct timer_list *t)
16111da177e4SLinus Torvalds {
1612e99e88a9SKees Cook 	struct neigh_table *tbl = from_timer(tbl, t, proxy_timer);
16131da177e4SLinus Torvalds 	long sched_next = 0;
16141da177e4SLinus Torvalds 	unsigned long now = jiffies;
1615f72051b0SDavid S. Miller 	struct sk_buff *skb, *n;
16161da177e4SLinus Torvalds 
16171da177e4SLinus Torvalds 	spin_lock(&tbl->proxy_queue.lock);
16181da177e4SLinus Torvalds 
1619f72051b0SDavid S. Miller 	skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1620f72051b0SDavid S. Miller 		long tdif = NEIGH_CB(skb)->sched_next - now;
16211da177e4SLinus Torvalds 
16221da177e4SLinus Torvalds 		if (tdif <= 0) {
1623f72051b0SDavid S. Miller 			struct net_device *dev = skb->dev;
162420e6074eSEric Dumazet 
16258207f253SThomas Zeitlhofer 			neigh_parms_qlen_dec(dev, tbl->family);
1626f72051b0SDavid S. Miller 			__skb_unlink(skb, &tbl->proxy_queue);
16270ff4eb3dSAlexander Mikhalitsyn 
162820e6074eSEric Dumazet 			if (tbl->proxy_redo && netif_running(dev)) {
162920e6074eSEric Dumazet 				rcu_read_lock();
1630f72051b0SDavid S. Miller 				tbl->proxy_redo(skb);
163120e6074eSEric Dumazet 				rcu_read_unlock();
163220e6074eSEric Dumazet 			} else {
1633f72051b0SDavid S. Miller 				kfree_skb(skb);
163420e6074eSEric Dumazet 			}
16351da177e4SLinus Torvalds 
16361da177e4SLinus Torvalds 			dev_put(dev);
16371da177e4SLinus Torvalds 		} else if (!sched_next || tdif < sched_next)
16381da177e4SLinus Torvalds 			sched_next = tdif;
16391da177e4SLinus Torvalds 	}
16401da177e4SLinus Torvalds 	del_timer(&tbl->proxy_timer);
16411da177e4SLinus Torvalds 	if (sched_next)
16421da177e4SLinus Torvalds 		mod_timer(&tbl->proxy_timer, jiffies + sched_next);
16431da177e4SLinus Torvalds 	spin_unlock(&tbl->proxy_queue.lock);
16441da177e4SLinus Torvalds }
16451da177e4SLinus Torvalds 
164662e395f8SBrian Haley static unsigned long neigh_proxy_delay(struct neigh_parms *p)
164762e395f8SBrian Haley {
164862e395f8SBrian Haley 	/* If proxy_delay is zero, do not call get_random_u32_below()
164962e395f8SBrian Haley 	 * as it is undefined behavior.
165062e395f8SBrian Haley 	 */
165162e395f8SBrian Haley 	unsigned long proxy_delay = NEIGH_VAR(p, PROXY_DELAY);
165262e395f8SBrian Haley 
165362e395f8SBrian Haley 	return proxy_delay ?
165462e395f8SBrian Haley 	       jiffies + get_random_u32_below(proxy_delay) : jiffies;
165562e395f8SBrian Haley }
165662e395f8SBrian Haley 
16571da177e4SLinus Torvalds void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
16581da177e4SLinus Torvalds 		    struct sk_buff *skb)
16591da177e4SLinus Torvalds {
166062e395f8SBrian Haley 	unsigned long sched_next = neigh_proxy_delay(p);
16611da177e4SLinus Torvalds 
16620ff4eb3dSAlexander Mikhalitsyn 	if (p->qlen > NEIGH_VAR(p, PROXY_QLEN)) {
16631da177e4SLinus Torvalds 		kfree_skb(skb);
16641da177e4SLinus Torvalds 		return;
16651da177e4SLinus Torvalds 	}
1666a61bbcf2SPatrick McHardy 
1667a61bbcf2SPatrick McHardy 	NEIGH_CB(skb)->sched_next = sched_next;
1668a61bbcf2SPatrick McHardy 	NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
16691da177e4SLinus Torvalds 
16701da177e4SLinus Torvalds 	spin_lock(&tbl->proxy_queue.lock);
16711da177e4SLinus Torvalds 	if (del_timer(&tbl->proxy_timer)) {
16721da177e4SLinus Torvalds 		if (time_before(tbl->proxy_timer.expires, sched_next))
16731da177e4SLinus Torvalds 			sched_next = tbl->proxy_timer.expires;
16741da177e4SLinus Torvalds 	}
1675adf30907SEric Dumazet 	skb_dst_drop(skb);
16761da177e4SLinus Torvalds 	dev_hold(skb->dev);
16771da177e4SLinus Torvalds 	__skb_queue_tail(&tbl->proxy_queue, skb);
16780ff4eb3dSAlexander Mikhalitsyn 	p->qlen++;
16791da177e4SLinus Torvalds 	mod_timer(&tbl->proxy_timer, sched_next);
16801da177e4SLinus Torvalds 	spin_unlock(&tbl->proxy_queue.lock);
16811da177e4SLinus Torvalds }
16820a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(pneigh_enqueue);
16831da177e4SLinus Torvalds 
168497fd5bc7STobias Klauser static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
1685426b5303SEric W. Biederman 						      struct net *net, int ifindex)
1686426b5303SEric W. Biederman {
1687426b5303SEric W. Biederman 	struct neigh_parms *p;
1688426b5303SEric W. Biederman 
168975fbfd33SNicolas Dichtel 	list_for_each_entry(p, &tbl->parms_list, list) {
1690878628fbSYOSHIFUJI Hideaki 		if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
1691170d6f99SGao feng 		    (!p->dev && !ifindex && net_eq(net, &init_net)))
1692426b5303SEric W. Biederman 			return p;
1693426b5303SEric W. Biederman 	}
1694426b5303SEric W. Biederman 
1695426b5303SEric W. Biederman 	return NULL;
1696426b5303SEric W. Biederman }
16971da177e4SLinus Torvalds 
16981da177e4SLinus Torvalds struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
16991da177e4SLinus Torvalds 				      struct neigh_table *tbl)
17001da177e4SLinus Torvalds {
1701cf89d6b2SGao feng 	struct neigh_parms *p;
170200829823SStephen Hemminger 	struct net *net = dev_net(dev);
170300829823SStephen Hemminger 	const struct net_device_ops *ops = dev->netdev_ops;
17041da177e4SLinus Torvalds 
1705cf89d6b2SGao feng 	p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL);
17061da177e4SLinus Torvalds 	if (p) {
17071da177e4SLinus Torvalds 		p->tbl		  = tbl;
17086343944bSReshetova, Elena 		refcount_set(&p->refcnt, 1);
17091da177e4SLinus Torvalds 		p->reachable_time =
17101f9248e5SJiri Pirko 				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
17110ff4eb3dSAlexander Mikhalitsyn 		p->qlen = 0;
1712d62607c3SJakub Kicinski 		netdev_hold(dev, &p->dev_tracker, GFP_KERNEL);
1713c7fb64dbSThomas Graf 		p->dev = dev;
1714efd7ef1cSEric W. Biederman 		write_pnet(&p->net, net);
17151da177e4SLinus Torvalds 		p->sysctl_table = NULL;
171663134803SVeaceslav Falico 
171763134803SVeaceslav Falico 		if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
1718d62607c3SJakub Kicinski 			netdev_put(dev, &p->dev_tracker);
171963134803SVeaceslav Falico 			kfree(p);
172063134803SVeaceslav Falico 			return NULL;
172163134803SVeaceslav Falico 		}
172263134803SVeaceslav Falico 
17231da177e4SLinus Torvalds 		write_lock_bh(&tbl->lock);
172475fbfd33SNicolas Dichtel 		list_add(&p->list, &tbl->parms.list);
17251da177e4SLinus Torvalds 		write_unlock_bh(&tbl->lock);
17261d4c8c29SJiri Pirko 
17271d4c8c29SJiri Pirko 		neigh_parms_data_state_cleanall(p);
17281da177e4SLinus Torvalds 	}
17291da177e4SLinus Torvalds 	return p;
17301da177e4SLinus Torvalds }
17310a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_parms_alloc);
17321da177e4SLinus Torvalds 
17331da177e4SLinus Torvalds static void neigh_rcu_free_parms(struct rcu_head *head)
17341da177e4SLinus Torvalds {
17351da177e4SLinus Torvalds 	struct neigh_parms *parms =
17361da177e4SLinus Torvalds 		container_of(head, struct neigh_parms, rcu_head);
17371da177e4SLinus Torvalds 
17381da177e4SLinus Torvalds 	neigh_parms_put(parms);
17391da177e4SLinus Torvalds }
17401da177e4SLinus Torvalds 
17411da177e4SLinus Torvalds void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
17421da177e4SLinus Torvalds {
17431da177e4SLinus Torvalds 	if (!parms || parms == &tbl->parms)
17441da177e4SLinus Torvalds 		return;
17451da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
174675fbfd33SNicolas Dichtel 	list_del(&parms->list);
17471da177e4SLinus Torvalds 	parms->dead = 1;
17481da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
1749d62607c3SJakub Kicinski 	netdev_put(parms->dev, &parms->dev_tracker);
17501da177e4SLinus Torvalds 	call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
17511da177e4SLinus Torvalds }
17520a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_parms_release);
17531da177e4SLinus Torvalds 
175406f0511dSDenis V. Lunev static void neigh_parms_destroy(struct neigh_parms *parms)
17551da177e4SLinus Torvalds {
17561da177e4SLinus Torvalds 	kfree(parms);
17571da177e4SLinus Torvalds }
17581da177e4SLinus Torvalds 
1759c2ecba71SPavel Emelianov static struct lock_class_key neigh_table_proxy_queue_class;
1760c2ecba71SPavel Emelianov 
1761d7480fd3SWANG Cong static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly;
1762d7480fd3SWANG Cong 
1763d7480fd3SWANG Cong void neigh_table_init(int index, struct neigh_table *tbl)
17641da177e4SLinus Torvalds {
17651da177e4SLinus Torvalds 	unsigned long now = jiffies;
17661da177e4SLinus Torvalds 	unsigned long phsize;
17671da177e4SLinus Torvalds 
176875fbfd33SNicolas Dichtel 	INIT_LIST_HEAD(&tbl->parms_list);
176958956317SDavid Ahern 	INIT_LIST_HEAD(&tbl->gc_list);
17707482e384SDaniel Borkmann 	INIT_LIST_HEAD(&tbl->managed_list);
17717482e384SDaniel Borkmann 
177275fbfd33SNicolas Dichtel 	list_add(&tbl->parms.list, &tbl->parms_list);
1773e42ea986SEric Dumazet 	write_pnet(&tbl->parms.net, &init_net);
17746343944bSReshetova, Elena 	refcount_set(&tbl->parms.refcnt, 1);
17751da177e4SLinus Torvalds 	tbl->parms.reachable_time =
17761f9248e5SJiri Pirko 			  neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME));
17770ff4eb3dSAlexander Mikhalitsyn 	tbl->parms.qlen = 0;
17781da177e4SLinus Torvalds 
17791da177e4SLinus Torvalds 	tbl->stats = alloc_percpu(struct neigh_statistics);
17801da177e4SLinus Torvalds 	if (!tbl->stats)
17811da177e4SLinus Torvalds 		panic("cannot create neighbour cache statistics");
17821da177e4SLinus Torvalds 
17831da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
178471a5053aSChristoph Hellwig 	if (!proc_create_seq_data(tbl->id, 0, init_net.proc_net_stat,
178571a5053aSChristoph Hellwig 			      &neigh_stat_seq_ops, tbl))
17861da177e4SLinus Torvalds 		panic("cannot create neighbour proc dir entry");
17871da177e4SLinus Torvalds #endif
17881da177e4SLinus Torvalds 
1789cd089336SDavid S. Miller 	RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
17901da177e4SLinus Torvalds 
17911da177e4SLinus Torvalds 	phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
179277d04bd9SAndrew Morton 	tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
17931da177e4SLinus Torvalds 
1794d6bf7817SEric Dumazet 	if (!tbl->nht || !tbl->phash_buckets)
17951da177e4SLinus Torvalds 		panic("cannot allocate neighbour cache hashes");
17961da177e4SLinus Torvalds 
179708433effSYOSHIFUJI Hideaki / 吉藤英明 	if (!tbl->entry_size)
179808433effSYOSHIFUJI Hideaki / 吉藤英明 		tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
179908433effSYOSHIFUJI Hideaki / 吉藤英明 					tbl->key_len, NEIGH_PRIV_ALIGN);
180008433effSYOSHIFUJI Hideaki / 吉藤英明 	else
180108433effSYOSHIFUJI Hideaki / 吉藤英明 		WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
180208433effSYOSHIFUJI Hideaki / 吉藤英明 
18031da177e4SLinus Torvalds 	rwlock_init(&tbl->lock);
18047482e384SDaniel Borkmann 
1805203b42f7STejun Heo 	INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
1806f618002bSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
1807f618002bSviresh kumar 			tbl->parms.reachable_time);
18087482e384SDaniel Borkmann 	INIT_DEFERRABLE_WORK(&tbl->managed_work, neigh_managed_work);
18097482e384SDaniel Borkmann 	queue_delayed_work(system_power_efficient_wq, &tbl->managed_work, 0);
18107482e384SDaniel Borkmann 
1811e99e88a9SKees Cook 	timer_setup(&tbl->proxy_timer, neigh_proxy_process, 0);
1812c2ecba71SPavel Emelianov 	skb_queue_head_init_class(&tbl->proxy_queue,
1813c2ecba71SPavel Emelianov 			&neigh_table_proxy_queue_class);
18141da177e4SLinus Torvalds 
18151da177e4SLinus Torvalds 	tbl->last_flush = now;
18161da177e4SLinus Torvalds 	tbl->last_rand	= now + tbl->parms.reachable_time * 20;
1817bd89efc5SSimon Kelley 
1818d7480fd3SWANG Cong 	neigh_tables[index] = tbl;
18191da177e4SLinus Torvalds }
18200a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_table_init);
18211da177e4SLinus Torvalds 
1822d7480fd3SWANG Cong int neigh_table_clear(int index, struct neigh_table *tbl)
18231da177e4SLinus Torvalds {
1824d7480fd3SWANG Cong 	neigh_tables[index] = NULL;
18251da177e4SLinus Torvalds 	/* It is not clean... Fix it to unload IPv6 module safely */
18264177d5b0SDaniel Borkmann 	cancel_delayed_work_sync(&tbl->managed_work);
1827a5c30b34STejun Heo 	cancel_delayed_work_sync(&tbl->gc_work);
18281da177e4SLinus Torvalds 	del_timer_sync(&tbl->proxy_timer);
18298207f253SThomas Zeitlhofer 	pneigh_queue_purge(&tbl->proxy_queue, NULL, tbl->family);
18301da177e4SLinus Torvalds 	neigh_ifdown(tbl, NULL);
18311da177e4SLinus Torvalds 	if (atomic_read(&tbl->entries))
1832e005d193SJoe Perches 		pr_crit("neighbour leakage\n");
18331da177e4SLinus Torvalds 
18346193d2beSEric Dumazet 	call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
18356193d2beSEric Dumazet 		 neigh_hash_free_rcu);
1836d6bf7817SEric Dumazet 	tbl->nht = NULL;
18371da177e4SLinus Torvalds 
18381da177e4SLinus Torvalds 	kfree(tbl->phash_buckets);
18391da177e4SLinus Torvalds 	tbl->phash_buckets = NULL;
18401da177e4SLinus Torvalds 
18413f192b5cSAlexey Dobriyan 	remove_proc_entry(tbl->id, init_net.proc_net_stat);
18423f192b5cSAlexey Dobriyan 
18433fcde74bSKirill Korotaev 	free_percpu(tbl->stats);
18443fcde74bSKirill Korotaev 	tbl->stats = NULL;
18453fcde74bSKirill Korotaev 
18461da177e4SLinus Torvalds 	return 0;
18471da177e4SLinus Torvalds }
18480a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_table_clear);
18491da177e4SLinus Torvalds 
1850d7480fd3SWANG Cong static struct neigh_table *neigh_find_table(int family)
1851d7480fd3SWANG Cong {
1852d7480fd3SWANG Cong 	struct neigh_table *tbl = NULL;
1853d7480fd3SWANG Cong 
1854d7480fd3SWANG Cong 	switch (family) {
1855d7480fd3SWANG Cong 	case AF_INET:
1856d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_ARP_TABLE];
1857d7480fd3SWANG Cong 		break;
1858d7480fd3SWANG Cong 	case AF_INET6:
1859d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_ND_TABLE];
1860d7480fd3SWANG Cong 		break;
1861d7480fd3SWANG Cong 	}
1862d7480fd3SWANG Cong 
1863d7480fd3SWANG Cong 	return tbl;
1864d7480fd3SWANG Cong }
1865d7480fd3SWANG Cong 
186682cbb5c6SRoopa Prabhu const struct nla_policy nda_policy[NDA_MAX+1] = {
18671274e1ccSRoopa Prabhu 	[NDA_UNSPEC]		= { .strict_start_type = NDA_NH_ID },
186882cbb5c6SRoopa Prabhu 	[NDA_DST]		= { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
186982cbb5c6SRoopa Prabhu 	[NDA_LLADDR]		= { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
187082cbb5c6SRoopa Prabhu 	[NDA_CACHEINFO]		= { .len = sizeof(struct nda_cacheinfo) },
187182cbb5c6SRoopa Prabhu 	[NDA_PROBES]		= { .type = NLA_U32 },
187282cbb5c6SRoopa Prabhu 	[NDA_VLAN]		= { .type = NLA_U16 },
187382cbb5c6SRoopa Prabhu 	[NDA_PORT]		= { .type = NLA_U16 },
187482cbb5c6SRoopa Prabhu 	[NDA_VNI]		= { .type = NLA_U32 },
187582cbb5c6SRoopa Prabhu 	[NDA_IFINDEX]		= { .type = NLA_U32 },
187682cbb5c6SRoopa Prabhu 	[NDA_MASTER]		= { .type = NLA_U32 },
1877a9cd3439SDavid Ahern 	[NDA_PROTOCOL]		= { .type = NLA_U8 },
18781274e1ccSRoopa Prabhu 	[NDA_NH_ID]		= { .type = NLA_U32 },
1879c8e80c11SDaniel Borkmann 	[NDA_FLAGS_EXT]		= NLA_POLICY_MASK(NLA_U32, NTF_EXT_MASK),
1880899426b3SNikolay Aleksandrov 	[NDA_FDB_EXT_ATTRS]	= { .type = NLA_NESTED },
188182cbb5c6SRoopa Prabhu };
188282cbb5c6SRoopa Prabhu 
1883c21ef3e3SDavid Ahern static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
1884c21ef3e3SDavid Ahern 			struct netlink_ext_ack *extack)
18851da177e4SLinus Torvalds {
18863b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
1887a14a49d2SThomas Graf 	struct ndmsg *ndm;
1888a14a49d2SThomas Graf 	struct nlattr *dst_attr;
18891da177e4SLinus Torvalds 	struct neigh_table *tbl;
1890d7480fd3SWANG Cong 	struct neighbour *neigh;
18911da177e4SLinus Torvalds 	struct net_device *dev = NULL;
1892a14a49d2SThomas Graf 	int err = -EINVAL;
18931da177e4SLinus Torvalds 
1894110b2499SEric Dumazet 	ASSERT_RTNL();
1895a14a49d2SThomas Graf 	if (nlmsg_len(nlh) < sizeof(*ndm))
18961da177e4SLinus Torvalds 		goto out;
18971da177e4SLinus Torvalds 
1898a14a49d2SThomas Graf 	dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
18997a35a50dSDavid Ahern 	if (!dst_attr) {
19007a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Network address not specified");
1901a14a49d2SThomas Graf 		goto out;
19027a35a50dSDavid Ahern 	}
1903a14a49d2SThomas Graf 
1904a14a49d2SThomas Graf 	ndm = nlmsg_data(nlh);
1905a14a49d2SThomas Graf 	if (ndm->ndm_ifindex) {
1906110b2499SEric Dumazet 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
1907a14a49d2SThomas Graf 		if (dev == NULL) {
1908a14a49d2SThomas Graf 			err = -ENODEV;
1909a14a49d2SThomas Graf 			goto out;
1910a14a49d2SThomas Graf 		}
1911a14a49d2SThomas Graf 	}
1912a14a49d2SThomas Graf 
1913d7480fd3SWANG Cong 	tbl = neigh_find_table(ndm->ndm_family);
1914d7480fd3SWANG Cong 	if (tbl == NULL)
1915d7480fd3SWANG Cong 		return -EAFNOSUPPORT;
19161da177e4SLinus Torvalds 
19177a35a50dSDavid Ahern 	if (nla_len(dst_attr) < (int)tbl->key_len) {
19187a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid network address");
1919110b2499SEric Dumazet 		goto out;
19207a35a50dSDavid Ahern 	}
19211da177e4SLinus Torvalds 
19221da177e4SLinus Torvalds 	if (ndm->ndm_flags & NTF_PROXY) {
1923426b5303SEric W. Biederman 		err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
1924110b2499SEric Dumazet 		goto out;
19251da177e4SLinus Torvalds 	}
19261da177e4SLinus Torvalds 
1927a14a49d2SThomas Graf 	if (dev == NULL)
1928110b2499SEric Dumazet 		goto out;
19291da177e4SLinus Torvalds 
1930a14a49d2SThomas Graf 	neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1931a14a49d2SThomas Graf 	if (neigh == NULL) {
1932a14a49d2SThomas Graf 		err = -ENOENT;
1933110b2499SEric Dumazet 		goto out;
1934a14a49d2SThomas Graf 	}
1935a14a49d2SThomas Graf 
19367a35a50dSDavid Ahern 	err = __neigh_update(neigh, NULL, NUD_FAILED,
19377a35a50dSDavid Ahern 			     NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN,
19387a35a50dSDavid Ahern 			     NETLINK_CB(skb).portid, extack);
19395071034eSSowmini Varadhan 	write_lock_bh(&tbl->lock);
1940a14a49d2SThomas Graf 	neigh_release(neigh);
19415071034eSSowmini Varadhan 	neigh_remove_one(neigh, tbl);
19425071034eSSowmini Varadhan 	write_unlock_bh(&tbl->lock);
1943a14a49d2SThomas Graf 
19441da177e4SLinus Torvalds out:
19451da177e4SLinus Torvalds 	return err;
19461da177e4SLinus Torvalds }
19471da177e4SLinus Torvalds 
1948c21ef3e3SDavid Ahern static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
1949c21ef3e3SDavid Ahern 		     struct netlink_ext_ack *extack)
19501da177e4SLinus Torvalds {
1951f7aa74e4SRoopa Prabhu 	int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE |
1952f7aa74e4SRoopa Prabhu 		    NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
19533b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
19545208debdSThomas Graf 	struct ndmsg *ndm;
19555208debdSThomas Graf 	struct nlattr *tb[NDA_MAX+1];
19561da177e4SLinus Torvalds 	struct neigh_table *tbl;
19571da177e4SLinus Torvalds 	struct net_device *dev = NULL;
1958d7480fd3SWANG Cong 	struct neighbour *neigh;
1959d7480fd3SWANG Cong 	void *dst, *lladdr;
1960df9b0e30SDavid Ahern 	u8 protocol = 0;
19612c611ad9SRoopa Prabhu 	u32 ndm_flags;
19625208debdSThomas Graf 	int err;
19631da177e4SLinus Torvalds 
1964110b2499SEric Dumazet 	ASSERT_RTNL();
19658cb08174SJohannes Berg 	err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX,
19668cb08174SJohannes Berg 				     nda_policy, extack);
19675208debdSThomas Graf 	if (err < 0)
19681da177e4SLinus Torvalds 		goto out;
19691da177e4SLinus Torvalds 
19705208debdSThomas Graf 	err = -EINVAL;
19717a35a50dSDavid Ahern 	if (!tb[NDA_DST]) {
19727a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Network address not specified");
19735208debdSThomas Graf 		goto out;
19747a35a50dSDavid Ahern 	}
19755208debdSThomas Graf 
19765208debdSThomas Graf 	ndm = nlmsg_data(nlh);
19772c611ad9SRoopa Prabhu 	ndm_flags = ndm->ndm_flags;
19782c611ad9SRoopa Prabhu 	if (tb[NDA_FLAGS_EXT]) {
19792c611ad9SRoopa Prabhu 		u32 ext = nla_get_u32(tb[NDA_FLAGS_EXT]);
19802c611ad9SRoopa Prabhu 
1981507c2f1dSDaniel Borkmann 		BUILD_BUG_ON(sizeof(neigh->flags) * BITS_PER_BYTE <
1982507c2f1dSDaniel Borkmann 			     (sizeof(ndm->ndm_flags) * BITS_PER_BYTE +
1983507c2f1dSDaniel Borkmann 			      hweight32(NTF_EXT_MASK)));
19842c611ad9SRoopa Prabhu 		ndm_flags |= (ext << NTF_EXT_SHIFT);
19852c611ad9SRoopa Prabhu 	}
19865208debdSThomas Graf 	if (ndm->ndm_ifindex) {
1987110b2499SEric Dumazet 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
19885208debdSThomas Graf 		if (dev == NULL) {
19895208debdSThomas Graf 			err = -ENODEV;
19905208debdSThomas Graf 			goto out;
19915208debdSThomas Graf 		}
19925208debdSThomas Graf 
19937a35a50dSDavid Ahern 		if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) {
19947a35a50dSDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid link address");
1995110b2499SEric Dumazet 			goto out;
19965208debdSThomas Graf 		}
19977a35a50dSDavid Ahern 	}
19985208debdSThomas Graf 
1999d7480fd3SWANG Cong 	tbl = neigh_find_table(ndm->ndm_family);
2000d7480fd3SWANG Cong 	if (tbl == NULL)
2001d7480fd3SWANG Cong 		return -EAFNOSUPPORT;
20021da177e4SLinus Torvalds 
20037a35a50dSDavid Ahern 	if (nla_len(tb[NDA_DST]) < (int)tbl->key_len) {
20047a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid network address");
2005110b2499SEric Dumazet 		goto out;
20067a35a50dSDavid Ahern 	}
20077a35a50dSDavid Ahern 
20085208debdSThomas Graf 	dst = nla_data(tb[NDA_DST]);
20095208debdSThomas Graf 	lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
20101da177e4SLinus Torvalds 
2011a9cd3439SDavid Ahern 	if (tb[NDA_PROTOCOL])
2012df9b0e30SDavid Ahern 		protocol = nla_get_u8(tb[NDA_PROTOCOL]);
20132c611ad9SRoopa Prabhu 	if (ndm_flags & NTF_PROXY) {
201462dd9318SVille Nuorvala 		struct pneigh_entry *pn;
201562dd9318SVille Nuorvala 
20167482e384SDaniel Borkmann 		if (ndm_flags & NTF_MANAGED) {
20177482e384SDaniel Borkmann 			NL_SET_ERR_MSG(extack, "Invalid NTF_* flag combination");
20187482e384SDaniel Borkmann 			goto out;
20197482e384SDaniel Borkmann 		}
20207482e384SDaniel Borkmann 
20215208debdSThomas Graf 		err = -ENOBUFS;
2022426b5303SEric W. Biederman 		pn = pneigh_lookup(tbl, net, dst, dev, 1);
202362dd9318SVille Nuorvala 		if (pn) {
20242c611ad9SRoopa Prabhu 			pn->flags = ndm_flags;
2025df9b0e30SDavid Ahern 			if (protocol)
2026df9b0e30SDavid Ahern 				pn->protocol = protocol;
202762dd9318SVille Nuorvala 			err = 0;
202862dd9318SVille Nuorvala 		}
2029110b2499SEric Dumazet 		goto out;
20301da177e4SLinus Torvalds 	}
20311da177e4SLinus Torvalds 
20327a35a50dSDavid Ahern 	if (!dev) {
20337a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Device not specified");
2034110b2499SEric Dumazet 		goto out;
20357a35a50dSDavid Ahern 	}
20361da177e4SLinus Torvalds 
2037b8fb1ab4SDavid Ahern 	if (tbl->allow_add && !tbl->allow_add(dev, extack)) {
2038b8fb1ab4SDavid Ahern 		err = -EINVAL;
2039b8fb1ab4SDavid Ahern 		goto out;
2040b8fb1ab4SDavid Ahern 	}
2041b8fb1ab4SDavid Ahern 
20425208debdSThomas Graf 	neigh = neigh_lookup(tbl, dst, dev);
20435208debdSThomas Graf 	if (neigh == NULL) {
204430fc7efaSDaniel Borkmann 		bool ndm_permanent  = ndm->ndm_state & NUD_PERMANENT;
204530fc7efaSDaniel Borkmann 		bool exempt_from_gc = ndm_permanent ||
204630fc7efaSDaniel Borkmann 				      ndm_flags & NTF_EXT_LEARNED;
2047e997f8a2SDavid Ahern 
20485208debdSThomas Graf 		if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
20491da177e4SLinus Torvalds 			err = -ENOENT;
2050110b2499SEric Dumazet 			goto out;
20515208debdSThomas Graf 		}
205230fc7efaSDaniel Borkmann 		if (ndm_permanent && (ndm_flags & NTF_MANAGED)) {
205330fc7efaSDaniel Borkmann 			NL_SET_ERR_MSG(extack, "Invalid NTF_* flag for permanent entry");
205430fc7efaSDaniel Borkmann 			err = -EINVAL;
205530fc7efaSDaniel Borkmann 			goto out;
205630fc7efaSDaniel Borkmann 		}
20575208debdSThomas Graf 
2058e4400bbfSDaniel Borkmann 		neigh = ___neigh_create(tbl, dst, dev,
20597482e384SDaniel Borkmann 					ndm_flags &
20607482e384SDaniel Borkmann 					(NTF_EXT_LEARNED | NTF_MANAGED),
2061e4400bbfSDaniel Borkmann 					exempt_from_gc, true);
20625208debdSThomas Graf 		if (IS_ERR(neigh)) {
20635208debdSThomas Graf 			err = PTR_ERR(neigh);
2064110b2499SEric Dumazet 			goto out;
20651da177e4SLinus Torvalds 		}
20665208debdSThomas Graf 	} else {
20675208debdSThomas Graf 		if (nlh->nlmsg_flags & NLM_F_EXCL) {
20685208debdSThomas Graf 			err = -EEXIST;
20695208debdSThomas Graf 			neigh_release(neigh);
2070110b2499SEric Dumazet 			goto out;
20711da177e4SLinus Torvalds 		}
20721da177e4SLinus Torvalds 
20735208debdSThomas Graf 		if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
2074f7aa74e4SRoopa Prabhu 			flags &= ~(NEIGH_UPDATE_F_OVERRIDE |
2075f7aa74e4SRoopa Prabhu 				   NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
20765208debdSThomas Graf 	}
20771da177e4SLinus Torvalds 
207838212bb3SRoman Mashak 	if (protocol)
207938212bb3SRoman Mashak 		neigh->protocol = protocol;
20802c611ad9SRoopa Prabhu 	if (ndm_flags & NTF_EXT_LEARNED)
20819ce33e46SRoopa Prabhu 		flags |= NEIGH_UPDATE_F_EXT_LEARNED;
20822c611ad9SRoopa Prabhu 	if (ndm_flags & NTF_ROUTER)
2083f7aa74e4SRoopa Prabhu 		flags |= NEIGH_UPDATE_F_ISROUTER;
20847482e384SDaniel Borkmann 	if (ndm_flags & NTF_MANAGED)
20857482e384SDaniel Borkmann 		flags |= NEIGH_UPDATE_F_MANAGED;
20862c611ad9SRoopa Prabhu 	if (ndm_flags & NTF_USE)
20873dc20f47SDaniel Borkmann 		flags |= NEIGH_UPDATE_F_USE;
2088f7aa74e4SRoopa Prabhu 
20897a35a50dSDavid Ahern 	err = __neigh_update(neigh, lladdr, ndm->ndm_state, flags,
20907a35a50dSDavid Ahern 			     NETLINK_CB(skb).portid, extack);
20917482e384SDaniel Borkmann 	if (!err && ndm_flags & (NTF_USE | NTF_MANAGED)) {
20923dc20f47SDaniel Borkmann 		neigh_event_send(neigh, NULL);
20933dc20f47SDaniel Borkmann 		err = 0;
20943dc20f47SDaniel Borkmann 	}
20955208debdSThomas Graf 	neigh_release(neigh);
20961da177e4SLinus Torvalds out:
20971da177e4SLinus Torvalds 	return err;
20981da177e4SLinus Torvalds }
20991da177e4SLinus Torvalds 
2100c7fb64dbSThomas Graf static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
2101c7fb64dbSThomas Graf {
2102ca860fb3SThomas Graf 	struct nlattr *nest;
2103e386c6ebSThomas Graf 
2104ae0be8deSMichal Kubecek 	nest = nla_nest_start_noflag(skb, NDTA_PARMS);
2105ca860fb3SThomas Graf 	if (nest == NULL)
2106ca860fb3SThomas Graf 		return -ENOBUFS;
2107c7fb64dbSThomas Graf 
21089a6308d7SDavid S. Miller 	if ((parms->dev &&
21099a6308d7SDavid S. Miller 	     nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
21106343944bSReshetova, Elena 	    nla_put_u32(skb, NDTPA_REFCNT, refcount_read(&parms->refcnt)) ||
21111f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_QUEUE_LENBYTES,
21121f9248e5SJiri Pirko 			NEIGH_VAR(parms, QUEUE_LEN_BYTES)) ||
21138b5c171bSEric Dumazet 	    /* approximative value for deprecated QUEUE_LEN (in packets) */
21149a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTPA_QUEUE_LEN,
21151f9248e5SJiri Pirko 			NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) ||
21161f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) ||
21171f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) ||
21181f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_UCAST_PROBES,
21191f9248e5SJiri Pirko 			NEIGH_VAR(parms, UCAST_PROBES)) ||
21201f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_MCAST_PROBES,
21211f9248e5SJiri Pirko 			NEIGH_VAR(parms, MCAST_PROBES)) ||
21228da86466SYOSHIFUJI Hideaki/吉藤英明 	    nla_put_u32(skb, NDTPA_MCAST_REPROBES,
21238da86466SYOSHIFUJI Hideaki/吉藤英明 			NEIGH_VAR(parms, MCAST_REPROBES)) ||
21242175d87cSNicolas Dichtel 	    nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time,
21252175d87cSNicolas Dichtel 			  NDTPA_PAD) ||
21269a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
21272175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, BASE_REACHABLE_TIME), NDTPA_PAD) ||
21281f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_GC_STALETIME,
21292175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, GC_STALETIME), NDTPA_PAD) ||
21309a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
21312175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, DELAY_PROBE_TIME), NDTPA_PAD) ||
21321f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_RETRANS_TIME,
21332175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, RETRANS_TIME), NDTPA_PAD) ||
21341f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_ANYCAST_DELAY,
21352175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, ANYCAST_DELAY), NDTPA_PAD) ||
21361f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_PROXY_DELAY,
21372175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, PROXY_DELAY), NDTPA_PAD) ||
21381f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_LOCKTIME,
2139211da42eSYuwei Wang 			  NEIGH_VAR(parms, LOCKTIME), NDTPA_PAD) ||
2140211da42eSYuwei Wang 	    nla_put_msecs(skb, NDTPA_INTERVAL_PROBE_TIME_MS,
2141211da42eSYuwei Wang 			  NEIGH_VAR(parms, INTERVAL_PROBE_TIME_MS), NDTPA_PAD))
21429a6308d7SDavid S. Miller 		goto nla_put_failure;
2143ca860fb3SThomas Graf 	return nla_nest_end(skb, nest);
2144c7fb64dbSThomas Graf 
2145ca860fb3SThomas Graf nla_put_failure:
2146bc3ed28cSThomas Graf 	nla_nest_cancel(skb, nest);
2147bc3ed28cSThomas Graf 	return -EMSGSIZE;
2148c7fb64dbSThomas Graf }
2149c7fb64dbSThomas Graf 
2150ca860fb3SThomas Graf static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
2151ca860fb3SThomas Graf 			      u32 pid, u32 seq, int type, int flags)
2152c7fb64dbSThomas Graf {
2153c7fb64dbSThomas Graf 	struct nlmsghdr *nlh;
2154c7fb64dbSThomas Graf 	struct ndtmsg *ndtmsg;
2155c7fb64dbSThomas Graf 
2156ca860fb3SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2157ca860fb3SThomas Graf 	if (nlh == NULL)
215826932566SPatrick McHardy 		return -EMSGSIZE;
2159c7fb64dbSThomas Graf 
2160ca860fb3SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2161c7fb64dbSThomas Graf 
2162c7fb64dbSThomas Graf 	read_lock_bh(&tbl->lock);
2163c7fb64dbSThomas Graf 	ndtmsg->ndtm_family = tbl->family;
21649ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad1   = 0;
21659ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad2   = 0;
2166c7fb64dbSThomas Graf 
21679a6308d7SDavid S. Miller 	if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
21682175d87cSNicolas Dichtel 	    nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval, NDTA_PAD) ||
21699a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
21709a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
21719a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
21729a6308d7SDavid S. Miller 		goto nla_put_failure;
2173c7fb64dbSThomas Graf 	{
2174c7fb64dbSThomas Graf 		unsigned long now = jiffies;
21759d027e3aSEric Dumazet 		long flush_delta = now - tbl->last_flush;
21769d027e3aSEric Dumazet 		long rand_delta = now - tbl->last_rand;
2177d6bf7817SEric Dumazet 		struct neigh_hash_table *nht;
2178c7fb64dbSThomas Graf 		struct ndt_config ndc = {
2179c7fb64dbSThomas Graf 			.ndtc_key_len		= tbl->key_len,
2180c7fb64dbSThomas Graf 			.ndtc_entry_size	= tbl->entry_size,
2181c7fb64dbSThomas Graf 			.ndtc_entries		= atomic_read(&tbl->entries),
2182c7fb64dbSThomas Graf 			.ndtc_last_flush	= jiffies_to_msecs(flush_delta),
2183c7fb64dbSThomas Graf 			.ndtc_last_rand		= jiffies_to_msecs(rand_delta),
2184c7fb64dbSThomas Graf 			.ndtc_proxy_qlen	= tbl->proxy_queue.qlen,
2185c7fb64dbSThomas Graf 		};
2186c7fb64dbSThomas Graf 
2187d6bf7817SEric Dumazet 		rcu_read_lock_bh();
2188d6bf7817SEric Dumazet 		nht = rcu_dereference_bh(tbl->nht);
21892c2aba6cSDavid S. Miller 		ndc.ndtc_hash_rnd = nht->hash_rnd[0];
2190cd089336SDavid S. Miller 		ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
2191d6bf7817SEric Dumazet 		rcu_read_unlock_bh();
2192d6bf7817SEric Dumazet 
21939a6308d7SDavid S. Miller 		if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
21949a6308d7SDavid S. Miller 			goto nla_put_failure;
2195c7fb64dbSThomas Graf 	}
2196c7fb64dbSThomas Graf 
2197c7fb64dbSThomas Graf 	{
2198c7fb64dbSThomas Graf 		int cpu;
2199c7fb64dbSThomas Graf 		struct ndt_stats ndst;
2200c7fb64dbSThomas Graf 
2201c7fb64dbSThomas Graf 		memset(&ndst, 0, sizeof(ndst));
2202c7fb64dbSThomas Graf 
22036f912042SKAMEZAWA Hiroyuki 		for_each_possible_cpu(cpu) {
2204c7fb64dbSThomas Graf 			struct neigh_statistics	*st;
2205c7fb64dbSThomas Graf 
2206c7fb64dbSThomas Graf 			st = per_cpu_ptr(tbl->stats, cpu);
2207c7fb64dbSThomas Graf 			ndst.ndts_allocs		+= st->allocs;
2208c7fb64dbSThomas Graf 			ndst.ndts_destroys		+= st->destroys;
2209c7fb64dbSThomas Graf 			ndst.ndts_hash_grows		+= st->hash_grows;
2210c7fb64dbSThomas Graf 			ndst.ndts_res_failed		+= st->res_failed;
2211c7fb64dbSThomas Graf 			ndst.ndts_lookups		+= st->lookups;
2212c7fb64dbSThomas Graf 			ndst.ndts_hits			+= st->hits;
2213c7fb64dbSThomas Graf 			ndst.ndts_rcv_probes_mcast	+= st->rcv_probes_mcast;
2214c7fb64dbSThomas Graf 			ndst.ndts_rcv_probes_ucast	+= st->rcv_probes_ucast;
2215c7fb64dbSThomas Graf 			ndst.ndts_periodic_gc_runs	+= st->periodic_gc_runs;
2216c7fb64dbSThomas Graf 			ndst.ndts_forced_gc_runs	+= st->forced_gc_runs;
2217fb811395SRick Jones 			ndst.ndts_table_fulls		+= st->table_fulls;
2218c7fb64dbSThomas Graf 		}
2219c7fb64dbSThomas Graf 
2220b676338fSNicolas Dichtel 		if (nla_put_64bit(skb, NDTA_STATS, sizeof(ndst), &ndst,
2221b676338fSNicolas Dichtel 				  NDTA_PAD))
22229a6308d7SDavid S. Miller 			goto nla_put_failure;
2223c7fb64dbSThomas Graf 	}
2224c7fb64dbSThomas Graf 
2225c7fb64dbSThomas Graf 	BUG_ON(tbl->parms.dev);
2226c7fb64dbSThomas Graf 	if (neightbl_fill_parms(skb, &tbl->parms) < 0)
2227ca860fb3SThomas Graf 		goto nla_put_failure;
2228c7fb64dbSThomas Graf 
2229c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
2230053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2231053c095aSJohannes Berg 	return 0;
2232c7fb64dbSThomas Graf 
2233ca860fb3SThomas Graf nla_put_failure:
2234c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
223526932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
223626932566SPatrick McHardy 	return -EMSGSIZE;
2237c7fb64dbSThomas Graf }
2238c7fb64dbSThomas Graf 
2239ca860fb3SThomas Graf static int neightbl_fill_param_info(struct sk_buff *skb,
2240ca860fb3SThomas Graf 				    struct neigh_table *tbl,
2241c7fb64dbSThomas Graf 				    struct neigh_parms *parms,
2242ca860fb3SThomas Graf 				    u32 pid, u32 seq, int type,
2243ca860fb3SThomas Graf 				    unsigned int flags)
2244c7fb64dbSThomas Graf {
2245c7fb64dbSThomas Graf 	struct ndtmsg *ndtmsg;
2246c7fb64dbSThomas Graf 	struct nlmsghdr *nlh;
2247c7fb64dbSThomas Graf 
2248ca860fb3SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2249ca860fb3SThomas Graf 	if (nlh == NULL)
225026932566SPatrick McHardy 		return -EMSGSIZE;
2251c7fb64dbSThomas Graf 
2252ca860fb3SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2253c7fb64dbSThomas Graf 
2254c7fb64dbSThomas Graf 	read_lock_bh(&tbl->lock);
2255c7fb64dbSThomas Graf 	ndtmsg->ndtm_family = tbl->family;
22569ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad1   = 0;
22579ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad2   = 0;
2258c7fb64dbSThomas Graf 
2259ca860fb3SThomas Graf 	if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
2260ca860fb3SThomas Graf 	    neightbl_fill_parms(skb, parms) < 0)
2261ca860fb3SThomas Graf 		goto errout;
2262c7fb64dbSThomas Graf 
2263c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
2264053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2265053c095aSJohannes Berg 	return 0;
2266ca860fb3SThomas Graf errout:
2267c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
226826932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
226926932566SPatrick McHardy 	return -EMSGSIZE;
2270c7fb64dbSThomas Graf }
2271c7fb64dbSThomas Graf 
2272ef7c79edSPatrick McHardy static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
22736b3f8674SThomas Graf 	[NDTA_NAME]		= { .type = NLA_STRING },
22746b3f8674SThomas Graf 	[NDTA_THRESH1]		= { .type = NLA_U32 },
22756b3f8674SThomas Graf 	[NDTA_THRESH2]		= { .type = NLA_U32 },
22766b3f8674SThomas Graf 	[NDTA_THRESH3]		= { .type = NLA_U32 },
22776b3f8674SThomas Graf 	[NDTA_GC_INTERVAL]	= { .type = NLA_U64 },
22786b3f8674SThomas Graf 	[NDTA_PARMS]		= { .type = NLA_NESTED },
22796b3f8674SThomas Graf };
22806b3f8674SThomas Graf 
2281ef7c79edSPatrick McHardy static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
22826b3f8674SThomas Graf 	[NDTPA_IFINDEX]			= { .type = NLA_U32 },
22836b3f8674SThomas Graf 	[NDTPA_QUEUE_LEN]		= { .type = NLA_U32 },
22846b3f8674SThomas Graf 	[NDTPA_PROXY_QLEN]		= { .type = NLA_U32 },
22856b3f8674SThomas Graf 	[NDTPA_APP_PROBES]		= { .type = NLA_U32 },
22866b3f8674SThomas Graf 	[NDTPA_UCAST_PROBES]		= { .type = NLA_U32 },
22876b3f8674SThomas Graf 	[NDTPA_MCAST_PROBES]		= { .type = NLA_U32 },
22888da86466SYOSHIFUJI Hideaki/吉藤英明 	[NDTPA_MCAST_REPROBES]		= { .type = NLA_U32 },
22896b3f8674SThomas Graf 	[NDTPA_BASE_REACHABLE_TIME]	= { .type = NLA_U64 },
22906b3f8674SThomas Graf 	[NDTPA_GC_STALETIME]		= { .type = NLA_U64 },
22916b3f8674SThomas Graf 	[NDTPA_DELAY_PROBE_TIME]	= { .type = NLA_U64 },
22926b3f8674SThomas Graf 	[NDTPA_RETRANS_TIME]		= { .type = NLA_U64 },
22936b3f8674SThomas Graf 	[NDTPA_ANYCAST_DELAY]		= { .type = NLA_U64 },
22946b3f8674SThomas Graf 	[NDTPA_PROXY_DELAY]		= { .type = NLA_U64 },
22956b3f8674SThomas Graf 	[NDTPA_LOCKTIME]		= { .type = NLA_U64 },
2296211da42eSYuwei Wang 	[NDTPA_INTERVAL_PROBE_TIME_MS]	= { .type = NLA_U64, .min = 1 },
22976b3f8674SThomas Graf };
22986b3f8674SThomas Graf 
2299c21ef3e3SDavid Ahern static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
2300c21ef3e3SDavid Ahern 			struct netlink_ext_ack *extack)
2301c7fb64dbSThomas Graf {
23023b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
2303c7fb64dbSThomas Graf 	struct neigh_table *tbl;
23046b3f8674SThomas Graf 	struct ndtmsg *ndtmsg;
23056b3f8674SThomas Graf 	struct nlattr *tb[NDTA_MAX+1];
2306d7480fd3SWANG Cong 	bool found = false;
2307d7480fd3SWANG Cong 	int err, tidx;
2308c7fb64dbSThomas Graf 
23098cb08174SJohannes Berg 	err = nlmsg_parse_deprecated(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
2310c21ef3e3SDavid Ahern 				     nl_neightbl_policy, extack);
23116b3f8674SThomas Graf 	if (err < 0)
23126b3f8674SThomas Graf 		goto errout;
2313c7fb64dbSThomas Graf 
23146b3f8674SThomas Graf 	if (tb[NDTA_NAME] == NULL) {
23156b3f8674SThomas Graf 		err = -EINVAL;
23166b3f8674SThomas Graf 		goto errout;
23176b3f8674SThomas Graf 	}
23186b3f8674SThomas Graf 
23196b3f8674SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2320d7480fd3SWANG Cong 
2321d7480fd3SWANG Cong 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2322d7480fd3SWANG Cong 		tbl = neigh_tables[tidx];
2323d7480fd3SWANG Cong 		if (!tbl)
2324d7480fd3SWANG Cong 			continue;
2325c7fb64dbSThomas Graf 		if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
2326c7fb64dbSThomas Graf 			continue;
2327d7480fd3SWANG Cong 		if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) {
2328d7480fd3SWANG Cong 			found = true;
2329c7fb64dbSThomas Graf 			break;
2330c7fb64dbSThomas Graf 		}
2331c7fb64dbSThomas Graf 	}
2332c7fb64dbSThomas Graf 
2333d7480fd3SWANG Cong 	if (!found)
2334d7480fd3SWANG Cong 		return -ENOENT;
2335d7480fd3SWANG Cong 
2336c7fb64dbSThomas Graf 	/*
2337c7fb64dbSThomas Graf 	 * We acquire tbl->lock to be nice to the periodic timers and
2338c7fb64dbSThomas Graf 	 * make sure they always see a consistent set of values.
2339c7fb64dbSThomas Graf 	 */
2340c7fb64dbSThomas Graf 	write_lock_bh(&tbl->lock);
2341c7fb64dbSThomas Graf 
23426b3f8674SThomas Graf 	if (tb[NDTA_PARMS]) {
23436b3f8674SThomas Graf 		struct nlattr *tbp[NDTPA_MAX+1];
2344c7fb64dbSThomas Graf 		struct neigh_parms *p;
23456b3f8674SThomas Graf 		int i, ifindex = 0;
2346c7fb64dbSThomas Graf 
23478cb08174SJohannes Berg 		err = nla_parse_nested_deprecated(tbp, NDTPA_MAX,
23488cb08174SJohannes Berg 						  tb[NDTA_PARMS],
2349c21ef3e3SDavid Ahern 						  nl_ntbl_parm_policy, extack);
23506b3f8674SThomas Graf 		if (err < 0)
23516b3f8674SThomas Graf 			goto errout_tbl_lock;
2352c7fb64dbSThomas Graf 
23536b3f8674SThomas Graf 		if (tbp[NDTPA_IFINDEX])
23546b3f8674SThomas Graf 			ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
2355c7fb64dbSThomas Graf 
235697fd5bc7STobias Klauser 		p = lookup_neigh_parms(tbl, net, ifindex);
2357c7fb64dbSThomas Graf 		if (p == NULL) {
2358c7fb64dbSThomas Graf 			err = -ENOENT;
23596b3f8674SThomas Graf 			goto errout_tbl_lock;
2360c7fb64dbSThomas Graf 		}
2361c7fb64dbSThomas Graf 
23626b3f8674SThomas Graf 		for (i = 1; i <= NDTPA_MAX; i++) {
23636b3f8674SThomas Graf 			if (tbp[i] == NULL)
23646b3f8674SThomas Graf 				continue;
2365c7fb64dbSThomas Graf 
23666b3f8674SThomas Graf 			switch (i) {
23676b3f8674SThomas Graf 			case NDTPA_QUEUE_LEN:
23681f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
23691f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]) *
23701f9248e5SJiri Pirko 					      SKB_TRUESIZE(ETH_FRAME_LEN));
23718b5c171bSEric Dumazet 				break;
23728b5c171bSEric Dumazet 			case NDTPA_QUEUE_LENBYTES:
23731f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
23741f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23756b3f8674SThomas Graf 				break;
23766b3f8674SThomas Graf 			case NDTPA_PROXY_QLEN:
23771f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, PROXY_QLEN,
23781f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23796b3f8674SThomas Graf 				break;
23806b3f8674SThomas Graf 			case NDTPA_APP_PROBES:
23811f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, APP_PROBES,
23821f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23836b3f8674SThomas Graf 				break;
23846b3f8674SThomas Graf 			case NDTPA_UCAST_PROBES:
23851f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, UCAST_PROBES,
23861f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23876b3f8674SThomas Graf 				break;
23886b3f8674SThomas Graf 			case NDTPA_MCAST_PROBES:
23891f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, MCAST_PROBES,
23901f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23916b3f8674SThomas Graf 				break;
23928da86466SYOSHIFUJI Hideaki/吉藤英明 			case NDTPA_MCAST_REPROBES:
23938da86466SYOSHIFUJI Hideaki/吉藤英明 				NEIGH_VAR_SET(p, MCAST_REPROBES,
23948da86466SYOSHIFUJI Hideaki/吉藤英明 					      nla_get_u32(tbp[i]));
23958da86466SYOSHIFUJI Hideaki/吉藤英明 				break;
23966b3f8674SThomas Graf 			case NDTPA_BASE_REACHABLE_TIME:
23971f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,
23981f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
23994bf6980dSJean-Francois Remy 				/* update reachable_time as well, otherwise, the change will
24004bf6980dSJean-Francois Remy 				 * only be effective after the next time neigh_periodic_work
24014bf6980dSJean-Francois Remy 				 * decides to recompute it (can be multiple minutes)
24024bf6980dSJean-Francois Remy 				 */
24034bf6980dSJean-Francois Remy 				p->reachable_time =
24044bf6980dSJean-Francois Remy 					neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
24056b3f8674SThomas Graf 				break;
24066b3f8674SThomas Graf 			case NDTPA_GC_STALETIME:
24071f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, GC_STALETIME,
24081f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
24096b3f8674SThomas Graf 				break;
24106b3f8674SThomas Graf 			case NDTPA_DELAY_PROBE_TIME:
24111f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, DELAY_PROBE_TIME,
24121f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
24132a4501aeSIdo Schimmel 				call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
24146b3f8674SThomas Graf 				break;
2415211da42eSYuwei Wang 			case NDTPA_INTERVAL_PROBE_TIME_MS:
2416211da42eSYuwei Wang 				NEIGH_VAR_SET(p, INTERVAL_PROBE_TIME_MS,
2417211da42eSYuwei Wang 					      nla_get_msecs(tbp[i]));
2418211da42eSYuwei Wang 				break;
24196b3f8674SThomas Graf 			case NDTPA_RETRANS_TIME:
24201f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, RETRANS_TIME,
24211f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
24226b3f8674SThomas Graf 				break;
24236b3f8674SThomas Graf 			case NDTPA_ANYCAST_DELAY:
24243977458cSJiri Pirko 				NEIGH_VAR_SET(p, ANYCAST_DELAY,
24253977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
24266b3f8674SThomas Graf 				break;
24276b3f8674SThomas Graf 			case NDTPA_PROXY_DELAY:
24283977458cSJiri Pirko 				NEIGH_VAR_SET(p, PROXY_DELAY,
24293977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
24306b3f8674SThomas Graf 				break;
24316b3f8674SThomas Graf 			case NDTPA_LOCKTIME:
24323977458cSJiri Pirko 				NEIGH_VAR_SET(p, LOCKTIME,
24333977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
24346b3f8674SThomas Graf 				break;
2435c7fb64dbSThomas Graf 			}
24366b3f8674SThomas Graf 		}
24376b3f8674SThomas Graf 	}
24386b3f8674SThomas Graf 
2439dc25c676SGao feng 	err = -ENOENT;
2440dc25c676SGao feng 	if ((tb[NDTA_THRESH1] || tb[NDTA_THRESH2] ||
2441dc25c676SGao feng 	     tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]) &&
2442dc25c676SGao feng 	    !net_eq(net, &init_net))
2443dc25c676SGao feng 		goto errout_tbl_lock;
2444dc25c676SGao feng 
24456b3f8674SThomas Graf 	if (tb[NDTA_THRESH1])
24466b3f8674SThomas Graf 		tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
24476b3f8674SThomas Graf 
24486b3f8674SThomas Graf 	if (tb[NDTA_THRESH2])
24496b3f8674SThomas Graf 		tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
24506b3f8674SThomas Graf 
24516b3f8674SThomas Graf 	if (tb[NDTA_THRESH3])
24526b3f8674SThomas Graf 		tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
24536b3f8674SThomas Graf 
24546b3f8674SThomas Graf 	if (tb[NDTA_GC_INTERVAL])
24556b3f8674SThomas Graf 		tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2456c7fb64dbSThomas Graf 
2457c7fb64dbSThomas Graf 	err = 0;
2458c7fb64dbSThomas Graf 
24596b3f8674SThomas Graf errout_tbl_lock:
2460c7fb64dbSThomas Graf 	write_unlock_bh(&tbl->lock);
24616b3f8674SThomas Graf errout:
2462c7fb64dbSThomas Graf 	return err;
2463c7fb64dbSThomas Graf }
2464c7fb64dbSThomas Graf 
24659632d47fSDavid Ahern static int neightbl_valid_dump_info(const struct nlmsghdr *nlh,
24669632d47fSDavid Ahern 				    struct netlink_ext_ack *extack)
24679632d47fSDavid Ahern {
24689632d47fSDavid Ahern 	struct ndtmsg *ndtm;
24699632d47fSDavid Ahern 
24709632d47fSDavid Ahern 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndtm))) {
24719632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid header for neighbor table dump request");
24729632d47fSDavid Ahern 		return -EINVAL;
24739632d47fSDavid Ahern 	}
24749632d47fSDavid Ahern 
24759632d47fSDavid Ahern 	ndtm = nlmsg_data(nlh);
24769632d47fSDavid Ahern 	if (ndtm->ndtm_pad1  || ndtm->ndtm_pad2) {
24779632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor table dump request");
24789632d47fSDavid Ahern 		return -EINVAL;
24799632d47fSDavid Ahern 	}
24809632d47fSDavid Ahern 
24819632d47fSDavid Ahern 	if (nlmsg_attrlen(nlh, sizeof(*ndtm))) {
24829632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid data after header in neighbor table dump request");
24839632d47fSDavid Ahern 		return -EINVAL;
24849632d47fSDavid Ahern 	}
24859632d47fSDavid Ahern 
24869632d47fSDavid Ahern 	return 0;
24879632d47fSDavid Ahern }
24889632d47fSDavid Ahern 
2489c8822a4eSThomas Graf static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
2490c7fb64dbSThomas Graf {
24919632d47fSDavid Ahern 	const struct nlmsghdr *nlh = cb->nlh;
24923b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
2493ca860fb3SThomas Graf 	int family, tidx, nidx = 0;
2494ca860fb3SThomas Graf 	int tbl_skip = cb->args[0];
2495ca860fb3SThomas Graf 	int neigh_skip = cb->args[1];
2496c7fb64dbSThomas Graf 	struct neigh_table *tbl;
2497c7fb64dbSThomas Graf 
24989632d47fSDavid Ahern 	if (cb->strict_check) {
24999632d47fSDavid Ahern 		int err = neightbl_valid_dump_info(nlh, cb->extack);
25009632d47fSDavid Ahern 
25019632d47fSDavid Ahern 		if (err < 0)
25029632d47fSDavid Ahern 			return err;
25039632d47fSDavid Ahern 	}
25049632d47fSDavid Ahern 
25059632d47fSDavid Ahern 	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
2506c7fb64dbSThomas Graf 
2507d7480fd3SWANG Cong 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2508c7fb64dbSThomas Graf 		struct neigh_parms *p;
2509c7fb64dbSThomas Graf 
2510d7480fd3SWANG Cong 		tbl = neigh_tables[tidx];
2511d7480fd3SWANG Cong 		if (!tbl)
2512d7480fd3SWANG Cong 			continue;
2513d7480fd3SWANG Cong 
2514ca860fb3SThomas Graf 		if (tidx < tbl_skip || (family && tbl->family != family))
2515c7fb64dbSThomas Graf 			continue;
2516c7fb64dbSThomas Graf 
251715e47304SEric W. Biederman 		if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
25189632d47fSDavid Ahern 				       nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
25197b46a644SDavid S. Miller 				       NLM_F_MULTI) < 0)
2520c7fb64dbSThomas Graf 			break;
2521c7fb64dbSThomas Graf 
252275fbfd33SNicolas Dichtel 		nidx = 0;
252375fbfd33SNicolas Dichtel 		p = list_next_entry(&tbl->parms, list);
252475fbfd33SNicolas Dichtel 		list_for_each_entry_from(p, &tbl->parms_list, list) {
2525878628fbSYOSHIFUJI Hideaki 			if (!net_eq(neigh_parms_net(p), net))
2526426b5303SEric W. Biederman 				continue;
2527426b5303SEric W. Biederman 
2528efc683fcSGautam Kachroo 			if (nidx < neigh_skip)
2529efc683fcSGautam Kachroo 				goto next;
2530c7fb64dbSThomas Graf 
2531ca860fb3SThomas Graf 			if (neightbl_fill_param_info(skb, tbl, p,
253215e47304SEric W. Biederman 						     NETLINK_CB(cb->skb).portid,
25339632d47fSDavid Ahern 						     nlh->nlmsg_seq,
2534ca860fb3SThomas Graf 						     RTM_NEWNEIGHTBL,
25357b46a644SDavid S. Miller 						     NLM_F_MULTI) < 0)
2536c7fb64dbSThomas Graf 				goto out;
2537efc683fcSGautam Kachroo 		next:
2538efc683fcSGautam Kachroo 			nidx++;
2539c7fb64dbSThomas Graf 		}
2540c7fb64dbSThomas Graf 
2541ca860fb3SThomas Graf 		neigh_skip = 0;
2542c7fb64dbSThomas Graf 	}
2543c7fb64dbSThomas Graf out:
2544ca860fb3SThomas Graf 	cb->args[0] = tidx;
2545ca860fb3SThomas Graf 	cb->args[1] = nidx;
2546c7fb64dbSThomas Graf 
2547c7fb64dbSThomas Graf 	return skb->len;
2548c7fb64dbSThomas Graf }
25491da177e4SLinus Torvalds 
25508b8aec50SThomas Graf static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
25518b8aec50SThomas Graf 			   u32 pid, u32 seq, int type, unsigned int flags)
25521da177e4SLinus Torvalds {
25532c611ad9SRoopa Prabhu 	u32 neigh_flags, neigh_flags_ext;
25541da177e4SLinus Torvalds 	unsigned long now = jiffies;
25551da177e4SLinus Torvalds 	struct nda_cacheinfo ci;
25568b8aec50SThomas Graf 	struct nlmsghdr *nlh;
25578b8aec50SThomas Graf 	struct ndmsg *ndm;
25581da177e4SLinus Torvalds 
25598b8aec50SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
25608b8aec50SThomas Graf 	if (nlh == NULL)
256126932566SPatrick McHardy 		return -EMSGSIZE;
25628b8aec50SThomas Graf 
25632c611ad9SRoopa Prabhu 	neigh_flags_ext = neigh->flags >> NTF_EXT_SHIFT;
25642c611ad9SRoopa Prabhu 	neigh_flags     = neigh->flags & NTF_OLD_MASK;
25652c611ad9SRoopa Prabhu 
25668b8aec50SThomas Graf 	ndm = nlmsg_data(nlh);
25678b8aec50SThomas Graf 	ndm->ndm_family	 = neigh->ops->family;
25689ef1d4c7SPatrick McHardy 	ndm->ndm_pad1    = 0;
25699ef1d4c7SPatrick McHardy 	ndm->ndm_pad2    = 0;
25702c611ad9SRoopa Prabhu 	ndm->ndm_flags	 = neigh_flags;
25718b8aec50SThomas Graf 	ndm->ndm_type	 = neigh->type;
25728b8aec50SThomas Graf 	ndm->ndm_ifindex = neigh->dev->ifindex;
25731da177e4SLinus Torvalds 
25749a6308d7SDavid S. Miller 	if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
25759a6308d7SDavid S. Miller 		goto nla_put_failure;
25768b8aec50SThomas Graf 
25778b8aec50SThomas Graf 	read_lock_bh(&neigh->lock);
25788b8aec50SThomas Graf 	ndm->ndm_state	 = neigh->nud_state;
25790ed8ddf4SEric Dumazet 	if (neigh->nud_state & NUD_VALID) {
25800ed8ddf4SEric Dumazet 		char haddr[MAX_ADDR_LEN];
25810ed8ddf4SEric Dumazet 
25820ed8ddf4SEric Dumazet 		neigh_ha_snapshot(haddr, neigh, neigh->dev);
25830ed8ddf4SEric Dumazet 		if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
25848b8aec50SThomas Graf 			read_unlock_bh(&neigh->lock);
25858b8aec50SThomas Graf 			goto nla_put_failure;
25868b8aec50SThomas Graf 		}
25870ed8ddf4SEric Dumazet 	}
25888b8aec50SThomas Graf 
2589b9f5f52cSStephen Hemminger 	ci.ndm_used	 = jiffies_to_clock_t(now - neigh->used);
2590b9f5f52cSStephen Hemminger 	ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2591b9f5f52cSStephen Hemminger 	ci.ndm_updated	 = jiffies_to_clock_t(now - neigh->updated);
25929f237430SReshetova, Elena 	ci.ndm_refcnt	 = refcount_read(&neigh->refcnt) - 1;
25938b8aec50SThomas Graf 	read_unlock_bh(&neigh->lock);
25948b8aec50SThomas Graf 
25959a6308d7SDavid S. Miller 	if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
25969a6308d7SDavid S. Miller 	    nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
25979a6308d7SDavid S. Miller 		goto nla_put_failure;
25988b8aec50SThomas Graf 
2599df9b0e30SDavid Ahern 	if (neigh->protocol && nla_put_u8(skb, NDA_PROTOCOL, neigh->protocol))
2600df9b0e30SDavid Ahern 		goto nla_put_failure;
26012c611ad9SRoopa Prabhu 	if (neigh_flags_ext && nla_put_u32(skb, NDA_FLAGS_EXT, neigh_flags_ext))
26022c611ad9SRoopa Prabhu 		goto nla_put_failure;
2603df9b0e30SDavid Ahern 
2604053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2605053c095aSJohannes Berg 	return 0;
26068b8aec50SThomas Graf 
26078b8aec50SThomas Graf nla_put_failure:
260826932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
260926932566SPatrick McHardy 	return -EMSGSIZE;
26101da177e4SLinus Torvalds }
26111da177e4SLinus Torvalds 
261284920c14STony Zelenoff static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
261384920c14STony Zelenoff 			    u32 pid, u32 seq, int type, unsigned int flags,
261484920c14STony Zelenoff 			    struct neigh_table *tbl)
261584920c14STony Zelenoff {
26162c611ad9SRoopa Prabhu 	u32 neigh_flags, neigh_flags_ext;
261784920c14STony Zelenoff 	struct nlmsghdr *nlh;
261884920c14STony Zelenoff 	struct ndmsg *ndm;
261984920c14STony Zelenoff 
262084920c14STony Zelenoff 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
262184920c14STony Zelenoff 	if (nlh == NULL)
262284920c14STony Zelenoff 		return -EMSGSIZE;
262384920c14STony Zelenoff 
26242c611ad9SRoopa Prabhu 	neigh_flags_ext = pn->flags >> NTF_EXT_SHIFT;
26252c611ad9SRoopa Prabhu 	neigh_flags     = pn->flags & NTF_OLD_MASK;
26262c611ad9SRoopa Prabhu 
262784920c14STony Zelenoff 	ndm = nlmsg_data(nlh);
262884920c14STony Zelenoff 	ndm->ndm_family	 = tbl->family;
262984920c14STony Zelenoff 	ndm->ndm_pad1    = 0;
263084920c14STony Zelenoff 	ndm->ndm_pad2    = 0;
26312c611ad9SRoopa Prabhu 	ndm->ndm_flags	 = neigh_flags | NTF_PROXY;
2632545469f7SJun Zhao 	ndm->ndm_type	 = RTN_UNICAST;
26336adc5fd6SKonstantin Khlebnikov 	ndm->ndm_ifindex = pn->dev ? pn->dev->ifindex : 0;
263484920c14STony Zelenoff 	ndm->ndm_state	 = NUD_NONE;
263584920c14STony Zelenoff 
26369a6308d7SDavid S. Miller 	if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
26379a6308d7SDavid S. Miller 		goto nla_put_failure;
263884920c14STony Zelenoff 
2639df9b0e30SDavid Ahern 	if (pn->protocol && nla_put_u8(skb, NDA_PROTOCOL, pn->protocol))
2640df9b0e30SDavid Ahern 		goto nla_put_failure;
26412c611ad9SRoopa Prabhu 	if (neigh_flags_ext && nla_put_u32(skb, NDA_FLAGS_EXT, neigh_flags_ext))
26422c611ad9SRoopa Prabhu 		goto nla_put_failure;
2643df9b0e30SDavid Ahern 
2644053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2645053c095aSJohannes Berg 	return 0;
264684920c14STony Zelenoff 
264784920c14STony Zelenoff nla_put_failure:
264884920c14STony Zelenoff 	nlmsg_cancel(skb, nlh);
264984920c14STony Zelenoff 	return -EMSGSIZE;
265084920c14STony Zelenoff }
265184920c14STony Zelenoff 
26527b8f7a40SRoopa Prabhu static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid)
2653d961db35SThomas Graf {
2654d961db35SThomas Graf 	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
26557b8f7a40SRoopa Prabhu 	__neigh_notify(neigh, RTM_NEWNEIGH, 0, nlmsg_pid);
2656d961db35SThomas Graf }
26571da177e4SLinus Torvalds 
265821fdd092SDavid Ahern static bool neigh_master_filtered(struct net_device *dev, int master_idx)
265921fdd092SDavid Ahern {
266021fdd092SDavid Ahern 	struct net_device *master;
266121fdd092SDavid Ahern 
266221fdd092SDavid Ahern 	if (!master_idx)
266321fdd092SDavid Ahern 		return false;
266421fdd092SDavid Ahern 
2665aab456dfSEric Dumazet 	master = dev ? netdev_master_upper_dev_get(dev) : NULL;
2666d3432bf1SLahav Schlesinger 
2667d3432bf1SLahav Schlesinger 	/* 0 is already used to denote NDA_MASTER wasn't passed, therefore need another
2668d3432bf1SLahav Schlesinger 	 * invalid value for ifindex to denote "no master".
2669d3432bf1SLahav Schlesinger 	 */
2670d3432bf1SLahav Schlesinger 	if (master_idx == -1)
2671d3432bf1SLahav Schlesinger 		return !!master;
2672d3432bf1SLahav Schlesinger 
267321fdd092SDavid Ahern 	if (!master || master->ifindex != master_idx)
267421fdd092SDavid Ahern 		return true;
267521fdd092SDavid Ahern 
267621fdd092SDavid Ahern 	return false;
267721fdd092SDavid Ahern }
267821fdd092SDavid Ahern 
267916660f0bSDavid Ahern static bool neigh_ifindex_filtered(struct net_device *dev, int filter_idx)
268016660f0bSDavid Ahern {
2681aab456dfSEric Dumazet 	if (filter_idx && (!dev || dev->ifindex != filter_idx))
268216660f0bSDavid Ahern 		return true;
268316660f0bSDavid Ahern 
268416660f0bSDavid Ahern 	return false;
268516660f0bSDavid Ahern }
268616660f0bSDavid Ahern 
26876f52f80eSDavid Ahern struct neigh_dump_filter {
26886f52f80eSDavid Ahern 	int master_idx;
26896f52f80eSDavid Ahern 	int dev_idx;
26906f52f80eSDavid Ahern };
26916f52f80eSDavid Ahern 
26921da177e4SLinus Torvalds static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
26936f52f80eSDavid Ahern 			    struct netlink_callback *cb,
26946f52f80eSDavid Ahern 			    struct neigh_dump_filter *filter)
26951da177e4SLinus Torvalds {
26963b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
26971da177e4SLinus Torvalds 	struct neighbour *n;
26981da177e4SLinus Torvalds 	int rc, h, s_h = cb->args[1];
26991da177e4SLinus Torvalds 	int idx, s_idx = idx = cb->args[2];
2700d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
270121fdd092SDavid Ahern 	unsigned int flags = NLM_F_MULTI;
270221fdd092SDavid Ahern 
27036f52f80eSDavid Ahern 	if (filter->dev_idx || filter->master_idx)
270421fdd092SDavid Ahern 		flags |= NLM_F_DUMP_FILTERED;
27051da177e4SLinus Torvalds 
2706d6bf7817SEric Dumazet 	rcu_read_lock_bh();
2707d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
2708d6bf7817SEric Dumazet 
27094bd6683bSEric Dumazet 	for (h = s_h; h < (1 << nht->hash_shift); h++) {
27101da177e4SLinus Torvalds 		if (h > s_h)
27111da177e4SLinus Torvalds 			s_idx = 0;
2712767e97e1SEric Dumazet 		for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2713767e97e1SEric Dumazet 		     n != NULL;
2714767e97e1SEric Dumazet 		     n = rcu_dereference_bh(n->next)) {
271518502acdSZhang Shengju 			if (idx < s_idx || !net_eq(dev_net(n->dev), net))
271618502acdSZhang Shengju 				goto next;
27176f52f80eSDavid Ahern 			if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
27186f52f80eSDavid Ahern 			    neigh_master_filtered(n->dev, filter->master_idx))
2719efc683fcSGautam Kachroo 				goto next;
272015e47304SEric W. Biederman 			if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
27211da177e4SLinus Torvalds 					    cb->nlh->nlmsg_seq,
2722b6544c0bSJamal Hadi Salim 					    RTM_NEWNEIGH,
272321fdd092SDavid Ahern 					    flags) < 0) {
27241da177e4SLinus Torvalds 				rc = -1;
27251da177e4SLinus Torvalds 				goto out;
27261da177e4SLinus Torvalds 			}
2727efc683fcSGautam Kachroo next:
2728efc683fcSGautam Kachroo 			idx++;
27291da177e4SLinus Torvalds 		}
27301da177e4SLinus Torvalds 	}
27311da177e4SLinus Torvalds 	rc = skb->len;
27321da177e4SLinus Torvalds out:
2733d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
27341da177e4SLinus Torvalds 	cb->args[1] = h;
27351da177e4SLinus Torvalds 	cb->args[2] = idx;
27361da177e4SLinus Torvalds 	return rc;
27371da177e4SLinus Torvalds }
27381da177e4SLinus Torvalds 
273984920c14STony Zelenoff static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
27406f52f80eSDavid Ahern 			     struct netlink_callback *cb,
27416f52f80eSDavid Ahern 			     struct neigh_dump_filter *filter)
274284920c14STony Zelenoff {
274384920c14STony Zelenoff 	struct pneigh_entry *n;
274484920c14STony Zelenoff 	struct net *net = sock_net(skb->sk);
274584920c14STony Zelenoff 	int rc, h, s_h = cb->args[3];
274684920c14STony Zelenoff 	int idx, s_idx = idx = cb->args[4];
27476f52f80eSDavid Ahern 	unsigned int flags = NLM_F_MULTI;
27486f52f80eSDavid Ahern 
27496f52f80eSDavid Ahern 	if (filter->dev_idx || filter->master_idx)
27506f52f80eSDavid Ahern 		flags |= NLM_F_DUMP_FILTERED;
275184920c14STony Zelenoff 
275284920c14STony Zelenoff 	read_lock_bh(&tbl->lock);
275384920c14STony Zelenoff 
27544bd6683bSEric Dumazet 	for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
275584920c14STony Zelenoff 		if (h > s_h)
275684920c14STony Zelenoff 			s_idx = 0;
275784920c14STony Zelenoff 		for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
275818502acdSZhang Shengju 			if (idx < s_idx || pneigh_net(n) != net)
275984920c14STony Zelenoff 				goto next;
27606f52f80eSDavid Ahern 			if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
27616f52f80eSDavid Ahern 			    neigh_master_filtered(n->dev, filter->master_idx))
27626f52f80eSDavid Ahern 				goto next;
276315e47304SEric W. Biederman 			if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
276484920c14STony Zelenoff 					    cb->nlh->nlmsg_seq,
27656f52f80eSDavid Ahern 					    RTM_NEWNEIGH, flags, tbl) < 0) {
276684920c14STony Zelenoff 				read_unlock_bh(&tbl->lock);
276784920c14STony Zelenoff 				rc = -1;
276884920c14STony Zelenoff 				goto out;
276984920c14STony Zelenoff 			}
277084920c14STony Zelenoff 		next:
277184920c14STony Zelenoff 			idx++;
277284920c14STony Zelenoff 		}
277384920c14STony Zelenoff 	}
277484920c14STony Zelenoff 
277584920c14STony Zelenoff 	read_unlock_bh(&tbl->lock);
277684920c14STony Zelenoff 	rc = skb->len;
277784920c14STony Zelenoff out:
277884920c14STony Zelenoff 	cb->args[3] = h;
277984920c14STony Zelenoff 	cb->args[4] = idx;
278084920c14STony Zelenoff 	return rc;
278184920c14STony Zelenoff 
278284920c14STony Zelenoff }
278384920c14STony Zelenoff 
278451183d23SDavid Ahern static int neigh_valid_dump_req(const struct nlmsghdr *nlh,
278551183d23SDavid Ahern 				bool strict_check,
278651183d23SDavid Ahern 				struct neigh_dump_filter *filter,
278751183d23SDavid Ahern 				struct netlink_ext_ack *extack)
278851183d23SDavid Ahern {
278951183d23SDavid Ahern 	struct nlattr *tb[NDA_MAX + 1];
279051183d23SDavid Ahern 	int err, i;
279151183d23SDavid Ahern 
279251183d23SDavid Ahern 	if (strict_check) {
279351183d23SDavid Ahern 		struct ndmsg *ndm;
279451183d23SDavid Ahern 
279551183d23SDavid Ahern 		if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
279651183d23SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid header for neighbor dump request");
279751183d23SDavid Ahern 			return -EINVAL;
279851183d23SDavid Ahern 		}
279951183d23SDavid Ahern 
280051183d23SDavid Ahern 		ndm = nlmsg_data(nlh);
280151183d23SDavid Ahern 		if (ndm->ndm_pad1  || ndm->ndm_pad2  || ndm->ndm_ifindex ||
2802c0fde870SDavid Ahern 		    ndm->ndm_state || ndm->ndm_type) {
280351183d23SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor dump request");
280451183d23SDavid Ahern 			return -EINVAL;
280551183d23SDavid Ahern 		}
280651183d23SDavid Ahern 
2807c0fde870SDavid Ahern 		if (ndm->ndm_flags & ~NTF_PROXY) {
2808c0fde870SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor dump request");
2809c0fde870SDavid Ahern 			return -EINVAL;
2810c0fde870SDavid Ahern 		}
2811c0fde870SDavid Ahern 
28128cb08174SJohannes Berg 		err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg),
28138cb08174SJohannes Berg 						    tb, NDA_MAX, nda_policy,
28148cb08174SJohannes Berg 						    extack);
281551183d23SDavid Ahern 	} else {
28168cb08174SJohannes Berg 		err = nlmsg_parse_deprecated(nlh, sizeof(struct ndmsg), tb,
28178cb08174SJohannes Berg 					     NDA_MAX, nda_policy, extack);
281851183d23SDavid Ahern 	}
281951183d23SDavid Ahern 	if (err < 0)
282051183d23SDavid Ahern 		return err;
282151183d23SDavid Ahern 
282251183d23SDavid Ahern 	for (i = 0; i <= NDA_MAX; ++i) {
282351183d23SDavid Ahern 		if (!tb[i])
282451183d23SDavid Ahern 			continue;
282551183d23SDavid Ahern 
282651183d23SDavid Ahern 		/* all new attributes should require strict_check */
282751183d23SDavid Ahern 		switch (i) {
282851183d23SDavid Ahern 		case NDA_IFINDEX:
282951183d23SDavid Ahern 			filter->dev_idx = nla_get_u32(tb[i]);
283051183d23SDavid Ahern 			break;
283151183d23SDavid Ahern 		case NDA_MASTER:
283251183d23SDavid Ahern 			filter->master_idx = nla_get_u32(tb[i]);
283351183d23SDavid Ahern 			break;
283451183d23SDavid Ahern 		default:
283551183d23SDavid Ahern 			if (strict_check) {
283651183d23SDavid Ahern 				NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor dump request");
283751183d23SDavid Ahern 				return -EINVAL;
283851183d23SDavid Ahern 			}
283951183d23SDavid Ahern 		}
284051183d23SDavid Ahern 	}
284151183d23SDavid Ahern 
284251183d23SDavid Ahern 	return 0;
284351183d23SDavid Ahern }
284451183d23SDavid Ahern 
2845c8822a4eSThomas Graf static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
28461da177e4SLinus Torvalds {
28476f52f80eSDavid Ahern 	const struct nlmsghdr *nlh = cb->nlh;
28486f52f80eSDavid Ahern 	struct neigh_dump_filter filter = {};
28491da177e4SLinus Torvalds 	struct neigh_table *tbl;
28501da177e4SLinus Torvalds 	int t, family, s_t;
285184920c14STony Zelenoff 	int proxy = 0;
28524bd6683bSEric Dumazet 	int err;
28531da177e4SLinus Torvalds 
28546f52f80eSDavid Ahern 	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
285584920c14STony Zelenoff 
285684920c14STony Zelenoff 	/* check for full ndmsg structure presence, family member is
285784920c14STony Zelenoff 	 * the same for both structures
285884920c14STony Zelenoff 	 */
28596f52f80eSDavid Ahern 	if (nlmsg_len(nlh) >= sizeof(struct ndmsg) &&
28606f52f80eSDavid Ahern 	    ((struct ndmsg *)nlmsg_data(nlh))->ndm_flags == NTF_PROXY)
286184920c14STony Zelenoff 		proxy = 1;
286284920c14STony Zelenoff 
286351183d23SDavid Ahern 	err = neigh_valid_dump_req(nlh, cb->strict_check, &filter, cb->extack);
286451183d23SDavid Ahern 	if (err < 0 && cb->strict_check)
286551183d23SDavid Ahern 		return err;
286651183d23SDavid Ahern 
28671da177e4SLinus Torvalds 	s_t = cb->args[0];
28681da177e4SLinus Torvalds 
2869d7480fd3SWANG Cong 	for (t = 0; t < NEIGH_NR_TABLES; t++) {
2870d7480fd3SWANG Cong 		tbl = neigh_tables[t];
2871d7480fd3SWANG Cong 
2872d7480fd3SWANG Cong 		if (!tbl)
2873d7480fd3SWANG Cong 			continue;
28741da177e4SLinus Torvalds 		if (t < s_t || (family && tbl->family != family))
28751da177e4SLinus Torvalds 			continue;
28761da177e4SLinus Torvalds 		if (t > s_t)
28771da177e4SLinus Torvalds 			memset(&cb->args[1], 0, sizeof(cb->args) -
28781da177e4SLinus Torvalds 						sizeof(cb->args[0]));
287984920c14STony Zelenoff 		if (proxy)
28806f52f80eSDavid Ahern 			err = pneigh_dump_table(tbl, skb, cb, &filter);
288184920c14STony Zelenoff 		else
28826f52f80eSDavid Ahern 			err = neigh_dump_table(tbl, skb, cb, &filter);
28834bd6683bSEric Dumazet 		if (err < 0)
28844bd6683bSEric Dumazet 			break;
28851da177e4SLinus Torvalds 	}
28861da177e4SLinus Torvalds 
28871da177e4SLinus Torvalds 	cb->args[0] = t;
28881da177e4SLinus Torvalds 	return skb->len;
28891da177e4SLinus Torvalds }
28901da177e4SLinus Torvalds 
289182cbb5c6SRoopa Prabhu static int neigh_valid_get_req(const struct nlmsghdr *nlh,
289282cbb5c6SRoopa Prabhu 			       struct neigh_table **tbl,
289382cbb5c6SRoopa Prabhu 			       void **dst, int *dev_idx, u8 *ndm_flags,
289482cbb5c6SRoopa Prabhu 			       struct netlink_ext_ack *extack)
289582cbb5c6SRoopa Prabhu {
289682cbb5c6SRoopa Prabhu 	struct nlattr *tb[NDA_MAX + 1];
289782cbb5c6SRoopa Prabhu 	struct ndmsg *ndm;
289882cbb5c6SRoopa Prabhu 	int err, i;
289982cbb5c6SRoopa Prabhu 
290082cbb5c6SRoopa Prabhu 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
290182cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid header for neighbor get request");
290282cbb5c6SRoopa Prabhu 		return -EINVAL;
290382cbb5c6SRoopa Prabhu 	}
290482cbb5c6SRoopa Prabhu 
290582cbb5c6SRoopa Prabhu 	ndm = nlmsg_data(nlh);
290682cbb5c6SRoopa Prabhu 	if (ndm->ndm_pad1  || ndm->ndm_pad2  || ndm->ndm_state ||
290782cbb5c6SRoopa Prabhu 	    ndm->ndm_type) {
290882cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor get request");
290982cbb5c6SRoopa Prabhu 		return -EINVAL;
291082cbb5c6SRoopa Prabhu 	}
291182cbb5c6SRoopa Prabhu 
291282cbb5c6SRoopa Prabhu 	if (ndm->ndm_flags & ~NTF_PROXY) {
291382cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor get request");
291482cbb5c6SRoopa Prabhu 		return -EINVAL;
291582cbb5c6SRoopa Prabhu 	}
291682cbb5c6SRoopa Prabhu 
29178cb08174SJohannes Berg 	err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb,
29188cb08174SJohannes Berg 					    NDA_MAX, nda_policy, extack);
291982cbb5c6SRoopa Prabhu 	if (err < 0)
292082cbb5c6SRoopa Prabhu 		return err;
292182cbb5c6SRoopa Prabhu 
292282cbb5c6SRoopa Prabhu 	*ndm_flags = ndm->ndm_flags;
292382cbb5c6SRoopa Prabhu 	*dev_idx = ndm->ndm_ifindex;
292482cbb5c6SRoopa Prabhu 	*tbl = neigh_find_table(ndm->ndm_family);
292582cbb5c6SRoopa Prabhu 	if (*tbl == NULL) {
292682cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
292782cbb5c6SRoopa Prabhu 		return -EAFNOSUPPORT;
292882cbb5c6SRoopa Prabhu 	}
292982cbb5c6SRoopa Prabhu 
293082cbb5c6SRoopa Prabhu 	for (i = 0; i <= NDA_MAX; ++i) {
293182cbb5c6SRoopa Prabhu 		if (!tb[i])
293282cbb5c6SRoopa Prabhu 			continue;
293382cbb5c6SRoopa Prabhu 
293482cbb5c6SRoopa Prabhu 		switch (i) {
293582cbb5c6SRoopa Prabhu 		case NDA_DST:
293682cbb5c6SRoopa Prabhu 			if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
293782cbb5c6SRoopa Prabhu 				NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
293882cbb5c6SRoopa Prabhu 				return -EINVAL;
293982cbb5c6SRoopa Prabhu 			}
294082cbb5c6SRoopa Prabhu 			*dst = nla_data(tb[i]);
294182cbb5c6SRoopa Prabhu 			break;
294282cbb5c6SRoopa Prabhu 		default:
294382cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request");
294482cbb5c6SRoopa Prabhu 			return -EINVAL;
294582cbb5c6SRoopa Prabhu 		}
294682cbb5c6SRoopa Prabhu 	}
294782cbb5c6SRoopa Prabhu 
294882cbb5c6SRoopa Prabhu 	return 0;
294982cbb5c6SRoopa Prabhu }
295082cbb5c6SRoopa Prabhu 
295182cbb5c6SRoopa Prabhu static inline size_t neigh_nlmsg_size(void)
295282cbb5c6SRoopa Prabhu {
295382cbb5c6SRoopa Prabhu 	return NLMSG_ALIGN(sizeof(struct ndmsg))
295482cbb5c6SRoopa Prabhu 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
295582cbb5c6SRoopa Prabhu 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
295682cbb5c6SRoopa Prabhu 	       + nla_total_size(sizeof(struct nda_cacheinfo))
295782cbb5c6SRoopa Prabhu 	       + nla_total_size(4)  /* NDA_PROBES */
29582c611ad9SRoopa Prabhu 	       + nla_total_size(4)  /* NDA_FLAGS_EXT */
295982cbb5c6SRoopa Prabhu 	       + nla_total_size(1); /* NDA_PROTOCOL */
296082cbb5c6SRoopa Prabhu }
296182cbb5c6SRoopa Prabhu 
296282cbb5c6SRoopa Prabhu static int neigh_get_reply(struct net *net, struct neighbour *neigh,
296382cbb5c6SRoopa Prabhu 			   u32 pid, u32 seq)
296482cbb5c6SRoopa Prabhu {
296582cbb5c6SRoopa Prabhu 	struct sk_buff *skb;
296682cbb5c6SRoopa Prabhu 	int err = 0;
296782cbb5c6SRoopa Prabhu 
296882cbb5c6SRoopa Prabhu 	skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL);
296982cbb5c6SRoopa Prabhu 	if (!skb)
297082cbb5c6SRoopa Prabhu 		return -ENOBUFS;
297182cbb5c6SRoopa Prabhu 
297282cbb5c6SRoopa Prabhu 	err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0);
297382cbb5c6SRoopa Prabhu 	if (err) {
297482cbb5c6SRoopa Prabhu 		kfree_skb(skb);
297582cbb5c6SRoopa Prabhu 		goto errout;
297682cbb5c6SRoopa Prabhu 	}
297782cbb5c6SRoopa Prabhu 
297882cbb5c6SRoopa Prabhu 	err = rtnl_unicast(skb, net, pid);
297982cbb5c6SRoopa Prabhu errout:
298082cbb5c6SRoopa Prabhu 	return err;
298182cbb5c6SRoopa Prabhu }
298282cbb5c6SRoopa Prabhu 
298382cbb5c6SRoopa Prabhu static inline size_t pneigh_nlmsg_size(void)
298482cbb5c6SRoopa Prabhu {
298582cbb5c6SRoopa Prabhu 	return NLMSG_ALIGN(sizeof(struct ndmsg))
2986463561e6SColin Ian King 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
29872c611ad9SRoopa Prabhu 	       + nla_total_size(4)  /* NDA_FLAGS_EXT */
298882cbb5c6SRoopa Prabhu 	       + nla_total_size(1); /* NDA_PROTOCOL */
298982cbb5c6SRoopa Prabhu }
299082cbb5c6SRoopa Prabhu 
299182cbb5c6SRoopa Prabhu static int pneigh_get_reply(struct net *net, struct pneigh_entry *neigh,
299282cbb5c6SRoopa Prabhu 			    u32 pid, u32 seq, struct neigh_table *tbl)
299382cbb5c6SRoopa Prabhu {
299482cbb5c6SRoopa Prabhu 	struct sk_buff *skb;
299582cbb5c6SRoopa Prabhu 	int err = 0;
299682cbb5c6SRoopa Prabhu 
299782cbb5c6SRoopa Prabhu 	skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL);
299882cbb5c6SRoopa Prabhu 	if (!skb)
299982cbb5c6SRoopa Prabhu 		return -ENOBUFS;
300082cbb5c6SRoopa Prabhu 
300182cbb5c6SRoopa Prabhu 	err = pneigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0, tbl);
300282cbb5c6SRoopa Prabhu 	if (err) {
300382cbb5c6SRoopa Prabhu 		kfree_skb(skb);
300482cbb5c6SRoopa Prabhu 		goto errout;
300582cbb5c6SRoopa Prabhu 	}
300682cbb5c6SRoopa Prabhu 
300782cbb5c6SRoopa Prabhu 	err = rtnl_unicast(skb, net, pid);
300882cbb5c6SRoopa Prabhu errout:
300982cbb5c6SRoopa Prabhu 	return err;
301082cbb5c6SRoopa Prabhu }
301182cbb5c6SRoopa Prabhu 
301282cbb5c6SRoopa Prabhu static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
301382cbb5c6SRoopa Prabhu 		     struct netlink_ext_ack *extack)
301482cbb5c6SRoopa Prabhu {
301582cbb5c6SRoopa Prabhu 	struct net *net = sock_net(in_skb->sk);
301682cbb5c6SRoopa Prabhu 	struct net_device *dev = NULL;
301782cbb5c6SRoopa Prabhu 	struct neigh_table *tbl = NULL;
301882cbb5c6SRoopa Prabhu 	struct neighbour *neigh;
301982cbb5c6SRoopa Prabhu 	void *dst = NULL;
302082cbb5c6SRoopa Prabhu 	u8 ndm_flags = 0;
302182cbb5c6SRoopa Prabhu 	int dev_idx = 0;
302282cbb5c6SRoopa Prabhu 	int err;
302382cbb5c6SRoopa Prabhu 
302482cbb5c6SRoopa Prabhu 	err = neigh_valid_get_req(nlh, &tbl, &dst, &dev_idx, &ndm_flags,
302582cbb5c6SRoopa Prabhu 				  extack);
302682cbb5c6SRoopa Prabhu 	if (err < 0)
302782cbb5c6SRoopa Prabhu 		return err;
302882cbb5c6SRoopa Prabhu 
302982cbb5c6SRoopa Prabhu 	if (dev_idx) {
303082cbb5c6SRoopa Prabhu 		dev = __dev_get_by_index(net, dev_idx);
303182cbb5c6SRoopa Prabhu 		if (!dev) {
303282cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Unknown device ifindex");
303382cbb5c6SRoopa Prabhu 			return -ENODEV;
303482cbb5c6SRoopa Prabhu 		}
303582cbb5c6SRoopa Prabhu 	}
303682cbb5c6SRoopa Prabhu 
303782cbb5c6SRoopa Prabhu 	if (!dst) {
303882cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Network address not specified");
303982cbb5c6SRoopa Prabhu 		return -EINVAL;
304082cbb5c6SRoopa Prabhu 	}
304182cbb5c6SRoopa Prabhu 
304282cbb5c6SRoopa Prabhu 	if (ndm_flags & NTF_PROXY) {
304382cbb5c6SRoopa Prabhu 		struct pneigh_entry *pn;
304482cbb5c6SRoopa Prabhu 
304582cbb5c6SRoopa Prabhu 		pn = pneigh_lookup(tbl, net, dst, dev, 0);
304682cbb5c6SRoopa Prabhu 		if (!pn) {
304782cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Proxy neighbour entry not found");
304882cbb5c6SRoopa Prabhu 			return -ENOENT;
304982cbb5c6SRoopa Prabhu 		}
305082cbb5c6SRoopa Prabhu 		return pneigh_get_reply(net, pn, NETLINK_CB(in_skb).portid,
305182cbb5c6SRoopa Prabhu 					nlh->nlmsg_seq, tbl);
305282cbb5c6SRoopa Prabhu 	}
305382cbb5c6SRoopa Prabhu 
305482cbb5c6SRoopa Prabhu 	if (!dev) {
305582cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "No device specified");
305682cbb5c6SRoopa Prabhu 		return -EINVAL;
305782cbb5c6SRoopa Prabhu 	}
305882cbb5c6SRoopa Prabhu 
305982cbb5c6SRoopa Prabhu 	neigh = neigh_lookup(tbl, dst, dev);
306082cbb5c6SRoopa Prabhu 	if (!neigh) {
306182cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Neighbour entry not found");
306282cbb5c6SRoopa Prabhu 		return -ENOENT;
306382cbb5c6SRoopa Prabhu 	}
306482cbb5c6SRoopa Prabhu 
306582cbb5c6SRoopa Prabhu 	err = neigh_get_reply(net, neigh, NETLINK_CB(in_skb).portid,
306682cbb5c6SRoopa Prabhu 			      nlh->nlmsg_seq);
306782cbb5c6SRoopa Prabhu 
306882cbb5c6SRoopa Prabhu 	neigh_release(neigh);
306982cbb5c6SRoopa Prabhu 
307082cbb5c6SRoopa Prabhu 	return err;
307182cbb5c6SRoopa Prabhu }
307282cbb5c6SRoopa Prabhu 
30731da177e4SLinus Torvalds void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
30741da177e4SLinus Torvalds {
30751da177e4SLinus Torvalds 	int chain;
3076d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
30771da177e4SLinus Torvalds 
3078d6bf7817SEric Dumazet 	rcu_read_lock_bh();
3079d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
3080d6bf7817SEric Dumazet 
3081767e97e1SEric Dumazet 	read_lock(&tbl->lock); /* avoid resizes */
3082cd089336SDavid S. Miller 	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
30831da177e4SLinus Torvalds 		struct neighbour *n;
30841da177e4SLinus Torvalds 
3085767e97e1SEric Dumazet 		for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
3086767e97e1SEric Dumazet 		     n != NULL;
3087767e97e1SEric Dumazet 		     n = rcu_dereference_bh(n->next))
30881da177e4SLinus Torvalds 			cb(n, cookie);
30891da177e4SLinus Torvalds 	}
3090d6bf7817SEric Dumazet 	read_unlock(&tbl->lock);
3091d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
30921da177e4SLinus Torvalds }
30931da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_for_each);
30941da177e4SLinus Torvalds 
30951da177e4SLinus Torvalds /* The tbl->lock must be held as a writer and BH disabled. */
30961da177e4SLinus Torvalds void __neigh_for_each_release(struct neigh_table *tbl,
30971da177e4SLinus Torvalds 			      int (*cb)(struct neighbour *))
30981da177e4SLinus Torvalds {
30991da177e4SLinus Torvalds 	int chain;
3100d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
31011da177e4SLinus Torvalds 
3102d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
3103d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
3104cd089336SDavid S. Miller 	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
3105767e97e1SEric Dumazet 		struct neighbour *n;
3106767e97e1SEric Dumazet 		struct neighbour __rcu **np;
31071da177e4SLinus Torvalds 
3108d6bf7817SEric Dumazet 		np = &nht->hash_buckets[chain];
3109767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
3110767e97e1SEric Dumazet 					lockdep_is_held(&tbl->lock))) != NULL) {
31111da177e4SLinus Torvalds 			int release;
31121da177e4SLinus Torvalds 
31131da177e4SLinus Torvalds 			write_lock(&n->lock);
31141da177e4SLinus Torvalds 			release = cb(n);
31151da177e4SLinus Torvalds 			if (release) {
3116767e97e1SEric Dumazet 				rcu_assign_pointer(*np,
3117767e97e1SEric Dumazet 					rcu_dereference_protected(n->next,
3118767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
311958956317SDavid Ahern 				neigh_mark_dead(n);
31201da177e4SLinus Torvalds 			} else
31211da177e4SLinus Torvalds 				np = &n->next;
31221da177e4SLinus Torvalds 			write_unlock(&n->lock);
31234f494554SThomas Graf 			if (release)
31244f494554SThomas Graf 				neigh_cleanup_and_release(n);
31251da177e4SLinus Torvalds 		}
31261da177e4SLinus Torvalds 	}
3127ecbb4169SAlexey Kuznetsov }
31281da177e4SLinus Torvalds EXPORT_SYMBOL(__neigh_for_each_release);
31291da177e4SLinus Torvalds 
3130b79bda3dSEric W. Biederman int neigh_xmit(int index, struct net_device *dev,
31314fd3d7d9SEric W. Biederman 	       const void *addr, struct sk_buff *skb)
31324fd3d7d9SEric W. Biederman {
3133b79bda3dSEric W. Biederman 	int err = -EAFNOSUPPORT;
3134b79bda3dSEric W. Biederman 	if (likely(index < NEIGH_NR_TABLES)) {
31354fd3d7d9SEric W. Biederman 		struct neigh_table *tbl;
31364fd3d7d9SEric W. Biederman 		struct neighbour *neigh;
31374fd3d7d9SEric W. Biederman 
3138b79bda3dSEric W. Biederman 		tbl = neigh_tables[index];
31394fd3d7d9SEric W. Biederman 		if (!tbl)
31404fd3d7d9SEric W. Biederman 			goto out;
3141b560f03dSDavid Barroso 		rcu_read_lock_bh();
31424b2a2bfeSDavid Ahern 		if (index == NEIGH_ARP_TABLE) {
31434b2a2bfeSDavid Ahern 			u32 key = *((u32 *)addr);
31444b2a2bfeSDavid Ahern 
31454b2a2bfeSDavid Ahern 			neigh = __ipv4_neigh_lookup_noref(dev, key);
31464b2a2bfeSDavid Ahern 		} else {
31474fd3d7d9SEric W. Biederman 			neigh = __neigh_lookup_noref(tbl, addr, dev);
31484b2a2bfeSDavid Ahern 		}
31494fd3d7d9SEric W. Biederman 		if (!neigh)
31504fd3d7d9SEric W. Biederman 			neigh = __neigh_create(tbl, addr, dev, false);
31514fd3d7d9SEric W. Biederman 		err = PTR_ERR(neigh);
3152b560f03dSDavid Barroso 		if (IS_ERR(neigh)) {
3153b560f03dSDavid Barroso 			rcu_read_unlock_bh();
31544fd3d7d9SEric W. Biederman 			goto out_kfree_skb;
3155b560f03dSDavid Barroso 		}
31564fd3d7d9SEric W. Biederman 		err = neigh->output(neigh, skb);
3157b560f03dSDavid Barroso 		rcu_read_unlock_bh();
31584fd3d7d9SEric W. Biederman 	}
3159b79bda3dSEric W. Biederman 	else if (index == NEIGH_LINK_TABLE) {
3160b79bda3dSEric W. Biederman 		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
3161b79bda3dSEric W. Biederman 				      addr, NULL, skb->len);
3162b79bda3dSEric W. Biederman 		if (err < 0)
3163b79bda3dSEric W. Biederman 			goto out_kfree_skb;
3164b79bda3dSEric W. Biederman 		err = dev_queue_xmit(skb);
3165b79bda3dSEric W. Biederman 	}
31664fd3d7d9SEric W. Biederman out:
31674fd3d7d9SEric W. Biederman 	return err;
31684fd3d7d9SEric W. Biederman out_kfree_skb:
31694fd3d7d9SEric W. Biederman 	kfree_skb(skb);
31704fd3d7d9SEric W. Biederman 	goto out;
31714fd3d7d9SEric W. Biederman }
31724fd3d7d9SEric W. Biederman EXPORT_SYMBOL(neigh_xmit);
31734fd3d7d9SEric W. Biederman 
31741da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
31751da177e4SLinus Torvalds 
31761da177e4SLinus Torvalds static struct neighbour *neigh_get_first(struct seq_file *seq)
31771da177e4SLinus Torvalds {
31781da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
31791218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
3180d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = state->nht;
31811da177e4SLinus Torvalds 	struct neighbour *n = NULL;
3182f530eed6SColin Ian King 	int bucket;
31831da177e4SLinus Torvalds 
31841da177e4SLinus Torvalds 	state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
3185cd089336SDavid S. Miller 	for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
3186767e97e1SEric Dumazet 		n = rcu_dereference_bh(nht->hash_buckets[bucket]);
31871da177e4SLinus Torvalds 
31881da177e4SLinus Torvalds 		while (n) {
3189878628fbSYOSHIFUJI Hideaki 			if (!net_eq(dev_net(n->dev), net))
3190426b5303SEric W. Biederman 				goto next;
31911da177e4SLinus Torvalds 			if (state->neigh_sub_iter) {
31921da177e4SLinus Torvalds 				loff_t fakep = 0;
31931da177e4SLinus Torvalds 				void *v;
31941da177e4SLinus Torvalds 
31951da177e4SLinus Torvalds 				v = state->neigh_sub_iter(state, n, &fakep);
31961da177e4SLinus Torvalds 				if (!v)
31971da177e4SLinus Torvalds 					goto next;
31981da177e4SLinus Torvalds 			}
31991da177e4SLinus Torvalds 			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
32001da177e4SLinus Torvalds 				break;
3201*b071af52SEric Dumazet 			if (READ_ONCE(n->nud_state) & ~NUD_NOARP)
32021da177e4SLinus Torvalds 				break;
32031da177e4SLinus Torvalds next:
3204767e97e1SEric Dumazet 			n = rcu_dereference_bh(n->next);
32051da177e4SLinus Torvalds 		}
32061da177e4SLinus Torvalds 
32071da177e4SLinus Torvalds 		if (n)
32081da177e4SLinus Torvalds 			break;
32091da177e4SLinus Torvalds 	}
32101da177e4SLinus Torvalds 	state->bucket = bucket;
32111da177e4SLinus Torvalds 
32121da177e4SLinus Torvalds 	return n;
32131da177e4SLinus Torvalds }
32141da177e4SLinus Torvalds 
32151da177e4SLinus Torvalds static struct neighbour *neigh_get_next(struct seq_file *seq,
32161da177e4SLinus Torvalds 					struct neighbour *n,
32171da177e4SLinus Torvalds 					loff_t *pos)
32181da177e4SLinus Torvalds {
32191da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
32201218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
3221d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = state->nht;
32221da177e4SLinus Torvalds 
32231da177e4SLinus Torvalds 	if (state->neigh_sub_iter) {
32241da177e4SLinus Torvalds 		void *v = state->neigh_sub_iter(state, n, pos);
32251da177e4SLinus Torvalds 		if (v)
32261da177e4SLinus Torvalds 			return n;
32271da177e4SLinus Torvalds 	}
3228767e97e1SEric Dumazet 	n = rcu_dereference_bh(n->next);
32291da177e4SLinus Torvalds 
32301da177e4SLinus Torvalds 	while (1) {
32311da177e4SLinus Torvalds 		while (n) {
3232878628fbSYOSHIFUJI Hideaki 			if (!net_eq(dev_net(n->dev), net))
3233426b5303SEric W. Biederman 				goto next;
32341da177e4SLinus Torvalds 			if (state->neigh_sub_iter) {
32351da177e4SLinus Torvalds 				void *v = state->neigh_sub_iter(state, n, pos);
32361da177e4SLinus Torvalds 				if (v)
32371da177e4SLinus Torvalds 					return n;
32381da177e4SLinus Torvalds 				goto next;
32391da177e4SLinus Torvalds 			}
32401da177e4SLinus Torvalds 			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
32411da177e4SLinus Torvalds 				break;
32421da177e4SLinus Torvalds 
3243*b071af52SEric Dumazet 			if (READ_ONCE(n->nud_state) & ~NUD_NOARP)
32441da177e4SLinus Torvalds 				break;
32451da177e4SLinus Torvalds next:
3246767e97e1SEric Dumazet 			n = rcu_dereference_bh(n->next);
32471da177e4SLinus Torvalds 		}
32481da177e4SLinus Torvalds 
32491da177e4SLinus Torvalds 		if (n)
32501da177e4SLinus Torvalds 			break;
32511da177e4SLinus Torvalds 
3252cd089336SDavid S. Miller 		if (++state->bucket >= (1 << nht->hash_shift))
32531da177e4SLinus Torvalds 			break;
32541da177e4SLinus Torvalds 
3255767e97e1SEric Dumazet 		n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
32561da177e4SLinus Torvalds 	}
32571da177e4SLinus Torvalds 
32581da177e4SLinus Torvalds 	if (n && pos)
32591da177e4SLinus Torvalds 		--(*pos);
32601da177e4SLinus Torvalds 	return n;
32611da177e4SLinus Torvalds }
32621da177e4SLinus Torvalds 
32631da177e4SLinus Torvalds static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
32641da177e4SLinus Torvalds {
32651da177e4SLinus Torvalds 	struct neighbour *n = neigh_get_first(seq);
32661da177e4SLinus Torvalds 
32671da177e4SLinus Torvalds 	if (n) {
3268745e2031SChris Larson 		--(*pos);
32691da177e4SLinus Torvalds 		while (*pos) {
32701da177e4SLinus Torvalds 			n = neigh_get_next(seq, n, pos);
32711da177e4SLinus Torvalds 			if (!n)
32721da177e4SLinus Torvalds 				break;
32731da177e4SLinus Torvalds 		}
32741da177e4SLinus Torvalds 	}
32751da177e4SLinus Torvalds 	return *pos ? NULL : n;
32761da177e4SLinus Torvalds }
32771da177e4SLinus Torvalds 
32781da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
32791da177e4SLinus Torvalds {
32801da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
32811218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
32821da177e4SLinus Torvalds 	struct neigh_table *tbl = state->tbl;
32831da177e4SLinus Torvalds 	struct pneigh_entry *pn = NULL;
328448de7c0cSYang Li 	int bucket;
32851da177e4SLinus Torvalds 
32861da177e4SLinus Torvalds 	state->flags |= NEIGH_SEQ_IS_PNEIGH;
32871da177e4SLinus Torvalds 	for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
32881da177e4SLinus Torvalds 		pn = tbl->phash_buckets[bucket];
3289878628fbSYOSHIFUJI Hideaki 		while (pn && !net_eq(pneigh_net(pn), net))
3290426b5303SEric W. Biederman 			pn = pn->next;
32911da177e4SLinus Torvalds 		if (pn)
32921da177e4SLinus Torvalds 			break;
32931da177e4SLinus Torvalds 	}
32941da177e4SLinus Torvalds 	state->bucket = bucket;
32951da177e4SLinus Torvalds 
32961da177e4SLinus Torvalds 	return pn;
32971da177e4SLinus Torvalds }
32981da177e4SLinus Torvalds 
32991da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
33001da177e4SLinus Torvalds 					    struct pneigh_entry *pn,
33011da177e4SLinus Torvalds 					    loff_t *pos)
33021da177e4SLinus Torvalds {
33031da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
33041218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
33051da177e4SLinus Torvalds 	struct neigh_table *tbl = state->tbl;
33061da177e4SLinus Torvalds 
3307df07a94cSJorge Boncompte [DTI2] 	do {
33081da177e4SLinus Torvalds 		pn = pn->next;
3309df07a94cSJorge Boncompte [DTI2] 	} while (pn && !net_eq(pneigh_net(pn), net));
3310df07a94cSJorge Boncompte [DTI2] 
33111da177e4SLinus Torvalds 	while (!pn) {
33121da177e4SLinus Torvalds 		if (++state->bucket > PNEIGH_HASHMASK)
33131da177e4SLinus Torvalds 			break;
33141da177e4SLinus Torvalds 		pn = tbl->phash_buckets[state->bucket];
3315878628fbSYOSHIFUJI Hideaki 		while (pn && !net_eq(pneigh_net(pn), net))
3316426b5303SEric W. Biederman 			pn = pn->next;
33171da177e4SLinus Torvalds 		if (pn)
33181da177e4SLinus Torvalds 			break;
33191da177e4SLinus Torvalds 	}
33201da177e4SLinus Torvalds 
33211da177e4SLinus Torvalds 	if (pn && pos)
33221da177e4SLinus Torvalds 		--(*pos);
33231da177e4SLinus Torvalds 
33241da177e4SLinus Torvalds 	return pn;
33251da177e4SLinus Torvalds }
33261da177e4SLinus Torvalds 
33271da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
33281da177e4SLinus Torvalds {
33291da177e4SLinus Torvalds 	struct pneigh_entry *pn = pneigh_get_first(seq);
33301da177e4SLinus Torvalds 
33311da177e4SLinus Torvalds 	if (pn) {
3332745e2031SChris Larson 		--(*pos);
33331da177e4SLinus Torvalds 		while (*pos) {
33341da177e4SLinus Torvalds 			pn = pneigh_get_next(seq, pn, pos);
33351da177e4SLinus Torvalds 			if (!pn)
33361da177e4SLinus Torvalds 				break;
33371da177e4SLinus Torvalds 		}
33381da177e4SLinus Torvalds 	}
33391da177e4SLinus Torvalds 	return *pos ? NULL : pn;
33401da177e4SLinus Torvalds }
33411da177e4SLinus Torvalds 
33421da177e4SLinus Torvalds static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
33431da177e4SLinus Torvalds {
33441da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
33451da177e4SLinus Torvalds 	void *rc;
3346745e2031SChris Larson 	loff_t idxpos = *pos;
33471da177e4SLinus Torvalds 
3348745e2031SChris Larson 	rc = neigh_get_idx(seq, &idxpos);
33491da177e4SLinus Torvalds 	if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
3350745e2031SChris Larson 		rc = pneigh_get_idx(seq, &idxpos);
33511da177e4SLinus Torvalds 
33521da177e4SLinus Torvalds 	return rc;
33531da177e4SLinus Torvalds }
33541da177e4SLinus Torvalds 
33551da177e4SLinus Torvalds void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags)
3356f3e92cb8SEric Dumazet 	__acquires(tbl->lock)
3357d6bf7817SEric Dumazet 	__acquires(rcu_bh)
33581da177e4SLinus Torvalds {
33591da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
33601da177e4SLinus Torvalds 
33611da177e4SLinus Torvalds 	state->tbl = tbl;
33621da177e4SLinus Torvalds 	state->bucket = 0;
33631da177e4SLinus Torvalds 	state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
33641da177e4SLinus Torvalds 
3365d6bf7817SEric Dumazet 	rcu_read_lock_bh();
3366d6bf7817SEric Dumazet 	state->nht = rcu_dereference_bh(tbl->nht);
3367f3e92cb8SEric Dumazet 	read_lock(&tbl->lock);
3368767e97e1SEric Dumazet 
3369745e2031SChris Larson 	return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
33701da177e4SLinus Torvalds }
33711da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_start);
33721da177e4SLinus Torvalds 
33731da177e4SLinus Torvalds void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
33741da177e4SLinus Torvalds {
33751da177e4SLinus Torvalds 	struct neigh_seq_state *state;
33761da177e4SLinus Torvalds 	void *rc;
33771da177e4SLinus Torvalds 
33781da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN) {
3379bff69732SChris Larson 		rc = neigh_get_first(seq);
33801da177e4SLinus Torvalds 		goto out;
33811da177e4SLinus Torvalds 	}
33821da177e4SLinus Torvalds 
33831da177e4SLinus Torvalds 	state = seq->private;
33841da177e4SLinus Torvalds 	if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
33851da177e4SLinus Torvalds 		rc = neigh_get_next(seq, v, NULL);
33861da177e4SLinus Torvalds 		if (rc)
33871da177e4SLinus Torvalds 			goto out;
33881da177e4SLinus Torvalds 		if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
33891da177e4SLinus Torvalds 			rc = pneigh_get_first(seq);
33901da177e4SLinus Torvalds 	} else {
33911da177e4SLinus Torvalds 		BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
33921da177e4SLinus Torvalds 		rc = pneigh_get_next(seq, v, NULL);
33931da177e4SLinus Torvalds 	}
33941da177e4SLinus Torvalds out:
33951da177e4SLinus Torvalds 	++(*pos);
33961da177e4SLinus Torvalds 	return rc;
33971da177e4SLinus Torvalds }
33981da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_next);
33991da177e4SLinus Torvalds 
34001da177e4SLinus Torvalds void neigh_seq_stop(struct seq_file *seq, void *v)
3401f3e92cb8SEric Dumazet 	__releases(tbl->lock)
3402d6bf7817SEric Dumazet 	__releases(rcu_bh)
34031da177e4SLinus Torvalds {
3404f3e92cb8SEric Dumazet 	struct neigh_seq_state *state = seq->private;
3405f3e92cb8SEric Dumazet 	struct neigh_table *tbl = state->tbl;
3406f3e92cb8SEric Dumazet 
3407f3e92cb8SEric Dumazet 	read_unlock(&tbl->lock);
3408d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
34091da177e4SLinus Torvalds }
34101da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_stop);
34111da177e4SLinus Torvalds 
34121da177e4SLinus Torvalds /* statistics via seq_file */
34131da177e4SLinus Torvalds 
34141da177e4SLinus Torvalds static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
34151da177e4SLinus Torvalds {
3416359745d7SMuchun Song 	struct neigh_table *tbl = pde_data(file_inode(seq->file));
34171da177e4SLinus Torvalds 	int cpu;
34181da177e4SLinus Torvalds 
34191da177e4SLinus Torvalds 	if (*pos == 0)
34201da177e4SLinus Torvalds 		return SEQ_START_TOKEN;
34211da177e4SLinus Torvalds 
34220f23174aSRusty Russell 	for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
34231da177e4SLinus Torvalds 		if (!cpu_possible(cpu))
34241da177e4SLinus Torvalds 			continue;
34251da177e4SLinus Torvalds 		*pos = cpu+1;
34261da177e4SLinus Torvalds 		return per_cpu_ptr(tbl->stats, cpu);
34271da177e4SLinus Torvalds 	}
34281da177e4SLinus Torvalds 	return NULL;
34291da177e4SLinus Torvalds }
34301da177e4SLinus Torvalds 
34311da177e4SLinus Torvalds static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
34321da177e4SLinus Torvalds {
3433359745d7SMuchun Song 	struct neigh_table *tbl = pde_data(file_inode(seq->file));
34341da177e4SLinus Torvalds 	int cpu;
34351da177e4SLinus Torvalds 
34360f23174aSRusty Russell 	for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
34371da177e4SLinus Torvalds 		if (!cpu_possible(cpu))
34381da177e4SLinus Torvalds 			continue;
34391da177e4SLinus Torvalds 		*pos = cpu+1;
34401da177e4SLinus Torvalds 		return per_cpu_ptr(tbl->stats, cpu);
34411da177e4SLinus Torvalds 	}
34421e3f9f07SVasily Averin 	(*pos)++;
34431da177e4SLinus Torvalds 	return NULL;
34441da177e4SLinus Torvalds }
34451da177e4SLinus Torvalds 
34461da177e4SLinus Torvalds static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
34471da177e4SLinus Torvalds {
34481da177e4SLinus Torvalds 
34491da177e4SLinus Torvalds }
34501da177e4SLinus Torvalds 
34511da177e4SLinus Torvalds static int neigh_stat_seq_show(struct seq_file *seq, void *v)
34521da177e4SLinus Torvalds {
3453359745d7SMuchun Song 	struct neigh_table *tbl = pde_data(file_inode(seq->file));
34541da177e4SLinus Torvalds 	struct neigh_statistics *st = v;
34551da177e4SLinus Torvalds 
34561da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN) {
34570547ffe6SYajun Deng 		seq_puts(seq, "entries  allocs   destroys hash_grows lookups  hits     res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs unresolved_discards table_fulls\n");
34581da177e4SLinus Torvalds 		return 0;
34591da177e4SLinus Torvalds 	}
34601da177e4SLinus Torvalds 
34611da177e4SLinus Torvalds 	seq_printf(seq, "%08x %08lx %08lx %08lx   %08lx %08lx %08lx   "
34620547ffe6SYajun Deng 			"%08lx         %08lx         %08lx         "
34630547ffe6SYajun Deng 			"%08lx       %08lx            %08lx\n",
34641da177e4SLinus Torvalds 		   atomic_read(&tbl->entries),
34651da177e4SLinus Torvalds 
34661da177e4SLinus Torvalds 		   st->allocs,
34671da177e4SLinus Torvalds 		   st->destroys,
34681da177e4SLinus Torvalds 		   st->hash_grows,
34691da177e4SLinus Torvalds 
34701da177e4SLinus Torvalds 		   st->lookups,
34711da177e4SLinus Torvalds 		   st->hits,
34721da177e4SLinus Torvalds 
34731da177e4SLinus Torvalds 		   st->res_failed,
34741da177e4SLinus Torvalds 
34751da177e4SLinus Torvalds 		   st->rcv_probes_mcast,
34761da177e4SLinus Torvalds 		   st->rcv_probes_ucast,
34771da177e4SLinus Torvalds 
34781da177e4SLinus Torvalds 		   st->periodic_gc_runs,
34799a6d276eSNeil Horman 		   st->forced_gc_runs,
3480fb811395SRick Jones 		   st->unres_discards,
3481fb811395SRick Jones 		   st->table_fulls
34821da177e4SLinus Torvalds 		   );
34831da177e4SLinus Torvalds 
34841da177e4SLinus Torvalds 	return 0;
34851da177e4SLinus Torvalds }
34861da177e4SLinus Torvalds 
3487f690808eSStephen Hemminger static const struct seq_operations neigh_stat_seq_ops = {
34881da177e4SLinus Torvalds 	.start	= neigh_stat_seq_start,
34891da177e4SLinus Torvalds 	.next	= neigh_stat_seq_next,
34901da177e4SLinus Torvalds 	.stop	= neigh_stat_seq_stop,
34911da177e4SLinus Torvalds 	.show	= neigh_stat_seq_show,
34921da177e4SLinus Torvalds };
34931da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */
34941da177e4SLinus Torvalds 
34957b8f7a40SRoopa Prabhu static void __neigh_notify(struct neighbour *n, int type, int flags,
34967b8f7a40SRoopa Prabhu 			   u32 pid)
34971da177e4SLinus Torvalds {
3498c346dca1SYOSHIFUJI Hideaki 	struct net *net = dev_net(n->dev);
34998b8aec50SThomas Graf 	struct sk_buff *skb;
3500b8673311SThomas Graf 	int err = -ENOBUFS;
35011da177e4SLinus Torvalds 
3502339bf98fSThomas Graf 	skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
35038b8aec50SThomas Graf 	if (skb == NULL)
3504b8673311SThomas Graf 		goto errout;
35051da177e4SLinus Torvalds 
35067b8f7a40SRoopa Prabhu 	err = neigh_fill_info(skb, n, pid, 0, type, flags);
350726932566SPatrick McHardy 	if (err < 0) {
350826932566SPatrick McHardy 		/* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
350926932566SPatrick McHardy 		WARN_ON(err == -EMSGSIZE);
351026932566SPatrick McHardy 		kfree_skb(skb);
351126932566SPatrick McHardy 		goto errout;
351226932566SPatrick McHardy 	}
35131ce85fe4SPablo Neira Ayuso 	rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
35141ce85fe4SPablo Neira Ayuso 	return;
3515b8673311SThomas Graf errout:
3516b8673311SThomas Graf 	if (err < 0)
3517426b5303SEric W. Biederman 		rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
3518b8673311SThomas Graf }
3519b8673311SThomas Graf 
3520b8673311SThomas Graf void neigh_app_ns(struct neighbour *n)
3521b8673311SThomas Graf {
35227b8f7a40SRoopa Prabhu 	__neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST, 0);
35238b8aec50SThomas Graf }
35240a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_app_ns);
35251da177e4SLinus Torvalds 
35261da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL
3527b93196dcSCong Wang static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
35281da177e4SLinus Torvalds 
3529fe2c6338SJoe Perches static int proc_unres_qlen(struct ctl_table *ctl, int write,
353032927393SChristoph Hellwig 			   void *buffer, size_t *lenp, loff_t *ppos)
35318b5c171bSEric Dumazet {
35328b5c171bSEric Dumazet 	int size, ret;
3533fe2c6338SJoe Perches 	struct ctl_table tmp = *ctl;
35348b5c171bSEric Dumazet 
3535eec4844fSMatteo Croce 	tmp.extra1 = SYSCTL_ZERO;
3536ce46cc64SShan Wei 	tmp.extra2 = &unres_qlen_max;
35378b5c171bSEric Dumazet 	tmp.data = &size;
3538ce46cc64SShan Wei 
3539ce46cc64SShan Wei 	size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN);
3540ce46cc64SShan Wei 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
3541ce46cc64SShan Wei 
35428b5c171bSEric Dumazet 	if (write && !ret)
35438b5c171bSEric Dumazet 		*(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
35448b5c171bSEric Dumazet 	return ret;
35458b5c171bSEric Dumazet }
35468b5c171bSEric Dumazet 
35471d4c8c29SJiri Pirko static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
35481d4c8c29SJiri Pirko 				  int index)
35491d4c8c29SJiri Pirko {
35501d4c8c29SJiri Pirko 	struct net_device *dev;
35511d4c8c29SJiri Pirko 	int family = neigh_parms_family(p);
35521d4c8c29SJiri Pirko 
35531d4c8c29SJiri Pirko 	rcu_read_lock();
35541d4c8c29SJiri Pirko 	for_each_netdev_rcu(net, dev) {
35551d4c8c29SJiri Pirko 		struct neigh_parms *dst_p =
35561d4c8c29SJiri Pirko 				neigh_get_dev_parms_rcu(dev, family);
35571d4c8c29SJiri Pirko 
35581d4c8c29SJiri Pirko 		if (dst_p && !test_bit(index, dst_p->data_state))
35591d4c8c29SJiri Pirko 			dst_p->data[index] = p->data[index];
35601d4c8c29SJiri Pirko 	}
35611d4c8c29SJiri Pirko 	rcu_read_unlock();
35621d4c8c29SJiri Pirko }
35631d4c8c29SJiri Pirko 
35641d4c8c29SJiri Pirko static void neigh_proc_update(struct ctl_table *ctl, int write)
35651d4c8c29SJiri Pirko {
35661d4c8c29SJiri Pirko 	struct net_device *dev = ctl->extra1;
35671d4c8c29SJiri Pirko 	struct neigh_parms *p = ctl->extra2;
356877d47afbSJiri Pirko 	struct net *net = neigh_parms_net(p);
35691d4c8c29SJiri Pirko 	int index = (int *) ctl->data - p->data;
35701d4c8c29SJiri Pirko 
35711d4c8c29SJiri Pirko 	if (!write)
35721d4c8c29SJiri Pirko 		return;
35731d4c8c29SJiri Pirko 
35741d4c8c29SJiri Pirko 	set_bit(index, p->data_state);
35757627ae60SMarcus Huewe 	if (index == NEIGH_VAR_DELAY_PROBE_TIME)
35762a4501aeSIdo Schimmel 		call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
35771d4c8c29SJiri Pirko 	if (!dev) /* NULL dev means this is default value */
35781d4c8c29SJiri Pirko 		neigh_copy_dflt_parms(net, p, index);
35791d4c8c29SJiri Pirko }
35801d4c8c29SJiri Pirko 
35811f9248e5SJiri Pirko static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
358232927393SChristoph Hellwig 					   void *buffer, size_t *lenp,
358332927393SChristoph Hellwig 					   loff_t *ppos)
35841f9248e5SJiri Pirko {
35851f9248e5SJiri Pirko 	struct ctl_table tmp = *ctl;
35861d4c8c29SJiri Pirko 	int ret;
35871f9248e5SJiri Pirko 
3588eec4844fSMatteo Croce 	tmp.extra1 = SYSCTL_ZERO;
3589eec4844fSMatteo Croce 	tmp.extra2 = SYSCTL_INT_MAX;
35901f9248e5SJiri Pirko 
35911d4c8c29SJiri Pirko 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
35921d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
35931d4c8c29SJiri Pirko 	return ret;
35941f9248e5SJiri Pirko }
35951f9248e5SJiri Pirko 
3596211da42eSYuwei Wang static int neigh_proc_dointvec_ms_jiffies_positive(struct ctl_table *ctl, int write,
3597211da42eSYuwei Wang 						   void *buffer, size_t *lenp, loff_t *ppos)
3598211da42eSYuwei Wang {
3599211da42eSYuwei Wang 	struct ctl_table tmp = *ctl;
3600211da42eSYuwei Wang 	int ret;
3601211da42eSYuwei Wang 
3602211da42eSYuwei Wang 	int min = msecs_to_jiffies(1);
3603211da42eSYuwei Wang 
3604211da42eSYuwei Wang 	tmp.extra1 = &min;
3605211da42eSYuwei Wang 	tmp.extra2 = NULL;
3606211da42eSYuwei Wang 
3607211da42eSYuwei Wang 	ret = proc_dointvec_ms_jiffies_minmax(&tmp, write, buffer, lenp, ppos);
3608211da42eSYuwei Wang 	neigh_proc_update(ctl, write);
3609211da42eSYuwei Wang 	return ret;
3610211da42eSYuwei Wang }
3611211da42eSYuwei Wang 
361232927393SChristoph Hellwig int neigh_proc_dointvec(struct ctl_table *ctl, int write, void *buffer,
361332927393SChristoph Hellwig 			size_t *lenp, loff_t *ppos)
3614cb5b09c1SJiri Pirko {
36151d4c8c29SJiri Pirko 	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
36161d4c8c29SJiri Pirko 
36171d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36181d4c8c29SJiri Pirko 	return ret;
3619cb5b09c1SJiri Pirko }
3620cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec);
3621cb5b09c1SJiri Pirko 
362232927393SChristoph Hellwig int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, void *buffer,
3623cb5b09c1SJiri Pirko 				size_t *lenp, loff_t *ppos)
3624cb5b09c1SJiri Pirko {
36251d4c8c29SJiri Pirko 	int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
36261d4c8c29SJiri Pirko 
36271d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36281d4c8c29SJiri Pirko 	return ret;
3629cb5b09c1SJiri Pirko }
3630cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
3631cb5b09c1SJiri Pirko 
3632cb5b09c1SJiri Pirko static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write,
363332927393SChristoph Hellwig 					      void *buffer, size_t *lenp,
363432927393SChristoph Hellwig 					      loff_t *ppos)
3635cb5b09c1SJiri Pirko {
36361d4c8c29SJiri Pirko 	int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
36371d4c8c29SJiri Pirko 
36381d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36391d4c8c29SJiri Pirko 	return ret;
3640cb5b09c1SJiri Pirko }
3641cb5b09c1SJiri Pirko 
3642cb5b09c1SJiri Pirko int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
364332927393SChristoph Hellwig 				   void *buffer, size_t *lenp, loff_t *ppos)
3644cb5b09c1SJiri Pirko {
36451d4c8c29SJiri Pirko 	int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
36461d4c8c29SJiri Pirko 
36471d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36481d4c8c29SJiri Pirko 	return ret;
3649cb5b09c1SJiri Pirko }
3650cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
3651cb5b09c1SJiri Pirko 
3652cb5b09c1SJiri Pirko static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
365332927393SChristoph Hellwig 					  void *buffer, size_t *lenp,
365432927393SChristoph Hellwig 					  loff_t *ppos)
3655cb5b09c1SJiri Pirko {
36561d4c8c29SJiri Pirko 	int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
36571d4c8c29SJiri Pirko 
36581d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36591d4c8c29SJiri Pirko 	return ret;
3660cb5b09c1SJiri Pirko }
3661cb5b09c1SJiri Pirko 
36624bf6980dSJean-Francois Remy static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write,
366332927393SChristoph Hellwig 					  void *buffer, size_t *lenp,
366432927393SChristoph Hellwig 					  loff_t *ppos)
36654bf6980dSJean-Francois Remy {
36664bf6980dSJean-Francois Remy 	struct neigh_parms *p = ctl->extra2;
36674bf6980dSJean-Francois Remy 	int ret;
36684bf6980dSJean-Francois Remy 
36694bf6980dSJean-Francois Remy 	if (strcmp(ctl->procname, "base_reachable_time") == 0)
36704bf6980dSJean-Francois Remy 		ret = neigh_proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
36714bf6980dSJean-Francois Remy 	else if (strcmp(ctl->procname, "base_reachable_time_ms") == 0)
36724bf6980dSJean-Francois Remy 		ret = neigh_proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
36734bf6980dSJean-Francois Remy 	else
36744bf6980dSJean-Francois Remy 		ret = -1;
36754bf6980dSJean-Francois Remy 
36764bf6980dSJean-Francois Remy 	if (write && ret == 0) {
36774bf6980dSJean-Francois Remy 		/* update reachable_time as well, otherwise, the change will
36784bf6980dSJean-Francois Remy 		 * only be effective after the next time neigh_periodic_work
36794bf6980dSJean-Francois Remy 		 * decides to recompute it
36804bf6980dSJean-Francois Remy 		 */
36814bf6980dSJean-Francois Remy 		p->reachable_time =
36824bf6980dSJean-Francois Remy 			neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
36834bf6980dSJean-Francois Remy 	}
36844bf6980dSJean-Francois Remy 	return ret;
36854bf6980dSJean-Francois Remy }
36864bf6980dSJean-Francois Remy 
36871f9248e5SJiri Pirko #define NEIGH_PARMS_DATA_OFFSET(index)	\
36881f9248e5SJiri Pirko 	(&((struct neigh_parms *) 0)->data[index])
36891f9248e5SJiri Pirko 
36901f9248e5SJiri Pirko #define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \
36911f9248e5SJiri Pirko 	[NEIGH_VAR_ ## attr] = { \
36921f9248e5SJiri Pirko 		.procname	= name, \
36931f9248e5SJiri Pirko 		.data		= NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \
36941f9248e5SJiri Pirko 		.maxlen		= sizeof(int), \
36951f9248e5SJiri Pirko 		.mode		= mval, \
36961f9248e5SJiri Pirko 		.proc_handler	= proc, \
36971f9248e5SJiri Pirko 	}
36981f9248e5SJiri Pirko 
36991f9248e5SJiri Pirko #define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \
37001f9248e5SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax)
37011f9248e5SJiri Pirko 
37021f9248e5SJiri Pirko #define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \
3703cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies)
37041f9248e5SJiri Pirko 
37051f9248e5SJiri Pirko #define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
3706cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)
37071f9248e5SJiri Pirko 
3708211da42eSYuwei Wang #define NEIGH_SYSCTL_MS_JIFFIES_POSITIVE_ENTRY(attr, name) \
3709211da42eSYuwei Wang 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_ms_jiffies_positive)
3710211da42eSYuwei Wang 
37111f9248e5SJiri Pirko #define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \
3712cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
37131f9248e5SJiri Pirko 
37141f9248e5SJiri Pirko #define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \
3715cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_unres_qlen)
371654716e3bSEric W. Biederman 
37171da177e4SLinus Torvalds static struct neigh_sysctl_table {
37181da177e4SLinus Torvalds 	struct ctl_table_header *sysctl_header;
37198b5c171bSEric Dumazet 	struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
3720ab32ea5dSBrian Haley } neigh_sysctl_template __read_mostly = {
37211da177e4SLinus Torvalds 	.neigh_vars = {
37221f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"),
37231f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"),
37241f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"),
37258da86466SYOSHIFUJI Hideaki/吉藤英明 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_REPROBES, "mcast_resolicit"),
37261f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),
37271f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),
37281f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"),
3729211da42eSYuwei Wang 		NEIGH_SYSCTL_MS_JIFFIES_POSITIVE_ENTRY(INTERVAL_PROBE_TIME_MS,
3730211da42eSYuwei Wang 						       "interval_probe_time_ms"),
37311f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"),
37321f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"),
37331f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"),
37341f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"),
37351f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"),
37361f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"),
37371f9248e5SJiri Pirko 		NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"),
37381f9248e5SJiri Pirko 		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"),
37391f9248e5SJiri Pirko 		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"),
37408b5c171bSEric Dumazet 		[NEIGH_VAR_GC_INTERVAL] = {
37411da177e4SLinus Torvalds 			.procname	= "gc_interval",
37421da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
37431da177e4SLinus Torvalds 			.mode		= 0644,
37446d9f239aSAlexey Dobriyan 			.proc_handler	= proc_dointvec_jiffies,
37451da177e4SLinus Torvalds 		},
37468b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH1] = {
37471da177e4SLinus Torvalds 			.procname	= "gc_thresh1",
37481da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
37491da177e4SLinus Torvalds 			.mode		= 0644,
3750eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3751eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3752555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
37531da177e4SLinus Torvalds 		},
37548b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH2] = {
37551da177e4SLinus Torvalds 			.procname	= "gc_thresh2",
37561da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
37571da177e4SLinus Torvalds 			.mode		= 0644,
3758eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3759eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3760555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
37611da177e4SLinus Torvalds 		},
37628b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH3] = {
37631da177e4SLinus Torvalds 			.procname	= "gc_thresh3",
37641da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
37651da177e4SLinus Torvalds 			.mode		= 0644,
3766eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3767eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3768555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
37691da177e4SLinus Torvalds 		},
3770c3bac5a7SPavel Emelyanov 		{},
37711da177e4SLinus Torvalds 	},
37721da177e4SLinus Torvalds };
37731da177e4SLinus Torvalds 
37741da177e4SLinus Torvalds int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
377573af614aSJiri Pirko 			  proc_handler *handler)
37761da177e4SLinus Torvalds {
37771f9248e5SJiri Pirko 	int i;
37783c607bbbSPavel Emelyanov 	struct neigh_sysctl_table *t;
37791f9248e5SJiri Pirko 	const char *dev_name_source;
37808f40a1f9SEric W. Biederman 	char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
378173af614aSJiri Pirko 	char *p_name;
37821da177e4SLinus Torvalds 
3783425b9c7fSVasily Averin 	t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL_ACCOUNT);
37841da177e4SLinus Torvalds 	if (!t)
37853c607bbbSPavel Emelyanov 		goto err;
37863c607bbbSPavel Emelyanov 
3787b194c1f1SJiri Pirko 	for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
37881f9248e5SJiri Pirko 		t->neigh_vars[i].data += (long) p;
3789cb5b09c1SJiri Pirko 		t->neigh_vars[i].extra1 = dev;
37901d4c8c29SJiri Pirko 		t->neigh_vars[i].extra2 = p;
3791cb5b09c1SJiri Pirko 	}
37921da177e4SLinus Torvalds 
37931da177e4SLinus Torvalds 	if (dev) {
37941da177e4SLinus Torvalds 		dev_name_source = dev->name;
3795d12af679SEric W. Biederman 		/* Terminate the table early */
37968b5c171bSEric Dumazet 		memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
37978b5c171bSEric Dumazet 		       sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
37981da177e4SLinus Torvalds 	} else {
37999ecf07a1SMathias Krause 		struct neigh_table *tbl = p->tbl;
38008f40a1f9SEric W. Biederman 		dev_name_source = "default";
38019ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = &tbl->gc_interval;
38029ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = &tbl->gc_thresh1;
38039ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = &tbl->gc_thresh2;
38049ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = &tbl->gc_thresh3;
38051da177e4SLinus Torvalds 	}
38061da177e4SLinus Torvalds 
3807f8572d8fSEric W. Biederman 	if (handler) {
38081da177e4SLinus Torvalds 		/* RetransTime */
38098b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
38101da177e4SLinus Torvalds 		/* ReachableTime */
38118b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
38121da177e4SLinus Torvalds 		/* RetransTime (in milliseconds)*/
38138b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
38141da177e4SLinus Torvalds 		/* ReachableTime (in milliseconds) */
38158b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
38164bf6980dSJean-Francois Remy 	} else {
38174bf6980dSJean-Francois Remy 		/* Those handlers will update p->reachable_time after
38184bf6980dSJean-Francois Remy 		 * base_reachable_time(_ms) is set to ensure the new timer starts being
38194bf6980dSJean-Francois Remy 		 * applied after the next neighbour update instead of waiting for
38204bf6980dSJean-Francois Remy 		 * neigh_periodic_work to update its value (can be multiple minutes)
38214bf6980dSJean-Francois Remy 		 * So any handler that replaces them should do this as well
38224bf6980dSJean-Francois Remy 		 */
38234bf6980dSJean-Francois Remy 		/* ReachableTime */
38244bf6980dSJean-Francois Remy 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler =
38254bf6980dSJean-Francois Remy 			neigh_proc_base_reachable_time;
38264bf6980dSJean-Francois Remy 		/* ReachableTime (in milliseconds) */
38274bf6980dSJean-Francois Remy 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler =
38284bf6980dSJean-Francois Remy 			neigh_proc_base_reachable_time;
38291da177e4SLinus Torvalds 	}
38301da177e4SLinus Torvalds 
383173af614aSJiri Pirko 	switch (neigh_parms_family(p)) {
383273af614aSJiri Pirko 	case AF_INET:
383373af614aSJiri Pirko 	      p_name = "ipv4";
383473af614aSJiri Pirko 	      break;
383573af614aSJiri Pirko 	case AF_INET6:
383673af614aSJiri Pirko 	      p_name = "ipv6";
383773af614aSJiri Pirko 	      break;
383873af614aSJiri Pirko 	default:
383973af614aSJiri Pirko 	      BUG();
384073af614aSJiri Pirko 	}
384173af614aSJiri Pirko 
38428f40a1f9SEric W. Biederman 	snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
38438f40a1f9SEric W. Biederman 		p_name, dev_name_source);
38444ab438fcSDenis V. Lunev 	t->sysctl_header =
38458f40a1f9SEric W. Biederman 		register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
38463c607bbbSPavel Emelyanov 	if (!t->sysctl_header)
38478f40a1f9SEric W. Biederman 		goto free;
38483c607bbbSPavel Emelyanov 
38491da177e4SLinus Torvalds 	p->sysctl_table = t;
38501da177e4SLinus Torvalds 	return 0;
38511da177e4SLinus Torvalds 
38521da177e4SLinus Torvalds free:
38531da177e4SLinus Torvalds 	kfree(t);
38543c607bbbSPavel Emelyanov err:
38553c607bbbSPavel Emelyanov 	return -ENOBUFS;
38561da177e4SLinus Torvalds }
38570a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_sysctl_register);
38581da177e4SLinus Torvalds 
38591da177e4SLinus Torvalds void neigh_sysctl_unregister(struct neigh_parms *p)
38601da177e4SLinus Torvalds {
38611da177e4SLinus Torvalds 	if (p->sysctl_table) {
38621da177e4SLinus Torvalds 		struct neigh_sysctl_table *t = p->sysctl_table;
38631da177e4SLinus Torvalds 		p->sysctl_table = NULL;
38645dd3df10SEric W. Biederman 		unregister_net_sysctl_table(t->sysctl_header);
38651da177e4SLinus Torvalds 		kfree(t);
38661da177e4SLinus Torvalds 	}
38671da177e4SLinus Torvalds }
38680a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_sysctl_unregister);
38691da177e4SLinus Torvalds 
38701da177e4SLinus Torvalds #endif	/* CONFIG_SYSCTL */
38711da177e4SLinus Torvalds 
3872c8822a4eSThomas Graf static int __init neigh_init(void)
3873c8822a4eSThomas Graf {
3874b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0);
3875b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0);
387682cbb5c6SRoopa Prabhu 	rtnl_register(PF_UNSPEC, RTM_GETNEIGH, neigh_get, neigh_dump_info, 0);
3877c8822a4eSThomas Graf 
3878c7ac8679SGreg Rose 	rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
3879b97bac64SFlorian Westphal 		      0);
3880b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, 0);
3881c8822a4eSThomas Graf 
3882c8822a4eSThomas Graf 	return 0;
3883c8822a4eSThomas Graf }
3884c8822a4eSThomas Graf 
3885c8822a4eSThomas Graf subsys_initcall(neigh_init);
3886