xref: /openbmc/linux/net/core/neighbour.c (revision 8207f253)
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 {
11481895a65SJason A. Donenfeld 	return base ? prandom_u32_max(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)) ||
272e997f8a2SDavid Ahern 			    time_after(tref, n->updated))
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 {
292a43d8994SPavel Emelyanov 	neigh_hold(n);
293a43d8994SPavel Emelyanov 	if (unlikely(mod_timer(&n->timer, when))) {
294a43d8994SPavel Emelyanov 		printk("NEIGH: BUG, double timer add, state is %x\n",
295a43d8994SPavel Emelyanov 		       n->nud_state);
296a43d8994SPavel Emelyanov 		dump_stack();
297a43d8994SPavel Emelyanov 	}
298a43d8994SPavel Emelyanov }
299a43d8994SPavel Emelyanov 
3001da177e4SLinus Torvalds static int neigh_del_timer(struct neighbour *n)
3011da177e4SLinus Torvalds {
3021da177e4SLinus Torvalds 	if ((n->nud_state & NUD_IN_TIMER) &&
3031da177e4SLinus Torvalds 	    del_timer(&n->timer)) {
3041da177e4SLinus Torvalds 		neigh_release(n);
3051da177e4SLinus Torvalds 		return 1;
3061da177e4SLinus Torvalds 	}
3071da177e4SLinus Torvalds 	return 0;
3081da177e4SLinus Torvalds }
3091da177e4SLinus Torvalds 
310*8207f253SThomas Zeitlhofer static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
311*8207f253SThomas Zeitlhofer 						   int family)
312*8207f253SThomas Zeitlhofer {
313*8207f253SThomas Zeitlhofer 	switch (family) {
314*8207f253SThomas Zeitlhofer 	case AF_INET:
315*8207f253SThomas Zeitlhofer 		return __in_dev_arp_parms_get_rcu(dev);
316*8207f253SThomas Zeitlhofer 	case AF_INET6:
317*8207f253SThomas Zeitlhofer 		return __in6_dev_nd_parms_get_rcu(dev);
318*8207f253SThomas Zeitlhofer 	}
319*8207f253SThomas Zeitlhofer 	return NULL;
320*8207f253SThomas Zeitlhofer }
321*8207f253SThomas Zeitlhofer 
322*8207f253SThomas Zeitlhofer static void neigh_parms_qlen_dec(struct net_device *dev, int family)
323*8207f253SThomas Zeitlhofer {
324*8207f253SThomas Zeitlhofer 	struct neigh_parms *p;
325*8207f253SThomas Zeitlhofer 
326*8207f253SThomas Zeitlhofer 	rcu_read_lock();
327*8207f253SThomas Zeitlhofer 	p = neigh_get_dev_parms_rcu(dev, family);
328*8207f253SThomas Zeitlhofer 	if (p)
329*8207f253SThomas Zeitlhofer 		p->qlen--;
330*8207f253SThomas Zeitlhofer 	rcu_read_unlock();
331*8207f253SThomas Zeitlhofer }
332*8207f253SThomas Zeitlhofer 
333*8207f253SThomas Zeitlhofer static void pneigh_queue_purge(struct sk_buff_head *list, struct net *net,
334*8207f253SThomas Zeitlhofer 			       int family)
3351da177e4SLinus Torvalds {
336d5485d9dSYang Yingliang 	struct sk_buff_head tmp;
33766ba215cSDenis V. Lunev 	unsigned long flags;
3381da177e4SLinus Torvalds 	struct sk_buff *skb;
3391da177e4SLinus Torvalds 
340d5485d9dSYang Yingliang 	skb_queue_head_init(&tmp);
34166ba215cSDenis V. Lunev 	spin_lock_irqsave(&list->lock, flags);
34266ba215cSDenis V. Lunev 	skb = skb_peek(list);
34366ba215cSDenis V. Lunev 	while (skb != NULL) {
34466ba215cSDenis V. Lunev 		struct sk_buff *skb_next = skb_peek_next(skb, list);
3450ff4eb3dSAlexander Mikhalitsyn 		struct net_device *dev = skb->dev;
346d5485d9dSYang Yingliang 
3470ff4eb3dSAlexander Mikhalitsyn 		if (net == NULL || net_eq(dev_net(dev), net)) {
348*8207f253SThomas Zeitlhofer 			neigh_parms_qlen_dec(dev, family);
34966ba215cSDenis V. Lunev 			__skb_unlink(skb, list);
350d5485d9dSYang Yingliang 			__skb_queue_tail(&tmp, skb);
3511da177e4SLinus Torvalds 		}
35266ba215cSDenis V. Lunev 		skb = skb_next;
35366ba215cSDenis V. Lunev 	}
35466ba215cSDenis V. Lunev 	spin_unlock_irqrestore(&list->lock, flags);
355d5485d9dSYang Yingliang 
356d5485d9dSYang Yingliang 	while ((skb = __skb_dequeue(&tmp))) {
357d5485d9dSYang Yingliang 		dev_put(skb->dev);
358d5485d9dSYang Yingliang 		kfree_skb(skb);
359d5485d9dSYang Yingliang 	}
3601da177e4SLinus Torvalds }
3611da177e4SLinus Torvalds 
362859bd2efSDavid Ahern static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev,
363859bd2efSDavid Ahern 			    bool skip_perm)
3641da177e4SLinus Torvalds {
3651da177e4SLinus Torvalds 	int i;
366d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
3671da177e4SLinus Torvalds 
368d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
369d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
370d6bf7817SEric Dumazet 
371cd089336SDavid S. Miller 	for (i = 0; i < (1 << nht->hash_shift); i++) {
372767e97e1SEric Dumazet 		struct neighbour *n;
373767e97e1SEric Dumazet 		struct neighbour __rcu **np = &nht->hash_buckets[i];
3741da177e4SLinus Torvalds 
375767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
376767e97e1SEric Dumazet 					lockdep_is_held(&tbl->lock))) != NULL) {
3771da177e4SLinus Torvalds 			if (dev && n->dev != dev) {
3781da177e4SLinus Torvalds 				np = &n->next;
3791da177e4SLinus Torvalds 				continue;
3801da177e4SLinus Torvalds 			}
381859bd2efSDavid Ahern 			if (skip_perm && n->nud_state & NUD_PERMANENT) {
382859bd2efSDavid Ahern 				np = &n->next;
383859bd2efSDavid Ahern 				continue;
384859bd2efSDavid Ahern 			}
385767e97e1SEric Dumazet 			rcu_assign_pointer(*np,
386767e97e1SEric Dumazet 				   rcu_dereference_protected(n->next,
387767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
3881da177e4SLinus Torvalds 			write_lock(&n->lock);
3891da177e4SLinus Torvalds 			neigh_del_timer(n);
39058956317SDavid Ahern 			neigh_mark_dead(n);
3919f237430SReshetova, Elena 			if (refcount_read(&n->refcnt) != 1) {
3921da177e4SLinus Torvalds 				/* The most unpleasant situation.
3931da177e4SLinus Torvalds 				   We must destroy neighbour entry,
3941da177e4SLinus Torvalds 				   but someone still uses it.
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds 				   The destroy will be delayed until
3971da177e4SLinus Torvalds 				   the last user releases us, but
3981da177e4SLinus Torvalds 				   we must kill timers etc. and move
3991da177e4SLinus Torvalds 				   it to safe state.
4001da177e4SLinus Torvalds 				 */
401c9ab4d85SEric Dumazet 				__skb_queue_purge(&n->arp_queue);
4028b5c171bSEric Dumazet 				n->arp_queue_len_bytes = 0;
4031da177e4SLinus Torvalds 				n->output = neigh_blackhole;
4041da177e4SLinus Torvalds 				if (n->nud_state & NUD_VALID)
4051da177e4SLinus Torvalds 					n->nud_state = NUD_NOARP;
4061da177e4SLinus Torvalds 				else
4071da177e4SLinus Torvalds 					n->nud_state = NUD_NONE;
408d5d427cdSJoe Perches 				neigh_dbg(2, "neigh %p is stray\n", n);
4091da177e4SLinus Torvalds 			}
4101da177e4SLinus Torvalds 			write_unlock(&n->lock);
4114f494554SThomas Graf 			neigh_cleanup_and_release(n);
4121da177e4SLinus Torvalds 		}
4131da177e4SLinus Torvalds 	}
41449636bb1SHerbert Xu }
4151da177e4SLinus Torvalds 
41649636bb1SHerbert Xu void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
41749636bb1SHerbert Xu {
41849636bb1SHerbert Xu 	write_lock_bh(&tbl->lock);
419859bd2efSDavid Ahern 	neigh_flush_dev(tbl, dev, false);
42049636bb1SHerbert Xu 	write_unlock_bh(&tbl->lock);
42149636bb1SHerbert Xu }
4220a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_changeaddr);
42349636bb1SHerbert Xu 
424859bd2efSDavid Ahern static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
425859bd2efSDavid Ahern 			  bool skip_perm)
42649636bb1SHerbert Xu {
42749636bb1SHerbert Xu 	write_lock_bh(&tbl->lock);
428859bd2efSDavid Ahern 	neigh_flush_dev(tbl, dev, skip_perm);
42953b76cdfSWolfgang Bumiller 	pneigh_ifdown_and_unlock(tbl, dev);
430*8207f253SThomas Zeitlhofer 	pneigh_queue_purge(&tbl->proxy_queue, dev ? dev_net(dev) : NULL,
431*8207f253SThomas Zeitlhofer 			   tbl->family);
43266ba215cSDenis V. Lunev 	if (skb_queue_empty_lockless(&tbl->proxy_queue))
4331da177e4SLinus Torvalds 		del_timer_sync(&tbl->proxy_timer);
4341da177e4SLinus Torvalds 	return 0;
4351da177e4SLinus Torvalds }
436859bd2efSDavid Ahern 
437859bd2efSDavid Ahern int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev)
438859bd2efSDavid Ahern {
439859bd2efSDavid Ahern 	__neigh_ifdown(tbl, dev, true);
440859bd2efSDavid Ahern 	return 0;
441859bd2efSDavid Ahern }
442859bd2efSDavid Ahern EXPORT_SYMBOL(neigh_carrier_down);
443859bd2efSDavid Ahern 
444859bd2efSDavid Ahern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
445859bd2efSDavid Ahern {
446859bd2efSDavid Ahern 	__neigh_ifdown(tbl, dev, false);
447859bd2efSDavid Ahern 	return 0;
448859bd2efSDavid Ahern }
4490a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_ifdown);
4501da177e4SLinus Torvalds 
45158956317SDavid Ahern static struct neighbour *neigh_alloc(struct neigh_table *tbl,
45258956317SDavid Ahern 				     struct net_device *dev,
4532c611ad9SRoopa Prabhu 				     u32 flags, bool exempt_from_gc)
4541da177e4SLinus Torvalds {
4551da177e4SLinus Torvalds 	struct neighbour *n = NULL;
4561da177e4SLinus Torvalds 	unsigned long now = jiffies;
4571da177e4SLinus Torvalds 	int entries;
4581da177e4SLinus Torvalds 
459e997f8a2SDavid Ahern 	if (exempt_from_gc)
46058956317SDavid Ahern 		goto do_alloc;
46158956317SDavid Ahern 
46258956317SDavid Ahern 	entries = atomic_inc_return(&tbl->gc_entries) - 1;
4631da177e4SLinus Torvalds 	if (entries >= tbl->gc_thresh3 ||
4641da177e4SLinus Torvalds 	    (entries >= tbl->gc_thresh2 &&
4651da177e4SLinus Torvalds 	     time_after(now, tbl->last_flush + 5 * HZ))) {
4661da177e4SLinus Torvalds 		if (!neigh_forced_gc(tbl) &&
467fb811395SRick Jones 		    entries >= tbl->gc_thresh3) {
468fb811395SRick Jones 			net_info_ratelimited("%s: neighbor table overflow!\n",
469fb811395SRick Jones 					     tbl->id);
470fb811395SRick Jones 			NEIGH_CACHE_STAT_INC(tbl, table_fulls);
4711da177e4SLinus Torvalds 			goto out_entries;
4721da177e4SLinus Torvalds 		}
473fb811395SRick Jones 	}
4741da177e4SLinus Torvalds 
47558956317SDavid Ahern do_alloc:
47608433effSYOSHIFUJI Hideaki / 吉藤英明 	n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
4771da177e4SLinus Torvalds 	if (!n)
4781da177e4SLinus Torvalds 		goto out_entries;
4791da177e4SLinus Torvalds 
480c9ab4d85SEric Dumazet 	__skb_queue_head_init(&n->arp_queue);
4811da177e4SLinus Torvalds 	rwlock_init(&n->lock);
4820ed8ddf4SEric Dumazet 	seqlock_init(&n->ha_lock);
4831da177e4SLinus Torvalds 	n->updated	  = n->used = now;
4841da177e4SLinus Torvalds 	n->nud_state	  = NUD_NONE;
4851da177e4SLinus Torvalds 	n->output	  = neigh_blackhole;
486e4400bbfSDaniel Borkmann 	n->flags	  = flags;
487f6b72b62SDavid S. Miller 	seqlock_init(&n->hh.hh_lock);
4881da177e4SLinus Torvalds 	n->parms	  = neigh_parms_clone(&tbl->parms);
489e99e88a9SKees Cook 	timer_setup(&n->timer, neigh_timer_handler, 0);
4901da177e4SLinus Torvalds 
4911da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, allocs);
4921da177e4SLinus Torvalds 	n->tbl		  = tbl;
4939f237430SReshetova, Elena 	refcount_set(&n->refcnt, 1);
4941da177e4SLinus Torvalds 	n->dead		  = 1;
49558956317SDavid Ahern 	INIT_LIST_HEAD(&n->gc_list);
4967482e384SDaniel Borkmann 	INIT_LIST_HEAD(&n->managed_list);
49758956317SDavid Ahern 
49858956317SDavid Ahern 	atomic_inc(&tbl->entries);
4991da177e4SLinus Torvalds out:
5001da177e4SLinus Torvalds 	return n;
5011da177e4SLinus Torvalds 
5021da177e4SLinus Torvalds out_entries:
503e997f8a2SDavid Ahern 	if (!exempt_from_gc)
50458956317SDavid Ahern 		atomic_dec(&tbl->gc_entries);
5051da177e4SLinus Torvalds 	goto out;
5061da177e4SLinus Torvalds }
5071da177e4SLinus Torvalds 
5082c2aba6cSDavid S. Miller static void neigh_get_hash_rnd(u32 *x)
5092c2aba6cSDavid S. Miller {
510b3d0f789SJason A. Donenfeld 	*x = get_random_u32() | 1;
5112c2aba6cSDavid S. Miller }
5122c2aba6cSDavid S. Miller 
513cd089336SDavid S. Miller static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
5141da177e4SLinus Torvalds {
515cd089336SDavid S. Miller 	size_t size = (1 << shift) * sizeof(struct neighbour *);
516d6bf7817SEric Dumazet 	struct neigh_hash_table *ret;
5176193d2beSEric Dumazet 	struct neighbour __rcu **buckets;
5182c2aba6cSDavid S. Miller 	int i;
5191da177e4SLinus Torvalds 
520d6bf7817SEric Dumazet 	ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
521d6bf7817SEric Dumazet 	if (!ret)
522d6bf7817SEric Dumazet 		return NULL;
52385704cb8SKonstantin Khlebnikov 	if (size <= PAGE_SIZE) {
524d6bf7817SEric Dumazet 		buckets = kzalloc(size, GFP_ATOMIC);
52585704cb8SKonstantin Khlebnikov 	} else {
5266193d2beSEric Dumazet 		buckets = (struct neighbour __rcu **)
527d6bf7817SEric Dumazet 			  __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
528d6bf7817SEric Dumazet 					   get_order(size));
52901b833abSKonstantin Khlebnikov 		kmemleak_alloc(buckets, size, 1, GFP_ATOMIC);
53085704cb8SKonstantin Khlebnikov 	}
531d6bf7817SEric Dumazet 	if (!buckets) {
532d6bf7817SEric Dumazet 		kfree(ret);
533d6bf7817SEric Dumazet 		return NULL;
5341da177e4SLinus Torvalds 	}
5356193d2beSEric Dumazet 	ret->hash_buckets = buckets;
536cd089336SDavid S. Miller 	ret->hash_shift = shift;
5372c2aba6cSDavid S. Miller 	for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
5382c2aba6cSDavid S. Miller 		neigh_get_hash_rnd(&ret->hash_rnd[i]);
5391da177e4SLinus Torvalds 	return ret;
5401da177e4SLinus Torvalds }
5411da177e4SLinus Torvalds 
542d6bf7817SEric Dumazet static void neigh_hash_free_rcu(struct rcu_head *head)
5431da177e4SLinus Torvalds {
544d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = container_of(head,
545d6bf7817SEric Dumazet 						    struct neigh_hash_table,
546d6bf7817SEric Dumazet 						    rcu);
547cd089336SDavid S. Miller 	size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
5486193d2beSEric Dumazet 	struct neighbour __rcu **buckets = nht->hash_buckets;
5491da177e4SLinus Torvalds 
55085704cb8SKonstantin Khlebnikov 	if (size <= PAGE_SIZE) {
551d6bf7817SEric Dumazet 		kfree(buckets);
55285704cb8SKonstantin Khlebnikov 	} else {
55385704cb8SKonstantin Khlebnikov 		kmemleak_free(buckets);
554d6bf7817SEric Dumazet 		free_pages((unsigned long)buckets, get_order(size));
55585704cb8SKonstantin Khlebnikov 	}
556d6bf7817SEric Dumazet 	kfree(nht);
5571da177e4SLinus Torvalds }
5581da177e4SLinus Torvalds 
559d6bf7817SEric Dumazet static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
560cd089336SDavid S. Miller 						unsigned long new_shift)
5611da177e4SLinus Torvalds {
562d6bf7817SEric Dumazet 	unsigned int i, hash;
563d6bf7817SEric Dumazet 	struct neigh_hash_table *new_nht, *old_nht;
5641da177e4SLinus Torvalds 
5651da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, hash_grows);
5661da177e4SLinus Torvalds 
567d6bf7817SEric Dumazet 	old_nht = rcu_dereference_protected(tbl->nht,
568d6bf7817SEric Dumazet 					    lockdep_is_held(&tbl->lock));
569cd089336SDavid S. Miller 	new_nht = neigh_hash_alloc(new_shift);
570d6bf7817SEric Dumazet 	if (!new_nht)
571d6bf7817SEric Dumazet 		return old_nht;
5721da177e4SLinus Torvalds 
573cd089336SDavid S. Miller 	for (i = 0; i < (1 << old_nht->hash_shift); i++) {
5741da177e4SLinus Torvalds 		struct neighbour *n, *next;
5751da177e4SLinus Torvalds 
576767e97e1SEric Dumazet 		for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
577767e97e1SEric Dumazet 						   lockdep_is_held(&tbl->lock));
578d6bf7817SEric Dumazet 		     n != NULL;
579d6bf7817SEric Dumazet 		     n = next) {
580d6bf7817SEric Dumazet 			hash = tbl->hash(n->primary_key, n->dev,
581d6bf7817SEric Dumazet 					 new_nht->hash_rnd);
5821da177e4SLinus Torvalds 
583cd089336SDavid S. Miller 			hash >>= (32 - new_nht->hash_shift);
584767e97e1SEric Dumazet 			next = rcu_dereference_protected(n->next,
585767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock));
5861da177e4SLinus Torvalds 
587767e97e1SEric Dumazet 			rcu_assign_pointer(n->next,
588767e97e1SEric Dumazet 					   rcu_dereference_protected(
589767e97e1SEric Dumazet 						new_nht->hash_buckets[hash],
590767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
591767e97e1SEric Dumazet 			rcu_assign_pointer(new_nht->hash_buckets[hash], n);
5921da177e4SLinus Torvalds 		}
5931da177e4SLinus Torvalds 	}
5941da177e4SLinus Torvalds 
595d6bf7817SEric Dumazet 	rcu_assign_pointer(tbl->nht, new_nht);
596d6bf7817SEric Dumazet 	call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
597d6bf7817SEric Dumazet 	return new_nht;
5981da177e4SLinus Torvalds }
5991da177e4SLinus Torvalds 
6001da177e4SLinus Torvalds struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
6011da177e4SLinus Torvalds 			       struct net_device *dev)
6021da177e4SLinus Torvalds {
6031da177e4SLinus Torvalds 	struct neighbour *n;
6041da177e4SLinus Torvalds 
6051da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, lookups);
6061da177e4SLinus Torvalds 
607d6bf7817SEric Dumazet 	rcu_read_lock_bh();
60860395a20SEric W. Biederman 	n = __neigh_lookup_noref(tbl, pkey, dev);
60960395a20SEric W. Biederman 	if (n) {
6109f237430SReshetova, Elena 		if (!refcount_inc_not_zero(&n->refcnt))
611767e97e1SEric Dumazet 			n = NULL;
6121da177e4SLinus Torvalds 		NEIGH_CACHE_STAT_INC(tbl, hits);
6131da177e4SLinus Torvalds 	}
614767e97e1SEric Dumazet 
615d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
6161da177e4SLinus Torvalds 	return n;
6171da177e4SLinus Torvalds }
6180a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_lookup);
6191da177e4SLinus Torvalds 
620426b5303SEric W. Biederman struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
621426b5303SEric W. Biederman 				     const void *pkey)
6221da177e4SLinus Torvalds {
6231da177e4SLinus Torvalds 	struct neighbour *n;
62401ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
625bc4bf5f3SPavel Emelyanov 	u32 hash_val;
626d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
6271da177e4SLinus Torvalds 
6281da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, lookups);
6291da177e4SLinus Torvalds 
630d6bf7817SEric Dumazet 	rcu_read_lock_bh();
631d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
632cd089336SDavid S. Miller 	hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
633767e97e1SEric Dumazet 
634767e97e1SEric Dumazet 	for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
635767e97e1SEric Dumazet 	     n != NULL;
636767e97e1SEric Dumazet 	     n = rcu_dereference_bh(n->next)) {
637426b5303SEric W. Biederman 		if (!memcmp(n->primary_key, pkey, key_len) &&
638878628fbSYOSHIFUJI Hideaki 		    net_eq(dev_net(n->dev), net)) {
6399f237430SReshetova, Elena 			if (!refcount_inc_not_zero(&n->refcnt))
640767e97e1SEric Dumazet 				n = NULL;
6411da177e4SLinus Torvalds 			NEIGH_CACHE_STAT_INC(tbl, hits);
6421da177e4SLinus Torvalds 			break;
6431da177e4SLinus Torvalds 		}
6441da177e4SLinus Torvalds 	}
645767e97e1SEric Dumazet 
646d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
6471da177e4SLinus Torvalds 	return n;
6481da177e4SLinus Torvalds }
6490a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_lookup_nodev);
6501da177e4SLinus Torvalds 
651e4400bbfSDaniel Borkmann static struct neighbour *
652e4400bbfSDaniel Borkmann ___neigh_create(struct neigh_table *tbl, const void *pkey,
6532c611ad9SRoopa Prabhu 		struct net_device *dev, u32 flags,
654e997f8a2SDavid Ahern 		bool exempt_from_gc, bool want_ref)
6551da177e4SLinus Torvalds {
656e4400bbfSDaniel Borkmann 	u32 hash_val, key_len = tbl->key_len;
657e4400bbfSDaniel Borkmann 	struct neighbour *n1, *rc, *n;
658d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
659e4400bbfSDaniel Borkmann 	int error;
6601da177e4SLinus Torvalds 
661e4400bbfSDaniel Borkmann 	n = neigh_alloc(tbl, dev, flags, exempt_from_gc);
662fc651001SDavid Ahern 	trace_neigh_create(tbl, dev, pkey, n, exempt_from_gc);
6631da177e4SLinus Torvalds 	if (!n) {
6641da177e4SLinus Torvalds 		rc = ERR_PTR(-ENOBUFS);
6651da177e4SLinus Torvalds 		goto out;
6661da177e4SLinus Torvalds 	}
6671da177e4SLinus Torvalds 
6681da177e4SLinus Torvalds 	memcpy(n->primary_key, pkey, key_len);
6691da177e4SLinus Torvalds 	n->dev = dev;
670d62607c3SJakub Kicinski 	netdev_hold(dev, &n->dev_tracker, GFP_ATOMIC);
6711da177e4SLinus Torvalds 
6721da177e4SLinus Torvalds 	/* Protocol specific setup. */
6731da177e4SLinus Torvalds 	if (tbl->constructor &&	(error = tbl->constructor(n)) < 0) {
6741da177e4SLinus Torvalds 		rc = ERR_PTR(error);
6751da177e4SLinus Torvalds 		goto out_neigh_release;
6761da177e4SLinus Torvalds 	}
6771da177e4SLinus Torvalds 
678da6a8fa0SDavid Miller 	if (dev->netdev_ops->ndo_neigh_construct) {
679503eebc2SJiri Pirko 		error = dev->netdev_ops->ndo_neigh_construct(dev, n);
680da6a8fa0SDavid Miller 		if (error < 0) {
681da6a8fa0SDavid Miller 			rc = ERR_PTR(error);
682da6a8fa0SDavid Miller 			goto out_neigh_release;
683da6a8fa0SDavid Miller 		}
684da6a8fa0SDavid Miller 	}
685da6a8fa0SDavid Miller 
686447f2191SDavid S. Miller 	/* Device specific setup. */
687447f2191SDavid S. Miller 	if (n->parms->neigh_setup &&
688447f2191SDavid S. Miller 	    (error = n->parms->neigh_setup(n)) < 0) {
689447f2191SDavid S. Miller 		rc = ERR_PTR(error);
690447f2191SDavid S. Miller 		goto out_neigh_release;
691447f2191SDavid S. Miller 	}
692447f2191SDavid S. Miller 
6931f9248e5SJiri Pirko 	n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1);
6941da177e4SLinus Torvalds 
6951da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
696d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
697d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
6981da177e4SLinus Torvalds 
699cd089336SDavid S. Miller 	if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
700cd089336SDavid S. Miller 		nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
7011da177e4SLinus Torvalds 
702096b9854SJim Westfall 	hash_val = tbl->hash(n->primary_key, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
7031da177e4SLinus Torvalds 
7041da177e4SLinus Torvalds 	if (n->parms->dead) {
7051da177e4SLinus Torvalds 		rc = ERR_PTR(-EINVAL);
7061da177e4SLinus Torvalds 		goto out_tbl_unlock;
7071da177e4SLinus Torvalds 	}
7081da177e4SLinus Torvalds 
709767e97e1SEric Dumazet 	for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
710767e97e1SEric Dumazet 					    lockdep_is_held(&tbl->lock));
711767e97e1SEric Dumazet 	     n1 != NULL;
712767e97e1SEric Dumazet 	     n1 = rcu_dereference_protected(n1->next,
713767e97e1SEric Dumazet 			lockdep_is_held(&tbl->lock))) {
714096b9854SJim Westfall 		if (dev == n1->dev && !memcmp(n1->primary_key, n->primary_key, key_len)) {
715a263b309SDavid S. Miller 			if (want_ref)
7161da177e4SLinus Torvalds 				neigh_hold(n1);
7171da177e4SLinus Torvalds 			rc = n1;
7181da177e4SLinus Torvalds 			goto out_tbl_unlock;
7191da177e4SLinus Torvalds 		}
7201da177e4SLinus Torvalds 	}
7211da177e4SLinus Torvalds 
7221da177e4SLinus Torvalds 	n->dead = 0;
723e997f8a2SDavid Ahern 	if (!exempt_from_gc)
7248cc196d6SDavid Ahern 		list_add_tail(&n->gc_list, &n->tbl->gc_list);
7257482e384SDaniel Borkmann 	if (n->flags & NTF_MANAGED)
7267482e384SDaniel Borkmann 		list_add_tail(&n->managed_list, &n->tbl->managed_list);
727a263b309SDavid S. Miller 	if (want_ref)
7281da177e4SLinus Torvalds 		neigh_hold(n);
729767e97e1SEric Dumazet 	rcu_assign_pointer(n->next,
730767e97e1SEric Dumazet 			   rcu_dereference_protected(nht->hash_buckets[hash_val],
731767e97e1SEric Dumazet 						     lockdep_is_held(&tbl->lock)));
732767e97e1SEric Dumazet 	rcu_assign_pointer(nht->hash_buckets[hash_val], n);
7331da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
734d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is created\n", n);
7351da177e4SLinus Torvalds 	rc = n;
7361da177e4SLinus Torvalds out:
7371da177e4SLinus Torvalds 	return rc;
7381da177e4SLinus Torvalds out_tbl_unlock:
7391da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
7401da177e4SLinus Torvalds out_neigh_release:
74164c6f4bbSDavid Ahern 	if (!exempt_from_gc)
74264c6f4bbSDavid Ahern 		atomic_dec(&tbl->gc_entries);
7431da177e4SLinus Torvalds 	neigh_release(n);
7441da177e4SLinus Torvalds 	goto out;
7451da177e4SLinus Torvalds }
74658956317SDavid Ahern 
74758956317SDavid Ahern struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
74858956317SDavid Ahern 				 struct net_device *dev, bool want_ref)
74958956317SDavid Ahern {
750e4400bbfSDaniel Borkmann 	return ___neigh_create(tbl, pkey, dev, 0, false, want_ref);
75158956317SDavid Ahern }
752a263b309SDavid S. Miller EXPORT_SYMBOL(__neigh_create);
7531da177e4SLinus Torvalds 
75401ccdf12SAlexey Dobriyan static u32 pneigh_hash(const void *pkey, unsigned int key_len)
755fa86d322SPavel Emelyanov {
756fa86d322SPavel Emelyanov 	u32 hash_val = *(u32 *)(pkey + key_len - 4);
757fa86d322SPavel Emelyanov 	hash_val ^= (hash_val >> 16);
758fa86d322SPavel Emelyanov 	hash_val ^= hash_val >> 8;
759fa86d322SPavel Emelyanov 	hash_val ^= hash_val >> 4;
760fa86d322SPavel Emelyanov 	hash_val &= PNEIGH_HASHMASK;
761be01d655SYOSHIFUJI Hideaki 	return hash_val;
762fa86d322SPavel Emelyanov }
763fa86d322SPavel Emelyanov 
764be01d655SYOSHIFUJI Hideaki static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
765be01d655SYOSHIFUJI Hideaki 					      struct net *net,
766be01d655SYOSHIFUJI Hideaki 					      const void *pkey,
76701ccdf12SAlexey Dobriyan 					      unsigned int key_len,
768be01d655SYOSHIFUJI Hideaki 					      struct net_device *dev)
769be01d655SYOSHIFUJI Hideaki {
770be01d655SYOSHIFUJI Hideaki 	while (n) {
771be01d655SYOSHIFUJI Hideaki 		if (!memcmp(n->key, pkey, key_len) &&
772be01d655SYOSHIFUJI Hideaki 		    net_eq(pneigh_net(n), net) &&
773be01d655SYOSHIFUJI Hideaki 		    (n->dev == dev || !n->dev))
774fa86d322SPavel Emelyanov 			return n;
775be01d655SYOSHIFUJI Hideaki 		n = n->next;
776be01d655SYOSHIFUJI Hideaki 	}
777be01d655SYOSHIFUJI Hideaki 	return NULL;
778be01d655SYOSHIFUJI Hideaki }
779be01d655SYOSHIFUJI Hideaki 
780be01d655SYOSHIFUJI Hideaki struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
781be01d655SYOSHIFUJI Hideaki 		struct net *net, const void *pkey, struct net_device *dev)
782be01d655SYOSHIFUJI Hideaki {
78301ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
784be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
785be01d655SYOSHIFUJI Hideaki 
786be01d655SYOSHIFUJI Hideaki 	return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
787be01d655SYOSHIFUJI Hideaki 				 net, pkey, key_len, dev);
788fa86d322SPavel Emelyanov }
7890a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL_GPL(__pneigh_lookup);
790fa86d322SPavel Emelyanov 
791426b5303SEric W. Biederman struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
792426b5303SEric W. Biederman 				    struct net *net, const void *pkey,
7931da177e4SLinus Torvalds 				    struct net_device *dev, int creat)
7941da177e4SLinus Torvalds {
7951da177e4SLinus Torvalds 	struct pneigh_entry *n;
79601ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
797be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
7981da177e4SLinus Torvalds 
7991da177e4SLinus Torvalds 	read_lock_bh(&tbl->lock);
800be01d655SYOSHIFUJI Hideaki 	n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
801be01d655SYOSHIFUJI Hideaki 			      net, pkey, key_len, dev);
802be01d655SYOSHIFUJI Hideaki 	read_unlock_bh(&tbl->lock);
8031da177e4SLinus Torvalds 
804be01d655SYOSHIFUJI Hideaki 	if (n || !creat)
8051da177e4SLinus Torvalds 		goto out;
8061da177e4SLinus Torvalds 
8074ae28944SPavel Emelyanov 	ASSERT_RTNL();
8084ae28944SPavel Emelyanov 
809e195e9b5SEric Dumazet 	n = kzalloc(sizeof(*n) + key_len, GFP_KERNEL);
8101da177e4SLinus Torvalds 	if (!n)
8111da177e4SLinus Torvalds 		goto out;
8121da177e4SLinus Torvalds 
813efd7ef1cSEric W. Biederman 	write_pnet(&n->net, net);
8141da177e4SLinus Torvalds 	memcpy(n->key, pkey, key_len);
8151da177e4SLinus Torvalds 	n->dev = dev;
816d62607c3SJakub Kicinski 	netdev_hold(dev, &n->dev_tracker, GFP_KERNEL);
8171da177e4SLinus Torvalds 
8181da177e4SLinus Torvalds 	if (tbl->pconstructor && tbl->pconstructor(n)) {
819d62607c3SJakub Kicinski 		netdev_put(dev, &n->dev_tracker);
8201da177e4SLinus Torvalds 		kfree(n);
8211da177e4SLinus Torvalds 		n = NULL;
8221da177e4SLinus Torvalds 		goto out;
8231da177e4SLinus Torvalds 	}
8241da177e4SLinus Torvalds 
8251da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
8261da177e4SLinus Torvalds 	n->next = tbl->phash_buckets[hash_val];
8271da177e4SLinus Torvalds 	tbl->phash_buckets[hash_val] = n;
8281da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
8291da177e4SLinus Torvalds out:
8301da177e4SLinus Torvalds 	return n;
8311da177e4SLinus Torvalds }
8320a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(pneigh_lookup);
8331da177e4SLinus Torvalds 
8341da177e4SLinus Torvalds 
835426b5303SEric W. Biederman int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
8361da177e4SLinus Torvalds 		  struct net_device *dev)
8371da177e4SLinus Torvalds {
8381da177e4SLinus Torvalds 	struct pneigh_entry *n, **np;
83901ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
840be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
8411da177e4SLinus Torvalds 
8421da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
8431da177e4SLinus Torvalds 	for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
8441da177e4SLinus Torvalds 	     np = &n->next) {
845426b5303SEric W. Biederman 		if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
846878628fbSYOSHIFUJI Hideaki 		    net_eq(pneigh_net(n), net)) {
8471da177e4SLinus Torvalds 			*np = n->next;
8481da177e4SLinus Torvalds 			write_unlock_bh(&tbl->lock);
8491da177e4SLinus Torvalds 			if (tbl->pdestructor)
8501da177e4SLinus Torvalds 				tbl->pdestructor(n);
851d62607c3SJakub Kicinski 			netdev_put(n->dev, &n->dev_tracker);
8521da177e4SLinus Torvalds 			kfree(n);
8531da177e4SLinus Torvalds 			return 0;
8541da177e4SLinus Torvalds 		}
8551da177e4SLinus Torvalds 	}
8561da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
8571da177e4SLinus Torvalds 	return -ENOENT;
8581da177e4SLinus Torvalds }
8591da177e4SLinus Torvalds 
86053b76cdfSWolfgang Bumiller static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
86153b76cdfSWolfgang Bumiller 				    struct net_device *dev)
8621da177e4SLinus Torvalds {
86353b76cdfSWolfgang Bumiller 	struct pneigh_entry *n, **np, *freelist = NULL;
8641da177e4SLinus Torvalds 	u32 h;
8651da177e4SLinus Torvalds 
8661da177e4SLinus Torvalds 	for (h = 0; h <= PNEIGH_HASHMASK; h++) {
8671da177e4SLinus Torvalds 		np = &tbl->phash_buckets[h];
8681da177e4SLinus Torvalds 		while ((n = *np) != NULL) {
8691da177e4SLinus Torvalds 			if (!dev || n->dev == dev) {
8701da177e4SLinus Torvalds 				*np = n->next;
87153b76cdfSWolfgang Bumiller 				n->next = freelist;
87253b76cdfSWolfgang Bumiller 				freelist = n;
87353b76cdfSWolfgang Bumiller 				continue;
87453b76cdfSWolfgang Bumiller 			}
87553b76cdfSWolfgang Bumiller 			np = &n->next;
87653b76cdfSWolfgang Bumiller 		}
87753b76cdfSWolfgang Bumiller 	}
87853b76cdfSWolfgang Bumiller 	write_unlock_bh(&tbl->lock);
87953b76cdfSWolfgang Bumiller 	while ((n = freelist)) {
88053b76cdfSWolfgang Bumiller 		freelist = n->next;
88153b76cdfSWolfgang Bumiller 		n->next = NULL;
8821da177e4SLinus Torvalds 		if (tbl->pdestructor)
8831da177e4SLinus Torvalds 			tbl->pdestructor(n);
884d62607c3SJakub Kicinski 		netdev_put(n->dev, &n->dev_tracker);
8851da177e4SLinus Torvalds 		kfree(n);
8861da177e4SLinus Torvalds 	}
8871da177e4SLinus Torvalds 	return -ENOENT;
8881da177e4SLinus Torvalds }
8891da177e4SLinus Torvalds 
89006f0511dSDenis V. Lunev static void neigh_parms_destroy(struct neigh_parms *parms);
89106f0511dSDenis V. Lunev 
89206f0511dSDenis V. Lunev static inline void neigh_parms_put(struct neigh_parms *parms)
89306f0511dSDenis V. Lunev {
8946343944bSReshetova, Elena 	if (refcount_dec_and_test(&parms->refcnt))
89506f0511dSDenis V. Lunev 		neigh_parms_destroy(parms);
89606f0511dSDenis V. Lunev }
8971da177e4SLinus Torvalds 
8981da177e4SLinus Torvalds /*
8991da177e4SLinus Torvalds  *	neighbour must already be out of the table;
9001da177e4SLinus Torvalds  *
9011da177e4SLinus Torvalds  */
9021da177e4SLinus Torvalds void neigh_destroy(struct neighbour *neigh)
9031da177e4SLinus Torvalds {
904da6a8fa0SDavid Miller 	struct net_device *dev = neigh->dev;
905da6a8fa0SDavid Miller 
9061da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
9071da177e4SLinus Torvalds 
9081da177e4SLinus Torvalds 	if (!neigh->dead) {
909e005d193SJoe Perches 		pr_warn("Destroying alive neighbour %p\n", neigh);
9101da177e4SLinus Torvalds 		dump_stack();
9111da177e4SLinus Torvalds 		return;
9121da177e4SLinus Torvalds 	}
9131da177e4SLinus Torvalds 
9141da177e4SLinus Torvalds 	if (neigh_del_timer(neigh))
915e005d193SJoe Perches 		pr_warn("Impossible event\n");
9161da177e4SLinus Torvalds 
917c9ab4d85SEric Dumazet 	write_lock_bh(&neigh->lock);
918c9ab4d85SEric Dumazet 	__skb_queue_purge(&neigh->arp_queue);
919c9ab4d85SEric Dumazet 	write_unlock_bh(&neigh->lock);
9208b5c171bSEric Dumazet 	neigh->arp_queue_len_bytes = 0;
9211da177e4SLinus Torvalds 
922447f2191SDavid S. Miller 	if (dev->netdev_ops->ndo_neigh_destroy)
923503eebc2SJiri Pirko 		dev->netdev_ops->ndo_neigh_destroy(dev, neigh);
924447f2191SDavid S. Miller 
925d62607c3SJakub Kicinski 	netdev_put(dev, &neigh->dev_tracker);
9261da177e4SLinus Torvalds 	neigh_parms_put(neigh->parms);
9271da177e4SLinus Torvalds 
928d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is destroyed\n", neigh);
9291da177e4SLinus Torvalds 
9301da177e4SLinus Torvalds 	atomic_dec(&neigh->tbl->entries);
9315b8b0060SDavid Miller 	kfree_rcu(neigh, rcu);
9321da177e4SLinus Torvalds }
9330a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_destroy);
9341da177e4SLinus Torvalds 
9351da177e4SLinus Torvalds /* Neighbour state is suspicious;
9361da177e4SLinus Torvalds    disable fast path.
9371da177e4SLinus Torvalds 
9381da177e4SLinus Torvalds    Called with write_locked neigh.
9391da177e4SLinus Torvalds  */
9401da177e4SLinus Torvalds static void neigh_suspect(struct neighbour *neigh)
9411da177e4SLinus Torvalds {
942d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is suspected\n", neigh);
9431da177e4SLinus Torvalds 
9441da177e4SLinus Torvalds 	neigh->output = neigh->ops->output;
9451da177e4SLinus Torvalds }
9461da177e4SLinus Torvalds 
9471da177e4SLinus Torvalds /* Neighbour state is OK;
9481da177e4SLinus Torvalds    enable fast path.
9491da177e4SLinus Torvalds 
9501da177e4SLinus Torvalds    Called with write_locked neigh.
9511da177e4SLinus Torvalds  */
9521da177e4SLinus Torvalds static void neigh_connect(struct neighbour *neigh)
9531da177e4SLinus Torvalds {
954d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is connected\n", neigh);
9551da177e4SLinus Torvalds 
9561da177e4SLinus Torvalds 	neigh->output = neigh->ops->connected_output;
9571da177e4SLinus Torvalds }
9581da177e4SLinus Torvalds 
959e4c4e448SEric Dumazet static void neigh_periodic_work(struct work_struct *work)
9601da177e4SLinus Torvalds {
961e4c4e448SEric Dumazet 	struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
962767e97e1SEric Dumazet 	struct neighbour *n;
963767e97e1SEric Dumazet 	struct neighbour __rcu **np;
964e4c4e448SEric Dumazet 	unsigned int i;
965d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
9661da177e4SLinus Torvalds 
9671da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
9681da177e4SLinus Torvalds 
969e4c4e448SEric Dumazet 	write_lock_bh(&tbl->lock);
970d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
971d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
9721da177e4SLinus Torvalds 
9731da177e4SLinus Torvalds 	/*
9741da177e4SLinus Torvalds 	 *	periodically recompute ReachableTime from random function
9751da177e4SLinus Torvalds 	 */
9761da177e4SLinus Torvalds 
977e4c4e448SEric Dumazet 	if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
9781da177e4SLinus Torvalds 		struct neigh_parms *p;
979e4c4e448SEric Dumazet 		tbl->last_rand = jiffies;
98075fbfd33SNicolas Dichtel 		list_for_each_entry(p, &tbl->parms_list, list)
9811da177e4SLinus Torvalds 			p->reachable_time =
9821f9248e5SJiri Pirko 				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
9831da177e4SLinus Torvalds 	}
9841da177e4SLinus Torvalds 
985feff9ab2SDuan Jiong 	if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
986feff9ab2SDuan Jiong 		goto out;
987feff9ab2SDuan Jiong 
988cd089336SDavid S. Miller 	for (i = 0 ; i < (1 << nht->hash_shift); i++) {
989d6bf7817SEric Dumazet 		np = &nht->hash_buckets[i];
9901da177e4SLinus Torvalds 
991767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
992767e97e1SEric Dumazet 				lockdep_is_held(&tbl->lock))) != NULL) {
9931da177e4SLinus Torvalds 			unsigned int state;
9941da177e4SLinus Torvalds 
9951da177e4SLinus Torvalds 			write_lock(&n->lock);
9961da177e4SLinus Torvalds 
9971da177e4SLinus Torvalds 			state = n->nud_state;
9989ce33e46SRoopa Prabhu 			if ((state & (NUD_PERMANENT | NUD_IN_TIMER)) ||
9999ce33e46SRoopa Prabhu 			    (n->flags & NTF_EXT_LEARNED)) {
10001da177e4SLinus Torvalds 				write_unlock(&n->lock);
10011da177e4SLinus Torvalds 				goto next_elt;
10021da177e4SLinus Torvalds 			}
10031da177e4SLinus Torvalds 
10041da177e4SLinus Torvalds 			if (time_before(n->used, n->confirmed))
10051da177e4SLinus Torvalds 				n->used = n->confirmed;
10061da177e4SLinus Torvalds 
10079f237430SReshetova, Elena 			if (refcount_read(&n->refcnt) == 1 &&
10081da177e4SLinus Torvalds 			    (state == NUD_FAILED ||
10091f9248e5SJiri Pirko 			     time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
10101da177e4SLinus Torvalds 				*np = n->next;
101158956317SDavid Ahern 				neigh_mark_dead(n);
10121da177e4SLinus Torvalds 				write_unlock(&n->lock);
10134f494554SThomas Graf 				neigh_cleanup_and_release(n);
10141da177e4SLinus Torvalds 				continue;
10151da177e4SLinus Torvalds 			}
10161da177e4SLinus Torvalds 			write_unlock(&n->lock);
10171da177e4SLinus Torvalds 
10181da177e4SLinus Torvalds next_elt:
10191da177e4SLinus Torvalds 			np = &n->next;
10201da177e4SLinus Torvalds 		}
1021e4c4e448SEric Dumazet 		/*
1022e4c4e448SEric Dumazet 		 * It's fine to release lock here, even if hash table
1023e4c4e448SEric Dumazet 		 * grows while we are preempted.
1024e4c4e448SEric Dumazet 		 */
1025e4c4e448SEric Dumazet 		write_unlock_bh(&tbl->lock);
1026e4c4e448SEric Dumazet 		cond_resched();
1027e4c4e448SEric Dumazet 		write_lock_bh(&tbl->lock);
102884338a6cSMichel Machado 		nht = rcu_dereference_protected(tbl->nht,
102984338a6cSMichel Machado 						lockdep_is_held(&tbl->lock));
1030e4c4e448SEric Dumazet 	}
10312724680bSYOSHIFUJI Hideaki / 吉藤英明 out:
10321f9248e5SJiri Pirko 	/* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks.
10331f9248e5SJiri Pirko 	 * ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2
10341f9248e5SJiri Pirko 	 * BASE_REACHABLE_TIME.
10351da177e4SLinus Torvalds 	 */
1036f618002bSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
10371f9248e5SJiri Pirko 			      NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1);
1038e4c4e448SEric Dumazet 	write_unlock_bh(&tbl->lock);
10391da177e4SLinus Torvalds }
10401da177e4SLinus Torvalds 
10411da177e4SLinus Torvalds static __inline__ int neigh_max_probes(struct neighbour *n)
10421da177e4SLinus Torvalds {
10431da177e4SLinus Torvalds 	struct neigh_parms *p = n->parms;
10448da86466SYOSHIFUJI Hideaki/吉藤英明 	return NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) +
10458da86466SYOSHIFUJI Hideaki/吉藤英明 	       (n->nud_state & NUD_PROBE ? NEIGH_VAR(p, MCAST_REPROBES) :
10468da86466SYOSHIFUJI Hideaki/吉藤英明 	        NEIGH_VAR(p, MCAST_PROBES));
10471da177e4SLinus Torvalds }
10481da177e4SLinus Torvalds 
10495ef12d98STimo Teras static void neigh_invalidate(struct neighbour *neigh)
10500a141509SEric Dumazet 	__releases(neigh->lock)
10510a141509SEric Dumazet 	__acquires(neigh->lock)
10525ef12d98STimo Teras {
10535ef12d98STimo Teras 	struct sk_buff *skb;
10545ef12d98STimo Teras 
10555ef12d98STimo Teras 	NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
1056d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is failed\n", neigh);
10575ef12d98STimo Teras 	neigh->updated = jiffies;
10585ef12d98STimo Teras 
10595ef12d98STimo Teras 	/* It is very thin place. report_unreachable is very complicated
10605ef12d98STimo Teras 	   routine. Particularly, it can hit the same neighbour entry!
10615ef12d98STimo Teras 
10625ef12d98STimo Teras 	   So that, we try to be accurate and avoid dead loop. --ANK
10635ef12d98STimo Teras 	 */
10645ef12d98STimo Teras 	while (neigh->nud_state == NUD_FAILED &&
10655ef12d98STimo Teras 	       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
10665ef12d98STimo Teras 		write_unlock(&neigh->lock);
10675ef12d98STimo Teras 		neigh->ops->error_report(neigh, skb);
10685ef12d98STimo Teras 		write_lock(&neigh->lock);
10695ef12d98STimo Teras 	}
1070c9ab4d85SEric Dumazet 	__skb_queue_purge(&neigh->arp_queue);
10718b5c171bSEric Dumazet 	neigh->arp_queue_len_bytes = 0;
10725ef12d98STimo Teras }
10735ef12d98STimo Teras 
1074cd28ca0aSEric Dumazet static void neigh_probe(struct neighbour *neigh)
1075cd28ca0aSEric Dumazet 	__releases(neigh->lock)
1076cd28ca0aSEric Dumazet {
10774ed377e3SHannes Frederic Sowa 	struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);
1078cd28ca0aSEric Dumazet 	/* keep skb alive even if arp_queue overflows */
1079cd28ca0aSEric Dumazet 	if (skb)
108019125c1aSMartin Zhang 		skb = skb_clone(skb, GFP_ATOMIC);
1081cd28ca0aSEric Dumazet 	write_unlock(&neigh->lock);
108248481c8fSEric Dumazet 	if (neigh->ops->solicit)
1083cd28ca0aSEric Dumazet 		neigh->ops->solicit(neigh, skb);
1084cd28ca0aSEric Dumazet 	atomic_inc(&neigh->probes);
108587fff3caSYang Wei 	consume_skb(skb);
1086cd28ca0aSEric Dumazet }
1087cd28ca0aSEric Dumazet 
10881da177e4SLinus Torvalds /* Called when a timer expires for a neighbour entry. */
10891da177e4SLinus Torvalds 
1090e99e88a9SKees Cook static void neigh_timer_handler(struct timer_list *t)
10911da177e4SLinus Torvalds {
10921da177e4SLinus Torvalds 	unsigned long now, next;
1093e99e88a9SKees Cook 	struct neighbour *neigh = from_timer(neigh, t, timer);
109495c96174SEric Dumazet 	unsigned int state;
10951da177e4SLinus Torvalds 	int notify = 0;
10961da177e4SLinus Torvalds 
10971da177e4SLinus Torvalds 	write_lock(&neigh->lock);
10981da177e4SLinus Torvalds 
10991da177e4SLinus Torvalds 	state = neigh->nud_state;
11001da177e4SLinus Torvalds 	now = jiffies;
11011da177e4SLinus Torvalds 	next = now + HZ;
11021da177e4SLinus Torvalds 
1103045f7b3bSDavid S. Miller 	if (!(state & NUD_IN_TIMER))
11041da177e4SLinus Torvalds 		goto out;
11051da177e4SLinus Torvalds 
11061da177e4SLinus Torvalds 	if (state & NUD_REACHABLE) {
11071da177e4SLinus Torvalds 		if (time_before_eq(now,
11081da177e4SLinus Torvalds 				   neigh->confirmed + neigh->parms->reachable_time)) {
1109d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is still alive\n", neigh);
11101da177e4SLinus Torvalds 			next = neigh->confirmed + neigh->parms->reachable_time;
11111da177e4SLinus Torvalds 		} else if (time_before_eq(now,
11121f9248e5SJiri Pirko 					  neigh->used +
11131f9248e5SJiri Pirko 					  NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
1114d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is delayed\n", neigh);
11151da177e4SLinus Torvalds 			neigh->nud_state = NUD_DELAY;
1116955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
11171da177e4SLinus Torvalds 			neigh_suspect(neigh);
11181f9248e5SJiri Pirko 			next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME);
11191da177e4SLinus Torvalds 		} else {
1120d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is suspected\n", neigh);
11211da177e4SLinus Torvalds 			neigh->nud_state = NUD_STALE;
1122955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
11231da177e4SLinus Torvalds 			neigh_suspect(neigh);
11248d71740cSTom Tucker 			notify = 1;
11251da177e4SLinus Torvalds 		}
11261da177e4SLinus Torvalds 	} else if (state & NUD_DELAY) {
11271da177e4SLinus Torvalds 		if (time_before_eq(now,
11281f9248e5SJiri Pirko 				   neigh->confirmed +
11291f9248e5SJiri Pirko 				   NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
1130d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is now reachable\n", neigh);
11311da177e4SLinus Torvalds 			neigh->nud_state = NUD_REACHABLE;
1132955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
11331da177e4SLinus Torvalds 			neigh_connect(neigh);
11348d71740cSTom Tucker 			notify = 1;
11351da177e4SLinus Torvalds 			next = neigh->confirmed + neigh->parms->reachable_time;
11361da177e4SLinus Torvalds 		} else {
1137d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is probed\n", neigh);
11381da177e4SLinus Torvalds 			neigh->nud_state = NUD_PROBE;
1139955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
11401da177e4SLinus Torvalds 			atomic_set(&neigh->probes, 0);
1141765c9c63SErik Kline 			notify = 1;
114219e16d22SHangbin Liu 			next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
114319e16d22SHangbin Liu 					 HZ/100);
11441da177e4SLinus Torvalds 		}
11451da177e4SLinus Torvalds 	} else {
11461da177e4SLinus Torvalds 		/* NUD_PROBE|NUD_INCOMPLETE */
114719e16d22SHangbin Liu 		next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME), HZ/100);
11481da177e4SLinus Torvalds 	}
11491da177e4SLinus Torvalds 
11501da177e4SLinus Torvalds 	if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
11511da177e4SLinus Torvalds 	    atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
11521da177e4SLinus Torvalds 		neigh->nud_state = NUD_FAILED;
11531da177e4SLinus Torvalds 		notify = 1;
11545ef12d98STimo Teras 		neigh_invalidate(neigh);
11555e2c21dcSDuan Jiong 		goto out;
11561da177e4SLinus Torvalds 	}
11571da177e4SLinus Torvalds 
11581da177e4SLinus Torvalds 	if (neigh->nud_state & NUD_IN_TIMER) {
115996d10d5bSHangbin Liu 		if (time_before(next, jiffies + HZ/100))
116096d10d5bSHangbin Liu 			next = jiffies + HZ/100;
11616fb9974fSHerbert Xu 		if (!mod_timer(&neigh->timer, next))
11626fb9974fSHerbert Xu 			neigh_hold(neigh);
11631da177e4SLinus Torvalds 	}
11641da177e4SLinus Torvalds 	if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
1165cd28ca0aSEric Dumazet 		neigh_probe(neigh);
11669ff56607SDavid S. Miller 	} else {
11671da177e4SLinus Torvalds out:
11681da177e4SLinus Torvalds 		write_unlock(&neigh->lock);
11699ff56607SDavid S. Miller 	}
11701da177e4SLinus Torvalds 
1171d961db35SThomas Graf 	if (notify)
11727b8f7a40SRoopa Prabhu 		neigh_update_notify(neigh, 0);
1173d961db35SThomas Graf 
117456dd18a4SRoopa Prabhu 	trace_neigh_timer_handler(neigh, 0);
117556dd18a4SRoopa Prabhu 
11761da177e4SLinus Torvalds 	neigh_release(neigh);
11771da177e4SLinus Torvalds }
11781da177e4SLinus Torvalds 
11794a81f6daSDaniel Borkmann int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb,
11804a81f6daSDaniel Borkmann 		       const bool immediate_ok)
11811da177e4SLinus Torvalds {
11821da177e4SLinus Torvalds 	int rc;
1183cd28ca0aSEric Dumazet 	bool immediate_probe = false;
11841da177e4SLinus Torvalds 
11851da177e4SLinus Torvalds 	write_lock_bh(&neigh->lock);
11861da177e4SLinus Torvalds 
11871da177e4SLinus Torvalds 	rc = 0;
11881da177e4SLinus Torvalds 	if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
11891da177e4SLinus Torvalds 		goto out_unlock_bh;
11902c51a97fSJulian Anastasov 	if (neigh->dead)
11912c51a97fSJulian Anastasov 		goto out_dead;
11921da177e4SLinus Torvalds 
11931da177e4SLinus Torvalds 	if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
11941f9248e5SJiri Pirko 		if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
11951f9248e5SJiri Pirko 		    NEIGH_VAR(neigh->parms, APP_PROBES)) {
1196cd28ca0aSEric Dumazet 			unsigned long next, now = jiffies;
1197cd28ca0aSEric Dumazet 
11981f9248e5SJiri Pirko 			atomic_set(&neigh->probes,
11991f9248e5SJiri Pirko 				   NEIGH_VAR(neigh->parms, UCAST_PROBES));
1200071c3798SLorenzo Bianconi 			neigh_del_timer(neigh);
12011da177e4SLinus Torvalds 			neigh->nud_state = NUD_INCOMPLETE;
1202cd28ca0aSEric Dumazet 			neigh->updated = now;
12034a81f6daSDaniel Borkmann 			if (!immediate_ok) {
12044a81f6daSDaniel Borkmann 				next = now + 1;
12054a81f6daSDaniel Borkmann 			} else {
1206cd28ca0aSEric Dumazet 				immediate_probe = true;
12074a81f6daSDaniel Borkmann 				next = now + max(NEIGH_VAR(neigh->parms,
12084a81f6daSDaniel Borkmann 							   RETRANS_TIME),
12094a81f6daSDaniel Borkmann 						 HZ / 100);
12104a81f6daSDaniel Borkmann 			}
12114a81f6daSDaniel Borkmann 			neigh_add_timer(neigh, next);
12121da177e4SLinus Torvalds 		} else {
12131da177e4SLinus Torvalds 			neigh->nud_state = NUD_FAILED;
1214955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
12151da177e4SLinus Torvalds 			write_unlock_bh(&neigh->lock);
12161da177e4SLinus Torvalds 
1217a5736eddSMenglong Dong 			kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_FAILED);
12181da177e4SLinus Torvalds 			return 1;
12191da177e4SLinus Torvalds 		}
12201da177e4SLinus Torvalds 	} else if (neigh->nud_state & NUD_STALE) {
1221d5d427cdSJoe Perches 		neigh_dbg(2, "neigh %p is delayed\n", neigh);
1222071c3798SLorenzo Bianconi 		neigh_del_timer(neigh);
12231da177e4SLinus Torvalds 		neigh->nud_state = NUD_DELAY;
1224955aaa2fSYOSHIFUJI Hideaki 		neigh->updated = jiffies;
12251f9248e5SJiri Pirko 		neigh_add_timer(neigh, jiffies +
12261f9248e5SJiri Pirko 				NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME));
12271da177e4SLinus Torvalds 	}
12281da177e4SLinus Torvalds 
12291da177e4SLinus Torvalds 	if (neigh->nud_state == NUD_INCOMPLETE) {
12301da177e4SLinus Torvalds 		if (skb) {
12318b5c171bSEric Dumazet 			while (neigh->arp_queue_len_bytes + skb->truesize >
12321f9248e5SJiri Pirko 			       NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) {
12331da177e4SLinus Torvalds 				struct sk_buff *buff;
12348b5c171bSEric Dumazet 
1235f72051b0SDavid S. Miller 				buff = __skb_dequeue(&neigh->arp_queue);
12368b5c171bSEric Dumazet 				if (!buff)
12378b5c171bSEric Dumazet 					break;
12388b5c171bSEric Dumazet 				neigh->arp_queue_len_bytes -= buff->truesize;
1239a5736eddSMenglong Dong 				kfree_skb_reason(buff, SKB_DROP_REASON_NEIGH_QUEUEFULL);
12409a6d276eSNeil Horman 				NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
12411da177e4SLinus Torvalds 			}
1242a4731138SEric Dumazet 			skb_dst_force(skb);
12431da177e4SLinus Torvalds 			__skb_queue_tail(&neigh->arp_queue, skb);
12448b5c171bSEric Dumazet 			neigh->arp_queue_len_bytes += skb->truesize;
12451da177e4SLinus Torvalds 		}
12461da177e4SLinus Torvalds 		rc = 1;
12471da177e4SLinus Torvalds 	}
12481da177e4SLinus Torvalds out_unlock_bh:
1249cd28ca0aSEric Dumazet 	if (immediate_probe)
1250cd28ca0aSEric Dumazet 		neigh_probe(neigh);
1251cd28ca0aSEric Dumazet 	else
1252cd28ca0aSEric Dumazet 		write_unlock(&neigh->lock);
1253cd28ca0aSEric Dumazet 	local_bh_enable();
125456dd18a4SRoopa Prabhu 	trace_neigh_event_send_done(neigh, rc);
12551da177e4SLinus Torvalds 	return rc;
12562c51a97fSJulian Anastasov 
12572c51a97fSJulian Anastasov out_dead:
12582c51a97fSJulian Anastasov 	if (neigh->nud_state & NUD_STALE)
12592c51a97fSJulian Anastasov 		goto out_unlock_bh;
12602c51a97fSJulian Anastasov 	write_unlock_bh(&neigh->lock);
1261a5736eddSMenglong Dong 	kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_DEAD);
126256dd18a4SRoopa Prabhu 	trace_neigh_event_send_dead(neigh, 1);
12632c51a97fSJulian Anastasov 	return 1;
12641da177e4SLinus Torvalds }
12650a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(__neigh_event_send);
12661da177e4SLinus Torvalds 
1267f6b72b62SDavid S. Miller static void neigh_update_hhs(struct neighbour *neigh)
12681da177e4SLinus Torvalds {
12691da177e4SLinus Torvalds 	struct hh_cache *hh;
12703b04dddeSStephen Hemminger 	void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
127191a72a70SDoug Kehn 		= NULL;
127291a72a70SDoug Kehn 
127391a72a70SDoug Kehn 	if (neigh->dev->header_ops)
127491a72a70SDoug Kehn 		update = neigh->dev->header_ops->cache_update;
12751da177e4SLinus Torvalds 
12761da177e4SLinus Torvalds 	if (update) {
1277f6b72b62SDavid S. Miller 		hh = &neigh->hh;
1278c305c6aeSEric Dumazet 		if (READ_ONCE(hh->hh_len)) {
12793644f0ceSStephen Hemminger 			write_seqlock_bh(&hh->hh_lock);
12801da177e4SLinus Torvalds 			update(hh, neigh->dev, neigh->ha);
12813644f0ceSStephen Hemminger 			write_sequnlock_bh(&hh->hh_lock);
12821da177e4SLinus Torvalds 		}
12831da177e4SLinus Torvalds 	}
12841da177e4SLinus Torvalds }
12851da177e4SLinus Torvalds 
12861da177e4SLinus Torvalds /* Generic update routine.
12871da177e4SLinus Torvalds    -- lladdr is new lladdr or NULL, if it is not supplied.
12881da177e4SLinus Torvalds    -- new    is new state.
12891da177e4SLinus Torvalds    -- flags
12901da177e4SLinus Torvalds 	NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
12911da177e4SLinus Torvalds 				if it is different.
12921da177e4SLinus Torvalds 	NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
12931da177e4SLinus Torvalds 				lladdr instead of overriding it
12941da177e4SLinus Torvalds 				if it is different.
12951da177e4SLinus Torvalds 	NEIGH_UPDATE_F_ADMIN	means that the change is administrative.
12963dc20f47SDaniel Borkmann 	NEIGH_UPDATE_F_USE	means that the entry is user triggered.
12977482e384SDaniel Borkmann 	NEIGH_UPDATE_F_MANAGED	means that the entry will be auto-refreshed.
12981da177e4SLinus Torvalds 	NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
12991da177e4SLinus Torvalds 				NTF_ROUTER flag.
13001da177e4SLinus Torvalds 	NEIGH_UPDATE_F_ISROUTER	indicates if the neighbour is known as
13011da177e4SLinus Torvalds 				a router.
13021da177e4SLinus Torvalds 
13031da177e4SLinus Torvalds    Caller MUST hold reference count on the entry.
13041da177e4SLinus Torvalds  */
13057a35a50dSDavid Ahern static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
13067a35a50dSDavid Ahern 			  u8 new, u32 flags, u32 nlmsg_pid,
13077a35a50dSDavid Ahern 			  struct netlink_ext_ack *extack)
13081da177e4SLinus Torvalds {
13097482e384SDaniel Borkmann 	bool gc_update = false, managed_update = false;
13101da177e4SLinus Torvalds 	int update_isrouter = 0;
13117482e384SDaniel Borkmann 	struct net_device *dev;
13127482e384SDaniel Borkmann 	int err, notify = 0;
13137482e384SDaniel Borkmann 	u8 old;
13141da177e4SLinus Torvalds 
131556dd18a4SRoopa Prabhu 	trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid);
131656dd18a4SRoopa Prabhu 
13171da177e4SLinus Torvalds 	write_lock_bh(&neigh->lock);
13181da177e4SLinus Torvalds 
13191da177e4SLinus Torvalds 	dev    = neigh->dev;
13201da177e4SLinus Torvalds 	old    = neigh->nud_state;
13211da177e4SLinus Torvalds 	err    = -EPERM;
13221da177e4SLinus Torvalds 
1323eb4e8facSChinmay Agarwal 	if (neigh->dead) {
1324eb4e8facSChinmay Agarwal 		NL_SET_ERR_MSG(extack, "Neighbor entry is now dead");
1325eb4e8facSChinmay Agarwal 		new = old;
1326eb4e8facSChinmay Agarwal 		goto out;
1327eb4e8facSChinmay Agarwal 	}
13281da177e4SLinus Torvalds 	if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
13291da177e4SLinus Torvalds 	    (old & (NUD_NOARP | NUD_PERMANENT)))
13301da177e4SLinus Torvalds 		goto out;
13311da177e4SLinus Torvalds 
13327482e384SDaniel Borkmann 	neigh_update_flags(neigh, flags, &notify, &gc_update, &managed_update);
13337482e384SDaniel Borkmann 	if (flags & (NEIGH_UPDATE_F_USE | NEIGH_UPDATE_F_MANAGED)) {
13343dc20f47SDaniel Borkmann 		new = old & ~NUD_PERMANENT;
13353dc20f47SDaniel Borkmann 		neigh->nud_state = new;
13363dc20f47SDaniel Borkmann 		err = 0;
13373dc20f47SDaniel Borkmann 		goto out;
13383dc20f47SDaniel Borkmann 	}
13399ce33e46SRoopa Prabhu 
13401da177e4SLinus Torvalds 	if (!(new & NUD_VALID)) {
13411da177e4SLinus Torvalds 		neigh_del_timer(neigh);
13421da177e4SLinus Torvalds 		if (old & NUD_CONNECTED)
13431da177e4SLinus Torvalds 			neigh_suspect(neigh);
13449c29a2f5SDavid Ahern 		neigh->nud_state = new;
13451da177e4SLinus Torvalds 		err = 0;
13461da177e4SLinus Torvalds 		notify = old & NUD_VALID;
1347d2fb4fb8SRoopa Prabhu 		if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
13485ef12d98STimo Teras 		    (new & NUD_FAILED)) {
13495ef12d98STimo Teras 			neigh_invalidate(neigh);
13505ef12d98STimo Teras 			notify = 1;
13515ef12d98STimo Teras 		}
13521da177e4SLinus Torvalds 		goto out;
13531da177e4SLinus Torvalds 	}
13541da177e4SLinus Torvalds 
13551da177e4SLinus Torvalds 	/* Compare new lladdr with cached one */
13561da177e4SLinus Torvalds 	if (!dev->addr_len) {
13571da177e4SLinus Torvalds 		/* First case: device needs no address. */
13581da177e4SLinus Torvalds 		lladdr = neigh->ha;
13591da177e4SLinus Torvalds 	} else if (lladdr) {
13601da177e4SLinus Torvalds 		/* The second case: if something is already cached
13611da177e4SLinus Torvalds 		   and a new address is proposed:
13621da177e4SLinus Torvalds 		   - compare new & old
13631da177e4SLinus Torvalds 		   - if they are different, check override flag
13641da177e4SLinus Torvalds 		 */
13651da177e4SLinus Torvalds 		if ((old & NUD_VALID) &&
13661da177e4SLinus Torvalds 		    !memcmp(lladdr, neigh->ha, dev->addr_len))
13671da177e4SLinus Torvalds 			lladdr = neigh->ha;
13681da177e4SLinus Torvalds 	} else {
13691da177e4SLinus Torvalds 		/* No address is supplied; if we know something,
13701da177e4SLinus Torvalds 		   use it, otherwise discard the request.
13711da177e4SLinus Torvalds 		 */
13721da177e4SLinus Torvalds 		err = -EINVAL;
13737a35a50dSDavid Ahern 		if (!(old & NUD_VALID)) {
13747a35a50dSDavid Ahern 			NL_SET_ERR_MSG(extack, "No link layer address given");
13751da177e4SLinus Torvalds 			goto out;
13767a35a50dSDavid Ahern 		}
13771da177e4SLinus Torvalds 		lladdr = neigh->ha;
13781da177e4SLinus Torvalds 	}
13791da177e4SLinus Torvalds 
1380f0e0d044SVasily Khoruzhick 	/* Update confirmed timestamp for neighbour entry after we
1381f0e0d044SVasily Khoruzhick 	 * received ARP packet even if it doesn't change IP to MAC binding.
1382f0e0d044SVasily Khoruzhick 	 */
1383f0e0d044SVasily Khoruzhick 	if (new & NUD_CONNECTED)
1384f0e0d044SVasily Khoruzhick 		neigh->confirmed = jiffies;
1385f0e0d044SVasily Khoruzhick 
13861da177e4SLinus Torvalds 	/* If entry was valid and address is not changed,
13871da177e4SLinus Torvalds 	   do not change entry state, if new one is STALE.
13881da177e4SLinus Torvalds 	 */
13891da177e4SLinus Torvalds 	err = 0;
13901da177e4SLinus Torvalds 	update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
13911da177e4SLinus Torvalds 	if (old & NUD_VALID) {
13921da177e4SLinus Torvalds 		if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
13931da177e4SLinus Torvalds 			update_isrouter = 0;
13941da177e4SLinus Torvalds 			if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
13951da177e4SLinus Torvalds 			    (old & NUD_CONNECTED)) {
13961da177e4SLinus Torvalds 				lladdr = neigh->ha;
13971da177e4SLinus Torvalds 				new = NUD_STALE;
13981da177e4SLinus Torvalds 			} else
13991da177e4SLinus Torvalds 				goto out;
14001da177e4SLinus Torvalds 		} else {
14010e7bbcc1SJulian Anastasov 			if (lladdr == neigh->ha && new == NUD_STALE &&
14020e7bbcc1SJulian Anastasov 			    !(flags & NEIGH_UPDATE_F_ADMIN))
14031da177e4SLinus Torvalds 				new = old;
14041da177e4SLinus Torvalds 		}
14051da177e4SLinus Torvalds 	}
14061da177e4SLinus Torvalds 
1407f0e0d044SVasily Khoruzhick 	/* Update timestamp only once we know we will make a change to the
140877d71233SIhar Hrachyshka 	 * neighbour entry. Otherwise we risk to move the locktime window with
140977d71233SIhar Hrachyshka 	 * noop updates and ignore relevant ARP updates.
141077d71233SIhar Hrachyshka 	 */
1411f0e0d044SVasily Khoruzhick 	if (new != old || lladdr != neigh->ha)
141277d71233SIhar Hrachyshka 		neigh->updated = jiffies;
141377d71233SIhar Hrachyshka 
14141da177e4SLinus Torvalds 	if (new != old) {
14151da177e4SLinus Torvalds 		neigh_del_timer(neigh);
1416765c9c63SErik Kline 		if (new & NUD_PROBE)
1417765c9c63SErik Kline 			atomic_set(&neigh->probes, 0);
1418a43d8994SPavel Emelyanov 		if (new & NUD_IN_TIMER)
1419667347f1SDavid S. Miller 			neigh_add_timer(neigh, (jiffies +
14201da177e4SLinus Torvalds 						((new & NUD_REACHABLE) ?
1421667347f1SDavid S. Miller 						 neigh->parms->reachable_time :
1422667347f1SDavid S. Miller 						 0)));
14239c29a2f5SDavid Ahern 		neigh->nud_state = new;
142453385d2dSBob Gilligan 		notify = 1;
14251da177e4SLinus Torvalds 	}
14261da177e4SLinus Torvalds 
14271da177e4SLinus Torvalds 	if (lladdr != neigh->ha) {
14280ed8ddf4SEric Dumazet 		write_seqlock(&neigh->ha_lock);
14291da177e4SLinus Torvalds 		memcpy(&neigh->ha, lladdr, dev->addr_len);
14300ed8ddf4SEric Dumazet 		write_sequnlock(&neigh->ha_lock);
14311da177e4SLinus Torvalds 		neigh_update_hhs(neigh);
14321da177e4SLinus Torvalds 		if (!(new & NUD_CONNECTED))
14331da177e4SLinus Torvalds 			neigh->confirmed = jiffies -
14341f9248e5SJiri Pirko 				      (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1);
14351da177e4SLinus Torvalds 		notify = 1;
14361da177e4SLinus Torvalds 	}
14371da177e4SLinus Torvalds 	if (new == old)
14381da177e4SLinus Torvalds 		goto out;
14391da177e4SLinus Torvalds 	if (new & NUD_CONNECTED)
14401da177e4SLinus Torvalds 		neigh_connect(neigh);
14411da177e4SLinus Torvalds 	else
14421da177e4SLinus Torvalds 		neigh_suspect(neigh);
14431da177e4SLinus Torvalds 	if (!(old & NUD_VALID)) {
14441da177e4SLinus Torvalds 		struct sk_buff *skb;
14451da177e4SLinus Torvalds 
14461da177e4SLinus Torvalds 		/* Again: avoid dead loop if something went wrong */
14471da177e4SLinus Torvalds 
14481da177e4SLinus Torvalds 		while (neigh->nud_state & NUD_VALID &&
14491da177e4SLinus Torvalds 		       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
145069cce1d1SDavid S. Miller 			struct dst_entry *dst = skb_dst(skb);
145169cce1d1SDavid S. Miller 			struct neighbour *n2, *n1 = neigh;
14521da177e4SLinus Torvalds 			write_unlock_bh(&neigh->lock);
1453e049f288Sroy.qing.li@gmail.com 
1454e049f288Sroy.qing.li@gmail.com 			rcu_read_lock();
145513a43d94SDavid S. Miller 
145613a43d94SDavid S. Miller 			/* Why not just use 'neigh' as-is?  The problem is that
145713a43d94SDavid S. Miller 			 * things such as shaper, eql, and sch_teql can end up
145813a43d94SDavid S. Miller 			 * using alternative, different, neigh objects to output
145913a43d94SDavid S. Miller 			 * the packet in the output path.  So what we need to do
146013a43d94SDavid S. Miller 			 * here is re-lookup the top-level neigh in the path so
146113a43d94SDavid S. Miller 			 * we can reinject the packet there.
146213a43d94SDavid S. Miller 			 */
146313a43d94SDavid S. Miller 			n2 = NULL;
1464d47ec7a0STong Zhu 			if (dst && dst->obsolete != DST_OBSOLETE_DEAD) {
146513a43d94SDavid S. Miller 				n2 = dst_neigh_lookup_skb(dst, skb);
146613a43d94SDavid S. Miller 				if (n2)
146769cce1d1SDavid S. Miller 					n1 = n2;
146813a43d94SDavid S. Miller 			}
14698f40b161SDavid S. Miller 			n1->output(n1, skb);
147013a43d94SDavid S. Miller 			if (n2)
147113a43d94SDavid S. Miller 				neigh_release(n2);
1472e049f288Sroy.qing.li@gmail.com 			rcu_read_unlock();
1473e049f288Sroy.qing.li@gmail.com 
14741da177e4SLinus Torvalds 			write_lock_bh(&neigh->lock);
14751da177e4SLinus Torvalds 		}
1476c9ab4d85SEric Dumazet 		__skb_queue_purge(&neigh->arp_queue);
14778b5c171bSEric Dumazet 		neigh->arp_queue_len_bytes = 0;
14781da177e4SLinus Torvalds 	}
14791da177e4SLinus Torvalds out:
1480fc6e8073SRoopa Prabhu 	if (update_isrouter)
1481fc6e8073SRoopa Prabhu 		neigh_update_is_router(neigh, flags, &notify);
14821da177e4SLinus Torvalds 	write_unlock_bh(&neigh->lock);
14837482e384SDaniel Borkmann 	if (((new ^ old) & NUD_PERMANENT) || gc_update)
14849c29a2f5SDavid Ahern 		neigh_update_gc_list(neigh);
14857482e384SDaniel Borkmann 	if (managed_update)
14867482e384SDaniel Borkmann 		neigh_update_managed_list(neigh);
14878d71740cSTom Tucker 	if (notify)
14887b8f7a40SRoopa Prabhu 		neigh_update_notify(neigh, nlmsg_pid);
148956dd18a4SRoopa Prabhu 	trace_neigh_update_done(neigh, err);
14901da177e4SLinus Torvalds 	return err;
14911da177e4SLinus Torvalds }
14927a35a50dSDavid Ahern 
14937a35a50dSDavid Ahern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
14947a35a50dSDavid Ahern 		 u32 flags, u32 nlmsg_pid)
14957a35a50dSDavid Ahern {
14967a35a50dSDavid Ahern 	return __neigh_update(neigh, lladdr, new, flags, nlmsg_pid, NULL);
14977a35a50dSDavid Ahern }
14980a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_update);
14991da177e4SLinus Torvalds 
15007e980569SJiri Benc /* Update the neigh to listen temporarily for probe responses, even if it is
15017e980569SJiri Benc  * in a NUD_FAILED state. The caller has to hold neigh->lock for writing.
15027e980569SJiri Benc  */
15037e980569SJiri Benc void __neigh_set_probe_once(struct neighbour *neigh)
15047e980569SJiri Benc {
15052c51a97fSJulian Anastasov 	if (neigh->dead)
15062c51a97fSJulian Anastasov 		return;
15077e980569SJiri Benc 	neigh->updated = jiffies;
15087e980569SJiri Benc 	if (!(neigh->nud_state & NUD_FAILED))
15097e980569SJiri Benc 		return;
15102176d5d4SDuan Jiong 	neigh->nud_state = NUD_INCOMPLETE;
15112176d5d4SDuan Jiong 	atomic_set(&neigh->probes, neigh_max_probes(neigh));
15127e980569SJiri Benc 	neigh_add_timer(neigh,
151319e16d22SHangbin Liu 			jiffies + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
151419e16d22SHangbin Liu 				      HZ/100));
15157e980569SJiri Benc }
15167e980569SJiri Benc EXPORT_SYMBOL(__neigh_set_probe_once);
15177e980569SJiri Benc 
15181da177e4SLinus Torvalds struct neighbour *neigh_event_ns(struct neigh_table *tbl,
15191da177e4SLinus Torvalds 				 u8 *lladdr, void *saddr,
15201da177e4SLinus Torvalds 				 struct net_device *dev)
15211da177e4SLinus Torvalds {
15221da177e4SLinus Torvalds 	struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
15231da177e4SLinus Torvalds 						 lladdr || !dev->addr_len);
15241da177e4SLinus Torvalds 	if (neigh)
15251da177e4SLinus Torvalds 		neigh_update(neigh, lladdr, NUD_STALE,
15267b8f7a40SRoopa Prabhu 			     NEIGH_UPDATE_F_OVERRIDE, 0);
15271da177e4SLinus Torvalds 	return neigh;
15281da177e4SLinus Torvalds }
15290a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_event_ns);
15301da177e4SLinus Torvalds 
153134d101ddSEric Dumazet /* called with read_lock_bh(&n->lock); */
1532bdf53c58SEric W. Biederman static void neigh_hh_init(struct neighbour *n)
15331da177e4SLinus Torvalds {
1534bdf53c58SEric W. Biederman 	struct net_device *dev = n->dev;
1535bdf53c58SEric W. Biederman 	__be16 prot = n->tbl->protocol;
1536f6b72b62SDavid S. Miller 	struct hh_cache	*hh = &n->hh;
15370ed8ddf4SEric Dumazet 
15380ed8ddf4SEric Dumazet 	write_lock_bh(&n->lock);
153934d101ddSEric Dumazet 
1540f6b72b62SDavid S. Miller 	/* Only one thread can come in here and initialize the
1541f6b72b62SDavid S. Miller 	 * hh_cache entry.
1542f6b72b62SDavid S. Miller 	 */
1543b23b5455SDavid S. Miller 	if (!hh->hh_len)
1544b23b5455SDavid S. Miller 		dev->header_ops->cache(n, hh, prot);
1545f6b72b62SDavid S. Miller 
15460ed8ddf4SEric Dumazet 	write_unlock_bh(&n->lock);
15471da177e4SLinus Torvalds }
15481da177e4SLinus Torvalds 
15491da177e4SLinus Torvalds /* Slow and careful. */
15501da177e4SLinus Torvalds 
15518f40b161SDavid S. Miller int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
15521da177e4SLinus Torvalds {
15531da177e4SLinus Torvalds 	int rc = 0;
15541da177e4SLinus Torvalds 
15551da177e4SLinus Torvalds 	if (!neigh_event_send(neigh, skb)) {
15561da177e4SLinus Torvalds 		int err;
15571da177e4SLinus Torvalds 		struct net_device *dev = neigh->dev;
15580ed8ddf4SEric Dumazet 		unsigned int seq;
155934d101ddSEric Dumazet 
1560c305c6aeSEric Dumazet 		if (dev->header_ops->cache && !READ_ONCE(neigh->hh.hh_len))
1561bdf53c58SEric W. Biederman 			neigh_hh_init(neigh);
156234d101ddSEric Dumazet 
15630ed8ddf4SEric Dumazet 		do {
1564e1f16503Sramesh.nagappa@gmail.com 			__skb_pull(skb, skb_network_offset(skb));
15650ed8ddf4SEric Dumazet 			seq = read_seqbegin(&neigh->ha_lock);
15660c4e8581SStephen Hemminger 			err = dev_hard_header(skb, dev, ntohs(skb->protocol),
15671da177e4SLinus Torvalds 					      neigh->ha, NULL, skb->len);
15680ed8ddf4SEric Dumazet 		} while (read_seqretry(&neigh->ha_lock, seq));
156934d101ddSEric Dumazet 
15701da177e4SLinus Torvalds 		if (err >= 0)
1571542d4d68SDavid S. Miller 			rc = dev_queue_xmit(skb);
15721da177e4SLinus Torvalds 		else
15731da177e4SLinus Torvalds 			goto out_kfree_skb;
15741da177e4SLinus Torvalds 	}
15751da177e4SLinus Torvalds out:
15761da177e4SLinus Torvalds 	return rc;
15771da177e4SLinus Torvalds out_kfree_skb:
15781da177e4SLinus Torvalds 	rc = -EINVAL;
15791da177e4SLinus Torvalds 	kfree_skb(skb);
15801da177e4SLinus Torvalds 	goto out;
15811da177e4SLinus Torvalds }
15820a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_resolve_output);
15831da177e4SLinus Torvalds 
15841da177e4SLinus Torvalds /* As fast as possible without hh cache */
15851da177e4SLinus Torvalds 
15868f40b161SDavid S. Miller int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
15871da177e4SLinus Torvalds {
15881da177e4SLinus Torvalds 	struct net_device *dev = neigh->dev;
15890ed8ddf4SEric Dumazet 	unsigned int seq;
15908f40b161SDavid S. Miller 	int err;
15911da177e4SLinus Torvalds 
15920ed8ddf4SEric Dumazet 	do {
1593e1f16503Sramesh.nagappa@gmail.com 		__skb_pull(skb, skb_network_offset(skb));
15940ed8ddf4SEric Dumazet 		seq = read_seqbegin(&neigh->ha_lock);
15950c4e8581SStephen Hemminger 		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
15961da177e4SLinus Torvalds 				      neigh->ha, NULL, skb->len);
15970ed8ddf4SEric Dumazet 	} while (read_seqretry(&neigh->ha_lock, seq));
15980ed8ddf4SEric Dumazet 
15991da177e4SLinus Torvalds 	if (err >= 0)
1600542d4d68SDavid S. Miller 		err = dev_queue_xmit(skb);
16011da177e4SLinus Torvalds 	else {
16021da177e4SLinus Torvalds 		err = -EINVAL;
16031da177e4SLinus Torvalds 		kfree_skb(skb);
16041da177e4SLinus Torvalds 	}
16051da177e4SLinus Torvalds 	return err;
16061da177e4SLinus Torvalds }
16070a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_connected_output);
16081da177e4SLinus Torvalds 
16098f40b161SDavid S. Miller int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
16108f40b161SDavid S. Miller {
16118f40b161SDavid S. Miller 	return dev_queue_xmit(skb);
16128f40b161SDavid S. Miller }
16138f40b161SDavid S. Miller EXPORT_SYMBOL(neigh_direct_output);
16148f40b161SDavid S. Miller 
16157482e384SDaniel Borkmann static void neigh_managed_work(struct work_struct *work)
16167482e384SDaniel Borkmann {
16177482e384SDaniel Borkmann 	struct neigh_table *tbl = container_of(work, struct neigh_table,
16187482e384SDaniel Borkmann 					       managed_work.work);
16197482e384SDaniel Borkmann 	struct neighbour *neigh;
16207482e384SDaniel Borkmann 
16217482e384SDaniel Borkmann 	write_lock_bh(&tbl->lock);
16227482e384SDaniel Borkmann 	list_for_each_entry(neigh, &tbl->managed_list, managed_list)
16234a81f6daSDaniel Borkmann 		neigh_event_send_probe(neigh, NULL, false);
16247482e384SDaniel Borkmann 	queue_delayed_work(system_power_efficient_wq, &tbl->managed_work,
1625211da42eSYuwei Wang 			   NEIGH_VAR(&tbl->parms, INTERVAL_PROBE_TIME_MS));
16267482e384SDaniel Borkmann 	write_unlock_bh(&tbl->lock);
16277482e384SDaniel Borkmann }
16287482e384SDaniel Borkmann 
1629e99e88a9SKees Cook static void neigh_proxy_process(struct timer_list *t)
16301da177e4SLinus Torvalds {
1631e99e88a9SKees Cook 	struct neigh_table *tbl = from_timer(tbl, t, proxy_timer);
16321da177e4SLinus Torvalds 	long sched_next = 0;
16331da177e4SLinus Torvalds 	unsigned long now = jiffies;
1634f72051b0SDavid S. Miller 	struct sk_buff *skb, *n;
16351da177e4SLinus Torvalds 
16361da177e4SLinus Torvalds 	spin_lock(&tbl->proxy_queue.lock);
16371da177e4SLinus Torvalds 
1638f72051b0SDavid S. Miller 	skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1639f72051b0SDavid S. Miller 		long tdif = NEIGH_CB(skb)->sched_next - now;
16401da177e4SLinus Torvalds 
16411da177e4SLinus Torvalds 		if (tdif <= 0) {
1642f72051b0SDavid S. Miller 			struct net_device *dev = skb->dev;
164320e6074eSEric Dumazet 
1644*8207f253SThomas Zeitlhofer 			neigh_parms_qlen_dec(dev, tbl->family);
1645f72051b0SDavid S. Miller 			__skb_unlink(skb, &tbl->proxy_queue);
16460ff4eb3dSAlexander Mikhalitsyn 
164720e6074eSEric Dumazet 			if (tbl->proxy_redo && netif_running(dev)) {
164820e6074eSEric Dumazet 				rcu_read_lock();
1649f72051b0SDavid S. Miller 				tbl->proxy_redo(skb);
165020e6074eSEric Dumazet 				rcu_read_unlock();
165120e6074eSEric Dumazet 			} else {
1652f72051b0SDavid S. Miller 				kfree_skb(skb);
165320e6074eSEric Dumazet 			}
16541da177e4SLinus Torvalds 
16551da177e4SLinus Torvalds 			dev_put(dev);
16561da177e4SLinus Torvalds 		} else if (!sched_next || tdif < sched_next)
16571da177e4SLinus Torvalds 			sched_next = tdif;
16581da177e4SLinus Torvalds 	}
16591da177e4SLinus Torvalds 	del_timer(&tbl->proxy_timer);
16601da177e4SLinus Torvalds 	if (sched_next)
16611da177e4SLinus Torvalds 		mod_timer(&tbl->proxy_timer, jiffies + sched_next);
16621da177e4SLinus Torvalds 	spin_unlock(&tbl->proxy_queue.lock);
16631da177e4SLinus Torvalds }
16641da177e4SLinus Torvalds 
16651da177e4SLinus Torvalds void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
16661da177e4SLinus Torvalds 		    struct sk_buff *skb)
16671da177e4SLinus Torvalds {
1668a533b70aSweichenchen 	unsigned long sched_next = jiffies +
1669a533b70aSweichenchen 			prandom_u32_max(NEIGH_VAR(p, PROXY_DELAY));
16701da177e4SLinus Torvalds 
16710ff4eb3dSAlexander Mikhalitsyn 	if (p->qlen > NEIGH_VAR(p, PROXY_QLEN)) {
16721da177e4SLinus Torvalds 		kfree_skb(skb);
16731da177e4SLinus Torvalds 		return;
16741da177e4SLinus Torvalds 	}
1675a61bbcf2SPatrick McHardy 
1676a61bbcf2SPatrick McHardy 	NEIGH_CB(skb)->sched_next = sched_next;
1677a61bbcf2SPatrick McHardy 	NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
16781da177e4SLinus Torvalds 
16791da177e4SLinus Torvalds 	spin_lock(&tbl->proxy_queue.lock);
16801da177e4SLinus Torvalds 	if (del_timer(&tbl->proxy_timer)) {
16811da177e4SLinus Torvalds 		if (time_before(tbl->proxy_timer.expires, sched_next))
16821da177e4SLinus Torvalds 			sched_next = tbl->proxy_timer.expires;
16831da177e4SLinus Torvalds 	}
1684adf30907SEric Dumazet 	skb_dst_drop(skb);
16851da177e4SLinus Torvalds 	dev_hold(skb->dev);
16861da177e4SLinus Torvalds 	__skb_queue_tail(&tbl->proxy_queue, skb);
16870ff4eb3dSAlexander Mikhalitsyn 	p->qlen++;
16881da177e4SLinus Torvalds 	mod_timer(&tbl->proxy_timer, sched_next);
16891da177e4SLinus Torvalds 	spin_unlock(&tbl->proxy_queue.lock);
16901da177e4SLinus Torvalds }
16910a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(pneigh_enqueue);
16921da177e4SLinus Torvalds 
169397fd5bc7STobias Klauser static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
1694426b5303SEric W. Biederman 						      struct net *net, int ifindex)
1695426b5303SEric W. Biederman {
1696426b5303SEric W. Biederman 	struct neigh_parms *p;
1697426b5303SEric W. Biederman 
169875fbfd33SNicolas Dichtel 	list_for_each_entry(p, &tbl->parms_list, list) {
1699878628fbSYOSHIFUJI Hideaki 		if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
1700170d6f99SGao feng 		    (!p->dev && !ifindex && net_eq(net, &init_net)))
1701426b5303SEric W. Biederman 			return p;
1702426b5303SEric W. Biederman 	}
1703426b5303SEric W. Biederman 
1704426b5303SEric W. Biederman 	return NULL;
1705426b5303SEric W. Biederman }
17061da177e4SLinus Torvalds 
17071da177e4SLinus Torvalds struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
17081da177e4SLinus Torvalds 				      struct neigh_table *tbl)
17091da177e4SLinus Torvalds {
1710cf89d6b2SGao feng 	struct neigh_parms *p;
171100829823SStephen Hemminger 	struct net *net = dev_net(dev);
171200829823SStephen Hemminger 	const struct net_device_ops *ops = dev->netdev_ops;
17131da177e4SLinus Torvalds 
1714cf89d6b2SGao feng 	p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL);
17151da177e4SLinus Torvalds 	if (p) {
17161da177e4SLinus Torvalds 		p->tbl		  = tbl;
17176343944bSReshetova, Elena 		refcount_set(&p->refcnt, 1);
17181da177e4SLinus Torvalds 		p->reachable_time =
17191f9248e5SJiri Pirko 				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
17200ff4eb3dSAlexander Mikhalitsyn 		p->qlen = 0;
1721d62607c3SJakub Kicinski 		netdev_hold(dev, &p->dev_tracker, GFP_KERNEL);
1722c7fb64dbSThomas Graf 		p->dev = dev;
1723efd7ef1cSEric W. Biederman 		write_pnet(&p->net, net);
17241da177e4SLinus Torvalds 		p->sysctl_table = NULL;
172563134803SVeaceslav Falico 
172663134803SVeaceslav Falico 		if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
1727d62607c3SJakub Kicinski 			netdev_put(dev, &p->dev_tracker);
172863134803SVeaceslav Falico 			kfree(p);
172963134803SVeaceslav Falico 			return NULL;
173063134803SVeaceslav Falico 		}
173163134803SVeaceslav Falico 
17321da177e4SLinus Torvalds 		write_lock_bh(&tbl->lock);
173375fbfd33SNicolas Dichtel 		list_add(&p->list, &tbl->parms.list);
17341da177e4SLinus Torvalds 		write_unlock_bh(&tbl->lock);
17351d4c8c29SJiri Pirko 
17361d4c8c29SJiri Pirko 		neigh_parms_data_state_cleanall(p);
17371da177e4SLinus Torvalds 	}
17381da177e4SLinus Torvalds 	return p;
17391da177e4SLinus Torvalds }
17400a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_parms_alloc);
17411da177e4SLinus Torvalds 
17421da177e4SLinus Torvalds static void neigh_rcu_free_parms(struct rcu_head *head)
17431da177e4SLinus Torvalds {
17441da177e4SLinus Torvalds 	struct neigh_parms *parms =
17451da177e4SLinus Torvalds 		container_of(head, struct neigh_parms, rcu_head);
17461da177e4SLinus Torvalds 
17471da177e4SLinus Torvalds 	neigh_parms_put(parms);
17481da177e4SLinus Torvalds }
17491da177e4SLinus Torvalds 
17501da177e4SLinus Torvalds void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
17511da177e4SLinus Torvalds {
17521da177e4SLinus Torvalds 	if (!parms || parms == &tbl->parms)
17531da177e4SLinus Torvalds 		return;
17541da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
175575fbfd33SNicolas Dichtel 	list_del(&parms->list);
17561da177e4SLinus Torvalds 	parms->dead = 1;
17571da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
1758d62607c3SJakub Kicinski 	netdev_put(parms->dev, &parms->dev_tracker);
17591da177e4SLinus Torvalds 	call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
17601da177e4SLinus Torvalds }
17610a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_parms_release);
17621da177e4SLinus Torvalds 
176306f0511dSDenis V. Lunev static void neigh_parms_destroy(struct neigh_parms *parms)
17641da177e4SLinus Torvalds {
17651da177e4SLinus Torvalds 	kfree(parms);
17661da177e4SLinus Torvalds }
17671da177e4SLinus Torvalds 
1768c2ecba71SPavel Emelianov static struct lock_class_key neigh_table_proxy_queue_class;
1769c2ecba71SPavel Emelianov 
1770d7480fd3SWANG Cong static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly;
1771d7480fd3SWANG Cong 
1772d7480fd3SWANG Cong void neigh_table_init(int index, struct neigh_table *tbl)
17731da177e4SLinus Torvalds {
17741da177e4SLinus Torvalds 	unsigned long now = jiffies;
17751da177e4SLinus Torvalds 	unsigned long phsize;
17761da177e4SLinus Torvalds 
177775fbfd33SNicolas Dichtel 	INIT_LIST_HEAD(&tbl->parms_list);
177858956317SDavid Ahern 	INIT_LIST_HEAD(&tbl->gc_list);
17797482e384SDaniel Borkmann 	INIT_LIST_HEAD(&tbl->managed_list);
17807482e384SDaniel Borkmann 
178175fbfd33SNicolas Dichtel 	list_add(&tbl->parms.list, &tbl->parms_list);
1782e42ea986SEric Dumazet 	write_pnet(&tbl->parms.net, &init_net);
17836343944bSReshetova, Elena 	refcount_set(&tbl->parms.refcnt, 1);
17841da177e4SLinus Torvalds 	tbl->parms.reachable_time =
17851f9248e5SJiri Pirko 			  neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME));
17860ff4eb3dSAlexander Mikhalitsyn 	tbl->parms.qlen = 0;
17871da177e4SLinus Torvalds 
17881da177e4SLinus Torvalds 	tbl->stats = alloc_percpu(struct neigh_statistics);
17891da177e4SLinus Torvalds 	if (!tbl->stats)
17901da177e4SLinus Torvalds 		panic("cannot create neighbour cache statistics");
17911da177e4SLinus Torvalds 
17921da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
179371a5053aSChristoph Hellwig 	if (!proc_create_seq_data(tbl->id, 0, init_net.proc_net_stat,
179471a5053aSChristoph Hellwig 			      &neigh_stat_seq_ops, tbl))
17951da177e4SLinus Torvalds 		panic("cannot create neighbour proc dir entry");
17961da177e4SLinus Torvalds #endif
17971da177e4SLinus Torvalds 
1798cd089336SDavid S. Miller 	RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
17991da177e4SLinus Torvalds 
18001da177e4SLinus Torvalds 	phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
180177d04bd9SAndrew Morton 	tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
18021da177e4SLinus Torvalds 
1803d6bf7817SEric Dumazet 	if (!tbl->nht || !tbl->phash_buckets)
18041da177e4SLinus Torvalds 		panic("cannot allocate neighbour cache hashes");
18051da177e4SLinus Torvalds 
180608433effSYOSHIFUJI Hideaki / 吉藤英明 	if (!tbl->entry_size)
180708433effSYOSHIFUJI Hideaki / 吉藤英明 		tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
180808433effSYOSHIFUJI Hideaki / 吉藤英明 					tbl->key_len, NEIGH_PRIV_ALIGN);
180908433effSYOSHIFUJI Hideaki / 吉藤英明 	else
181008433effSYOSHIFUJI Hideaki / 吉藤英明 		WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
181108433effSYOSHIFUJI Hideaki / 吉藤英明 
18121da177e4SLinus Torvalds 	rwlock_init(&tbl->lock);
18137482e384SDaniel Borkmann 
1814203b42f7STejun Heo 	INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
1815f618002bSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
1816f618002bSviresh kumar 			tbl->parms.reachable_time);
18177482e384SDaniel Borkmann 	INIT_DEFERRABLE_WORK(&tbl->managed_work, neigh_managed_work);
18187482e384SDaniel Borkmann 	queue_delayed_work(system_power_efficient_wq, &tbl->managed_work, 0);
18197482e384SDaniel Borkmann 
1820e99e88a9SKees Cook 	timer_setup(&tbl->proxy_timer, neigh_proxy_process, 0);
1821c2ecba71SPavel Emelianov 	skb_queue_head_init_class(&tbl->proxy_queue,
1822c2ecba71SPavel Emelianov 			&neigh_table_proxy_queue_class);
18231da177e4SLinus Torvalds 
18241da177e4SLinus Torvalds 	tbl->last_flush = now;
18251da177e4SLinus Torvalds 	tbl->last_rand	= now + tbl->parms.reachable_time * 20;
1826bd89efc5SSimon Kelley 
1827d7480fd3SWANG Cong 	neigh_tables[index] = tbl;
18281da177e4SLinus Torvalds }
18290a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_table_init);
18301da177e4SLinus Torvalds 
1831d7480fd3SWANG Cong int neigh_table_clear(int index, struct neigh_table *tbl)
18321da177e4SLinus Torvalds {
1833d7480fd3SWANG Cong 	neigh_tables[index] = NULL;
18341da177e4SLinus Torvalds 	/* It is not clean... Fix it to unload IPv6 module safely */
18354177d5b0SDaniel Borkmann 	cancel_delayed_work_sync(&tbl->managed_work);
1836a5c30b34STejun Heo 	cancel_delayed_work_sync(&tbl->gc_work);
18371da177e4SLinus Torvalds 	del_timer_sync(&tbl->proxy_timer);
1838*8207f253SThomas Zeitlhofer 	pneigh_queue_purge(&tbl->proxy_queue, NULL, tbl->family);
18391da177e4SLinus Torvalds 	neigh_ifdown(tbl, NULL);
18401da177e4SLinus Torvalds 	if (atomic_read(&tbl->entries))
1841e005d193SJoe Perches 		pr_crit("neighbour leakage\n");
18421da177e4SLinus Torvalds 
18436193d2beSEric Dumazet 	call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
18446193d2beSEric Dumazet 		 neigh_hash_free_rcu);
1845d6bf7817SEric Dumazet 	tbl->nht = NULL;
18461da177e4SLinus Torvalds 
18471da177e4SLinus Torvalds 	kfree(tbl->phash_buckets);
18481da177e4SLinus Torvalds 	tbl->phash_buckets = NULL;
18491da177e4SLinus Torvalds 
18503f192b5cSAlexey Dobriyan 	remove_proc_entry(tbl->id, init_net.proc_net_stat);
18513f192b5cSAlexey Dobriyan 
18523fcde74bSKirill Korotaev 	free_percpu(tbl->stats);
18533fcde74bSKirill Korotaev 	tbl->stats = NULL;
18543fcde74bSKirill Korotaev 
18551da177e4SLinus Torvalds 	return 0;
18561da177e4SLinus Torvalds }
18570a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_table_clear);
18581da177e4SLinus Torvalds 
1859d7480fd3SWANG Cong static struct neigh_table *neigh_find_table(int family)
1860d7480fd3SWANG Cong {
1861d7480fd3SWANG Cong 	struct neigh_table *tbl = NULL;
1862d7480fd3SWANG Cong 
1863d7480fd3SWANG Cong 	switch (family) {
1864d7480fd3SWANG Cong 	case AF_INET:
1865d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_ARP_TABLE];
1866d7480fd3SWANG Cong 		break;
1867d7480fd3SWANG Cong 	case AF_INET6:
1868d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_ND_TABLE];
1869d7480fd3SWANG Cong 		break;
1870d7480fd3SWANG Cong 	}
1871d7480fd3SWANG Cong 
1872d7480fd3SWANG Cong 	return tbl;
1873d7480fd3SWANG Cong }
1874d7480fd3SWANG Cong 
187582cbb5c6SRoopa Prabhu const struct nla_policy nda_policy[NDA_MAX+1] = {
18761274e1ccSRoopa Prabhu 	[NDA_UNSPEC]		= { .strict_start_type = NDA_NH_ID },
187782cbb5c6SRoopa Prabhu 	[NDA_DST]		= { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
187882cbb5c6SRoopa Prabhu 	[NDA_LLADDR]		= { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
187982cbb5c6SRoopa Prabhu 	[NDA_CACHEINFO]		= { .len = sizeof(struct nda_cacheinfo) },
188082cbb5c6SRoopa Prabhu 	[NDA_PROBES]		= { .type = NLA_U32 },
188182cbb5c6SRoopa Prabhu 	[NDA_VLAN]		= { .type = NLA_U16 },
188282cbb5c6SRoopa Prabhu 	[NDA_PORT]		= { .type = NLA_U16 },
188382cbb5c6SRoopa Prabhu 	[NDA_VNI]		= { .type = NLA_U32 },
188482cbb5c6SRoopa Prabhu 	[NDA_IFINDEX]		= { .type = NLA_U32 },
188582cbb5c6SRoopa Prabhu 	[NDA_MASTER]		= { .type = NLA_U32 },
1886a9cd3439SDavid Ahern 	[NDA_PROTOCOL]		= { .type = NLA_U8 },
18871274e1ccSRoopa Prabhu 	[NDA_NH_ID]		= { .type = NLA_U32 },
1888c8e80c11SDaniel Borkmann 	[NDA_FLAGS_EXT]		= NLA_POLICY_MASK(NLA_U32, NTF_EXT_MASK),
1889899426b3SNikolay Aleksandrov 	[NDA_FDB_EXT_ATTRS]	= { .type = NLA_NESTED },
189082cbb5c6SRoopa Prabhu };
189182cbb5c6SRoopa Prabhu 
1892c21ef3e3SDavid Ahern static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
1893c21ef3e3SDavid Ahern 			struct netlink_ext_ack *extack)
18941da177e4SLinus Torvalds {
18953b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
1896a14a49d2SThomas Graf 	struct ndmsg *ndm;
1897a14a49d2SThomas Graf 	struct nlattr *dst_attr;
18981da177e4SLinus Torvalds 	struct neigh_table *tbl;
1899d7480fd3SWANG Cong 	struct neighbour *neigh;
19001da177e4SLinus Torvalds 	struct net_device *dev = NULL;
1901a14a49d2SThomas Graf 	int err = -EINVAL;
19021da177e4SLinus Torvalds 
1903110b2499SEric Dumazet 	ASSERT_RTNL();
1904a14a49d2SThomas Graf 	if (nlmsg_len(nlh) < sizeof(*ndm))
19051da177e4SLinus Torvalds 		goto out;
19061da177e4SLinus Torvalds 
1907a14a49d2SThomas Graf 	dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
19087a35a50dSDavid Ahern 	if (!dst_attr) {
19097a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Network address not specified");
1910a14a49d2SThomas Graf 		goto out;
19117a35a50dSDavid Ahern 	}
1912a14a49d2SThomas Graf 
1913a14a49d2SThomas Graf 	ndm = nlmsg_data(nlh);
1914a14a49d2SThomas Graf 	if (ndm->ndm_ifindex) {
1915110b2499SEric Dumazet 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
1916a14a49d2SThomas Graf 		if (dev == NULL) {
1917a14a49d2SThomas Graf 			err = -ENODEV;
1918a14a49d2SThomas Graf 			goto out;
1919a14a49d2SThomas Graf 		}
1920a14a49d2SThomas Graf 	}
1921a14a49d2SThomas Graf 
1922d7480fd3SWANG Cong 	tbl = neigh_find_table(ndm->ndm_family);
1923d7480fd3SWANG Cong 	if (tbl == NULL)
1924d7480fd3SWANG Cong 		return -EAFNOSUPPORT;
19251da177e4SLinus Torvalds 
19267a35a50dSDavid Ahern 	if (nla_len(dst_attr) < (int)tbl->key_len) {
19277a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid network address");
1928110b2499SEric Dumazet 		goto out;
19297a35a50dSDavid Ahern 	}
19301da177e4SLinus Torvalds 
19311da177e4SLinus Torvalds 	if (ndm->ndm_flags & NTF_PROXY) {
1932426b5303SEric W. Biederman 		err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
1933110b2499SEric Dumazet 		goto out;
19341da177e4SLinus Torvalds 	}
19351da177e4SLinus Torvalds 
1936a14a49d2SThomas Graf 	if (dev == NULL)
1937110b2499SEric Dumazet 		goto out;
19381da177e4SLinus Torvalds 
1939a14a49d2SThomas Graf 	neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1940a14a49d2SThomas Graf 	if (neigh == NULL) {
1941a14a49d2SThomas Graf 		err = -ENOENT;
1942110b2499SEric Dumazet 		goto out;
1943a14a49d2SThomas Graf 	}
1944a14a49d2SThomas Graf 
19457a35a50dSDavid Ahern 	err = __neigh_update(neigh, NULL, NUD_FAILED,
19467a35a50dSDavid Ahern 			     NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN,
19477a35a50dSDavid Ahern 			     NETLINK_CB(skb).portid, extack);
19485071034eSSowmini Varadhan 	write_lock_bh(&tbl->lock);
1949a14a49d2SThomas Graf 	neigh_release(neigh);
19505071034eSSowmini Varadhan 	neigh_remove_one(neigh, tbl);
19515071034eSSowmini Varadhan 	write_unlock_bh(&tbl->lock);
1952a14a49d2SThomas Graf 
19531da177e4SLinus Torvalds out:
19541da177e4SLinus Torvalds 	return err;
19551da177e4SLinus Torvalds }
19561da177e4SLinus Torvalds 
1957c21ef3e3SDavid Ahern static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
1958c21ef3e3SDavid Ahern 		     struct netlink_ext_ack *extack)
19591da177e4SLinus Torvalds {
1960f7aa74e4SRoopa Prabhu 	int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE |
1961f7aa74e4SRoopa Prabhu 		    NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
19623b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
19635208debdSThomas Graf 	struct ndmsg *ndm;
19645208debdSThomas Graf 	struct nlattr *tb[NDA_MAX+1];
19651da177e4SLinus Torvalds 	struct neigh_table *tbl;
19661da177e4SLinus Torvalds 	struct net_device *dev = NULL;
1967d7480fd3SWANG Cong 	struct neighbour *neigh;
1968d7480fd3SWANG Cong 	void *dst, *lladdr;
1969df9b0e30SDavid Ahern 	u8 protocol = 0;
19702c611ad9SRoopa Prabhu 	u32 ndm_flags;
19715208debdSThomas Graf 	int err;
19721da177e4SLinus Torvalds 
1973110b2499SEric Dumazet 	ASSERT_RTNL();
19748cb08174SJohannes Berg 	err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX,
19758cb08174SJohannes Berg 				     nda_policy, extack);
19765208debdSThomas Graf 	if (err < 0)
19771da177e4SLinus Torvalds 		goto out;
19781da177e4SLinus Torvalds 
19795208debdSThomas Graf 	err = -EINVAL;
19807a35a50dSDavid Ahern 	if (!tb[NDA_DST]) {
19817a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Network address not specified");
19825208debdSThomas Graf 		goto out;
19837a35a50dSDavid Ahern 	}
19845208debdSThomas Graf 
19855208debdSThomas Graf 	ndm = nlmsg_data(nlh);
19862c611ad9SRoopa Prabhu 	ndm_flags = ndm->ndm_flags;
19872c611ad9SRoopa Prabhu 	if (tb[NDA_FLAGS_EXT]) {
19882c611ad9SRoopa Prabhu 		u32 ext = nla_get_u32(tb[NDA_FLAGS_EXT]);
19892c611ad9SRoopa Prabhu 
1990507c2f1dSDaniel Borkmann 		BUILD_BUG_ON(sizeof(neigh->flags) * BITS_PER_BYTE <
1991507c2f1dSDaniel Borkmann 			     (sizeof(ndm->ndm_flags) * BITS_PER_BYTE +
1992507c2f1dSDaniel Borkmann 			      hweight32(NTF_EXT_MASK)));
19932c611ad9SRoopa Prabhu 		ndm_flags |= (ext << NTF_EXT_SHIFT);
19942c611ad9SRoopa Prabhu 	}
19955208debdSThomas Graf 	if (ndm->ndm_ifindex) {
1996110b2499SEric Dumazet 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
19975208debdSThomas Graf 		if (dev == NULL) {
19985208debdSThomas Graf 			err = -ENODEV;
19995208debdSThomas Graf 			goto out;
20005208debdSThomas Graf 		}
20015208debdSThomas Graf 
20027a35a50dSDavid Ahern 		if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) {
20037a35a50dSDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid link address");
2004110b2499SEric Dumazet 			goto out;
20055208debdSThomas Graf 		}
20067a35a50dSDavid Ahern 	}
20075208debdSThomas Graf 
2008d7480fd3SWANG Cong 	tbl = neigh_find_table(ndm->ndm_family);
2009d7480fd3SWANG Cong 	if (tbl == NULL)
2010d7480fd3SWANG Cong 		return -EAFNOSUPPORT;
20111da177e4SLinus Torvalds 
20127a35a50dSDavid Ahern 	if (nla_len(tb[NDA_DST]) < (int)tbl->key_len) {
20137a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid network address");
2014110b2499SEric Dumazet 		goto out;
20157a35a50dSDavid Ahern 	}
20167a35a50dSDavid Ahern 
20175208debdSThomas Graf 	dst = nla_data(tb[NDA_DST]);
20185208debdSThomas Graf 	lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
20191da177e4SLinus Torvalds 
2020a9cd3439SDavid Ahern 	if (tb[NDA_PROTOCOL])
2021df9b0e30SDavid Ahern 		protocol = nla_get_u8(tb[NDA_PROTOCOL]);
20222c611ad9SRoopa Prabhu 	if (ndm_flags & NTF_PROXY) {
202362dd9318SVille Nuorvala 		struct pneigh_entry *pn;
202462dd9318SVille Nuorvala 
20257482e384SDaniel Borkmann 		if (ndm_flags & NTF_MANAGED) {
20267482e384SDaniel Borkmann 			NL_SET_ERR_MSG(extack, "Invalid NTF_* flag combination");
20277482e384SDaniel Borkmann 			goto out;
20287482e384SDaniel Borkmann 		}
20297482e384SDaniel Borkmann 
20305208debdSThomas Graf 		err = -ENOBUFS;
2031426b5303SEric W. Biederman 		pn = pneigh_lookup(tbl, net, dst, dev, 1);
203262dd9318SVille Nuorvala 		if (pn) {
20332c611ad9SRoopa Prabhu 			pn->flags = ndm_flags;
2034df9b0e30SDavid Ahern 			if (protocol)
2035df9b0e30SDavid Ahern 				pn->protocol = protocol;
203662dd9318SVille Nuorvala 			err = 0;
203762dd9318SVille Nuorvala 		}
2038110b2499SEric Dumazet 		goto out;
20391da177e4SLinus Torvalds 	}
20401da177e4SLinus Torvalds 
20417a35a50dSDavid Ahern 	if (!dev) {
20427a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Device not specified");
2043110b2499SEric Dumazet 		goto out;
20447a35a50dSDavid Ahern 	}
20451da177e4SLinus Torvalds 
2046b8fb1ab4SDavid Ahern 	if (tbl->allow_add && !tbl->allow_add(dev, extack)) {
2047b8fb1ab4SDavid Ahern 		err = -EINVAL;
2048b8fb1ab4SDavid Ahern 		goto out;
2049b8fb1ab4SDavid Ahern 	}
2050b8fb1ab4SDavid Ahern 
20515208debdSThomas Graf 	neigh = neigh_lookup(tbl, dst, dev);
20525208debdSThomas Graf 	if (neigh == NULL) {
205330fc7efaSDaniel Borkmann 		bool ndm_permanent  = ndm->ndm_state & NUD_PERMANENT;
205430fc7efaSDaniel Borkmann 		bool exempt_from_gc = ndm_permanent ||
205530fc7efaSDaniel Borkmann 				      ndm_flags & NTF_EXT_LEARNED;
2056e997f8a2SDavid Ahern 
20575208debdSThomas Graf 		if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
20581da177e4SLinus Torvalds 			err = -ENOENT;
2059110b2499SEric Dumazet 			goto out;
20605208debdSThomas Graf 		}
206130fc7efaSDaniel Borkmann 		if (ndm_permanent && (ndm_flags & NTF_MANAGED)) {
206230fc7efaSDaniel Borkmann 			NL_SET_ERR_MSG(extack, "Invalid NTF_* flag for permanent entry");
206330fc7efaSDaniel Borkmann 			err = -EINVAL;
206430fc7efaSDaniel Borkmann 			goto out;
206530fc7efaSDaniel Borkmann 		}
20665208debdSThomas Graf 
2067e4400bbfSDaniel Borkmann 		neigh = ___neigh_create(tbl, dst, dev,
20687482e384SDaniel Borkmann 					ndm_flags &
20697482e384SDaniel Borkmann 					(NTF_EXT_LEARNED | NTF_MANAGED),
2070e4400bbfSDaniel Borkmann 					exempt_from_gc, true);
20715208debdSThomas Graf 		if (IS_ERR(neigh)) {
20725208debdSThomas Graf 			err = PTR_ERR(neigh);
2073110b2499SEric Dumazet 			goto out;
20741da177e4SLinus Torvalds 		}
20755208debdSThomas Graf 	} else {
20765208debdSThomas Graf 		if (nlh->nlmsg_flags & NLM_F_EXCL) {
20775208debdSThomas Graf 			err = -EEXIST;
20785208debdSThomas Graf 			neigh_release(neigh);
2079110b2499SEric Dumazet 			goto out;
20801da177e4SLinus Torvalds 		}
20811da177e4SLinus Torvalds 
20825208debdSThomas Graf 		if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
2083f7aa74e4SRoopa Prabhu 			flags &= ~(NEIGH_UPDATE_F_OVERRIDE |
2084f7aa74e4SRoopa Prabhu 				   NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
20855208debdSThomas Graf 	}
20861da177e4SLinus Torvalds 
208738212bb3SRoman Mashak 	if (protocol)
208838212bb3SRoman Mashak 		neigh->protocol = protocol;
20892c611ad9SRoopa Prabhu 	if (ndm_flags & NTF_EXT_LEARNED)
20909ce33e46SRoopa Prabhu 		flags |= NEIGH_UPDATE_F_EXT_LEARNED;
20912c611ad9SRoopa Prabhu 	if (ndm_flags & NTF_ROUTER)
2092f7aa74e4SRoopa Prabhu 		flags |= NEIGH_UPDATE_F_ISROUTER;
20937482e384SDaniel Borkmann 	if (ndm_flags & NTF_MANAGED)
20947482e384SDaniel Borkmann 		flags |= NEIGH_UPDATE_F_MANAGED;
20952c611ad9SRoopa Prabhu 	if (ndm_flags & NTF_USE)
20963dc20f47SDaniel Borkmann 		flags |= NEIGH_UPDATE_F_USE;
2097f7aa74e4SRoopa Prabhu 
20987a35a50dSDavid Ahern 	err = __neigh_update(neigh, lladdr, ndm->ndm_state, flags,
20997a35a50dSDavid Ahern 			     NETLINK_CB(skb).portid, extack);
21007482e384SDaniel Borkmann 	if (!err && ndm_flags & (NTF_USE | NTF_MANAGED)) {
21013dc20f47SDaniel Borkmann 		neigh_event_send(neigh, NULL);
21023dc20f47SDaniel Borkmann 		err = 0;
21033dc20f47SDaniel Borkmann 	}
21045208debdSThomas Graf 	neigh_release(neigh);
21051da177e4SLinus Torvalds out:
21061da177e4SLinus Torvalds 	return err;
21071da177e4SLinus Torvalds }
21081da177e4SLinus Torvalds 
2109c7fb64dbSThomas Graf static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
2110c7fb64dbSThomas Graf {
2111ca860fb3SThomas Graf 	struct nlattr *nest;
2112e386c6ebSThomas Graf 
2113ae0be8deSMichal Kubecek 	nest = nla_nest_start_noflag(skb, NDTA_PARMS);
2114ca860fb3SThomas Graf 	if (nest == NULL)
2115ca860fb3SThomas Graf 		return -ENOBUFS;
2116c7fb64dbSThomas Graf 
21179a6308d7SDavid S. Miller 	if ((parms->dev &&
21189a6308d7SDavid S. Miller 	     nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
21196343944bSReshetova, Elena 	    nla_put_u32(skb, NDTPA_REFCNT, refcount_read(&parms->refcnt)) ||
21201f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_QUEUE_LENBYTES,
21211f9248e5SJiri Pirko 			NEIGH_VAR(parms, QUEUE_LEN_BYTES)) ||
21228b5c171bSEric Dumazet 	    /* approximative value for deprecated QUEUE_LEN (in packets) */
21239a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTPA_QUEUE_LEN,
21241f9248e5SJiri Pirko 			NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) ||
21251f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) ||
21261f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) ||
21271f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_UCAST_PROBES,
21281f9248e5SJiri Pirko 			NEIGH_VAR(parms, UCAST_PROBES)) ||
21291f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_MCAST_PROBES,
21301f9248e5SJiri Pirko 			NEIGH_VAR(parms, MCAST_PROBES)) ||
21318da86466SYOSHIFUJI Hideaki/吉藤英明 	    nla_put_u32(skb, NDTPA_MCAST_REPROBES,
21328da86466SYOSHIFUJI Hideaki/吉藤英明 			NEIGH_VAR(parms, MCAST_REPROBES)) ||
21332175d87cSNicolas Dichtel 	    nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time,
21342175d87cSNicolas Dichtel 			  NDTPA_PAD) ||
21359a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
21362175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, BASE_REACHABLE_TIME), NDTPA_PAD) ||
21371f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_GC_STALETIME,
21382175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, GC_STALETIME), NDTPA_PAD) ||
21399a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
21402175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, DELAY_PROBE_TIME), NDTPA_PAD) ||
21411f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_RETRANS_TIME,
21422175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, RETRANS_TIME), NDTPA_PAD) ||
21431f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_ANYCAST_DELAY,
21442175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, ANYCAST_DELAY), NDTPA_PAD) ||
21451f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_PROXY_DELAY,
21462175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, PROXY_DELAY), NDTPA_PAD) ||
21471f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_LOCKTIME,
2148211da42eSYuwei Wang 			  NEIGH_VAR(parms, LOCKTIME), NDTPA_PAD) ||
2149211da42eSYuwei Wang 	    nla_put_msecs(skb, NDTPA_INTERVAL_PROBE_TIME_MS,
2150211da42eSYuwei Wang 			  NEIGH_VAR(parms, INTERVAL_PROBE_TIME_MS), NDTPA_PAD))
21519a6308d7SDavid S. Miller 		goto nla_put_failure;
2152ca860fb3SThomas Graf 	return nla_nest_end(skb, nest);
2153c7fb64dbSThomas Graf 
2154ca860fb3SThomas Graf nla_put_failure:
2155bc3ed28cSThomas Graf 	nla_nest_cancel(skb, nest);
2156bc3ed28cSThomas Graf 	return -EMSGSIZE;
2157c7fb64dbSThomas Graf }
2158c7fb64dbSThomas Graf 
2159ca860fb3SThomas Graf static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
2160ca860fb3SThomas Graf 			      u32 pid, u32 seq, int type, int flags)
2161c7fb64dbSThomas Graf {
2162c7fb64dbSThomas Graf 	struct nlmsghdr *nlh;
2163c7fb64dbSThomas Graf 	struct ndtmsg *ndtmsg;
2164c7fb64dbSThomas Graf 
2165ca860fb3SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2166ca860fb3SThomas Graf 	if (nlh == NULL)
216726932566SPatrick McHardy 		return -EMSGSIZE;
2168c7fb64dbSThomas Graf 
2169ca860fb3SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2170c7fb64dbSThomas Graf 
2171c7fb64dbSThomas Graf 	read_lock_bh(&tbl->lock);
2172c7fb64dbSThomas Graf 	ndtmsg->ndtm_family = tbl->family;
21739ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad1   = 0;
21749ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad2   = 0;
2175c7fb64dbSThomas Graf 
21769a6308d7SDavid S. Miller 	if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
21772175d87cSNicolas Dichtel 	    nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval, NDTA_PAD) ||
21789a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
21799a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
21809a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
21819a6308d7SDavid S. Miller 		goto nla_put_failure;
2182c7fb64dbSThomas Graf 	{
2183c7fb64dbSThomas Graf 		unsigned long now = jiffies;
21849d027e3aSEric Dumazet 		long flush_delta = now - tbl->last_flush;
21859d027e3aSEric Dumazet 		long rand_delta = now - tbl->last_rand;
2186d6bf7817SEric Dumazet 		struct neigh_hash_table *nht;
2187c7fb64dbSThomas Graf 		struct ndt_config ndc = {
2188c7fb64dbSThomas Graf 			.ndtc_key_len		= tbl->key_len,
2189c7fb64dbSThomas Graf 			.ndtc_entry_size	= tbl->entry_size,
2190c7fb64dbSThomas Graf 			.ndtc_entries		= atomic_read(&tbl->entries),
2191c7fb64dbSThomas Graf 			.ndtc_last_flush	= jiffies_to_msecs(flush_delta),
2192c7fb64dbSThomas Graf 			.ndtc_last_rand		= jiffies_to_msecs(rand_delta),
2193c7fb64dbSThomas Graf 			.ndtc_proxy_qlen	= tbl->proxy_queue.qlen,
2194c7fb64dbSThomas Graf 		};
2195c7fb64dbSThomas Graf 
2196d6bf7817SEric Dumazet 		rcu_read_lock_bh();
2197d6bf7817SEric Dumazet 		nht = rcu_dereference_bh(tbl->nht);
21982c2aba6cSDavid S. Miller 		ndc.ndtc_hash_rnd = nht->hash_rnd[0];
2199cd089336SDavid S. Miller 		ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
2200d6bf7817SEric Dumazet 		rcu_read_unlock_bh();
2201d6bf7817SEric Dumazet 
22029a6308d7SDavid S. Miller 		if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
22039a6308d7SDavid S. Miller 			goto nla_put_failure;
2204c7fb64dbSThomas Graf 	}
2205c7fb64dbSThomas Graf 
2206c7fb64dbSThomas Graf 	{
2207c7fb64dbSThomas Graf 		int cpu;
2208c7fb64dbSThomas Graf 		struct ndt_stats ndst;
2209c7fb64dbSThomas Graf 
2210c7fb64dbSThomas Graf 		memset(&ndst, 0, sizeof(ndst));
2211c7fb64dbSThomas Graf 
22126f912042SKAMEZAWA Hiroyuki 		for_each_possible_cpu(cpu) {
2213c7fb64dbSThomas Graf 			struct neigh_statistics	*st;
2214c7fb64dbSThomas Graf 
2215c7fb64dbSThomas Graf 			st = per_cpu_ptr(tbl->stats, cpu);
2216c7fb64dbSThomas Graf 			ndst.ndts_allocs		+= st->allocs;
2217c7fb64dbSThomas Graf 			ndst.ndts_destroys		+= st->destroys;
2218c7fb64dbSThomas Graf 			ndst.ndts_hash_grows		+= st->hash_grows;
2219c7fb64dbSThomas Graf 			ndst.ndts_res_failed		+= st->res_failed;
2220c7fb64dbSThomas Graf 			ndst.ndts_lookups		+= st->lookups;
2221c7fb64dbSThomas Graf 			ndst.ndts_hits			+= st->hits;
2222c7fb64dbSThomas Graf 			ndst.ndts_rcv_probes_mcast	+= st->rcv_probes_mcast;
2223c7fb64dbSThomas Graf 			ndst.ndts_rcv_probes_ucast	+= st->rcv_probes_ucast;
2224c7fb64dbSThomas Graf 			ndst.ndts_periodic_gc_runs	+= st->periodic_gc_runs;
2225c7fb64dbSThomas Graf 			ndst.ndts_forced_gc_runs	+= st->forced_gc_runs;
2226fb811395SRick Jones 			ndst.ndts_table_fulls		+= st->table_fulls;
2227c7fb64dbSThomas Graf 		}
2228c7fb64dbSThomas Graf 
2229b676338fSNicolas Dichtel 		if (nla_put_64bit(skb, NDTA_STATS, sizeof(ndst), &ndst,
2230b676338fSNicolas Dichtel 				  NDTA_PAD))
22319a6308d7SDavid S. Miller 			goto nla_put_failure;
2232c7fb64dbSThomas Graf 	}
2233c7fb64dbSThomas Graf 
2234c7fb64dbSThomas Graf 	BUG_ON(tbl->parms.dev);
2235c7fb64dbSThomas Graf 	if (neightbl_fill_parms(skb, &tbl->parms) < 0)
2236ca860fb3SThomas Graf 		goto nla_put_failure;
2237c7fb64dbSThomas Graf 
2238c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
2239053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2240053c095aSJohannes Berg 	return 0;
2241c7fb64dbSThomas Graf 
2242ca860fb3SThomas Graf nla_put_failure:
2243c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
224426932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
224526932566SPatrick McHardy 	return -EMSGSIZE;
2246c7fb64dbSThomas Graf }
2247c7fb64dbSThomas Graf 
2248ca860fb3SThomas Graf static int neightbl_fill_param_info(struct sk_buff *skb,
2249ca860fb3SThomas Graf 				    struct neigh_table *tbl,
2250c7fb64dbSThomas Graf 				    struct neigh_parms *parms,
2251ca860fb3SThomas Graf 				    u32 pid, u32 seq, int type,
2252ca860fb3SThomas Graf 				    unsigned int flags)
2253c7fb64dbSThomas Graf {
2254c7fb64dbSThomas Graf 	struct ndtmsg *ndtmsg;
2255c7fb64dbSThomas Graf 	struct nlmsghdr *nlh;
2256c7fb64dbSThomas Graf 
2257ca860fb3SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2258ca860fb3SThomas Graf 	if (nlh == NULL)
225926932566SPatrick McHardy 		return -EMSGSIZE;
2260c7fb64dbSThomas Graf 
2261ca860fb3SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2262c7fb64dbSThomas Graf 
2263c7fb64dbSThomas Graf 	read_lock_bh(&tbl->lock);
2264c7fb64dbSThomas Graf 	ndtmsg->ndtm_family = tbl->family;
22659ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad1   = 0;
22669ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad2   = 0;
2267c7fb64dbSThomas Graf 
2268ca860fb3SThomas Graf 	if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
2269ca860fb3SThomas Graf 	    neightbl_fill_parms(skb, parms) < 0)
2270ca860fb3SThomas Graf 		goto errout;
2271c7fb64dbSThomas Graf 
2272c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
2273053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2274053c095aSJohannes Berg 	return 0;
2275ca860fb3SThomas Graf errout:
2276c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
227726932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
227826932566SPatrick McHardy 	return -EMSGSIZE;
2279c7fb64dbSThomas Graf }
2280c7fb64dbSThomas Graf 
2281ef7c79edSPatrick McHardy static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
22826b3f8674SThomas Graf 	[NDTA_NAME]		= { .type = NLA_STRING },
22836b3f8674SThomas Graf 	[NDTA_THRESH1]		= { .type = NLA_U32 },
22846b3f8674SThomas Graf 	[NDTA_THRESH2]		= { .type = NLA_U32 },
22856b3f8674SThomas Graf 	[NDTA_THRESH3]		= { .type = NLA_U32 },
22866b3f8674SThomas Graf 	[NDTA_GC_INTERVAL]	= { .type = NLA_U64 },
22876b3f8674SThomas Graf 	[NDTA_PARMS]		= { .type = NLA_NESTED },
22886b3f8674SThomas Graf };
22896b3f8674SThomas Graf 
2290ef7c79edSPatrick McHardy static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
22916b3f8674SThomas Graf 	[NDTPA_IFINDEX]			= { .type = NLA_U32 },
22926b3f8674SThomas Graf 	[NDTPA_QUEUE_LEN]		= { .type = NLA_U32 },
22936b3f8674SThomas Graf 	[NDTPA_PROXY_QLEN]		= { .type = NLA_U32 },
22946b3f8674SThomas Graf 	[NDTPA_APP_PROBES]		= { .type = NLA_U32 },
22956b3f8674SThomas Graf 	[NDTPA_UCAST_PROBES]		= { .type = NLA_U32 },
22966b3f8674SThomas Graf 	[NDTPA_MCAST_PROBES]		= { .type = NLA_U32 },
22978da86466SYOSHIFUJI Hideaki/吉藤英明 	[NDTPA_MCAST_REPROBES]		= { .type = NLA_U32 },
22986b3f8674SThomas Graf 	[NDTPA_BASE_REACHABLE_TIME]	= { .type = NLA_U64 },
22996b3f8674SThomas Graf 	[NDTPA_GC_STALETIME]		= { .type = NLA_U64 },
23006b3f8674SThomas Graf 	[NDTPA_DELAY_PROBE_TIME]	= { .type = NLA_U64 },
23016b3f8674SThomas Graf 	[NDTPA_RETRANS_TIME]		= { .type = NLA_U64 },
23026b3f8674SThomas Graf 	[NDTPA_ANYCAST_DELAY]		= { .type = NLA_U64 },
23036b3f8674SThomas Graf 	[NDTPA_PROXY_DELAY]		= { .type = NLA_U64 },
23046b3f8674SThomas Graf 	[NDTPA_LOCKTIME]		= { .type = NLA_U64 },
2305211da42eSYuwei Wang 	[NDTPA_INTERVAL_PROBE_TIME_MS]	= { .type = NLA_U64, .min = 1 },
23066b3f8674SThomas Graf };
23076b3f8674SThomas Graf 
2308c21ef3e3SDavid Ahern static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
2309c21ef3e3SDavid Ahern 			struct netlink_ext_ack *extack)
2310c7fb64dbSThomas Graf {
23113b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
2312c7fb64dbSThomas Graf 	struct neigh_table *tbl;
23136b3f8674SThomas Graf 	struct ndtmsg *ndtmsg;
23146b3f8674SThomas Graf 	struct nlattr *tb[NDTA_MAX+1];
2315d7480fd3SWANG Cong 	bool found = false;
2316d7480fd3SWANG Cong 	int err, tidx;
2317c7fb64dbSThomas Graf 
23188cb08174SJohannes Berg 	err = nlmsg_parse_deprecated(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
2319c21ef3e3SDavid Ahern 				     nl_neightbl_policy, extack);
23206b3f8674SThomas Graf 	if (err < 0)
23216b3f8674SThomas Graf 		goto errout;
2322c7fb64dbSThomas Graf 
23236b3f8674SThomas Graf 	if (tb[NDTA_NAME] == NULL) {
23246b3f8674SThomas Graf 		err = -EINVAL;
23256b3f8674SThomas Graf 		goto errout;
23266b3f8674SThomas Graf 	}
23276b3f8674SThomas Graf 
23286b3f8674SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2329d7480fd3SWANG Cong 
2330d7480fd3SWANG Cong 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2331d7480fd3SWANG Cong 		tbl = neigh_tables[tidx];
2332d7480fd3SWANG Cong 		if (!tbl)
2333d7480fd3SWANG Cong 			continue;
2334c7fb64dbSThomas Graf 		if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
2335c7fb64dbSThomas Graf 			continue;
2336d7480fd3SWANG Cong 		if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) {
2337d7480fd3SWANG Cong 			found = true;
2338c7fb64dbSThomas Graf 			break;
2339c7fb64dbSThomas Graf 		}
2340c7fb64dbSThomas Graf 	}
2341c7fb64dbSThomas Graf 
2342d7480fd3SWANG Cong 	if (!found)
2343d7480fd3SWANG Cong 		return -ENOENT;
2344d7480fd3SWANG Cong 
2345c7fb64dbSThomas Graf 	/*
2346c7fb64dbSThomas Graf 	 * We acquire tbl->lock to be nice to the periodic timers and
2347c7fb64dbSThomas Graf 	 * make sure they always see a consistent set of values.
2348c7fb64dbSThomas Graf 	 */
2349c7fb64dbSThomas Graf 	write_lock_bh(&tbl->lock);
2350c7fb64dbSThomas Graf 
23516b3f8674SThomas Graf 	if (tb[NDTA_PARMS]) {
23526b3f8674SThomas Graf 		struct nlattr *tbp[NDTPA_MAX+1];
2353c7fb64dbSThomas Graf 		struct neigh_parms *p;
23546b3f8674SThomas Graf 		int i, ifindex = 0;
2355c7fb64dbSThomas Graf 
23568cb08174SJohannes Berg 		err = nla_parse_nested_deprecated(tbp, NDTPA_MAX,
23578cb08174SJohannes Berg 						  tb[NDTA_PARMS],
2358c21ef3e3SDavid Ahern 						  nl_ntbl_parm_policy, extack);
23596b3f8674SThomas Graf 		if (err < 0)
23606b3f8674SThomas Graf 			goto errout_tbl_lock;
2361c7fb64dbSThomas Graf 
23626b3f8674SThomas Graf 		if (tbp[NDTPA_IFINDEX])
23636b3f8674SThomas Graf 			ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
2364c7fb64dbSThomas Graf 
236597fd5bc7STobias Klauser 		p = lookup_neigh_parms(tbl, net, ifindex);
2366c7fb64dbSThomas Graf 		if (p == NULL) {
2367c7fb64dbSThomas Graf 			err = -ENOENT;
23686b3f8674SThomas Graf 			goto errout_tbl_lock;
2369c7fb64dbSThomas Graf 		}
2370c7fb64dbSThomas Graf 
23716b3f8674SThomas Graf 		for (i = 1; i <= NDTPA_MAX; i++) {
23726b3f8674SThomas Graf 			if (tbp[i] == NULL)
23736b3f8674SThomas Graf 				continue;
2374c7fb64dbSThomas Graf 
23756b3f8674SThomas Graf 			switch (i) {
23766b3f8674SThomas Graf 			case NDTPA_QUEUE_LEN:
23771f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
23781f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]) *
23791f9248e5SJiri Pirko 					      SKB_TRUESIZE(ETH_FRAME_LEN));
23808b5c171bSEric Dumazet 				break;
23818b5c171bSEric Dumazet 			case NDTPA_QUEUE_LENBYTES:
23821f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
23831f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23846b3f8674SThomas Graf 				break;
23856b3f8674SThomas Graf 			case NDTPA_PROXY_QLEN:
23861f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, PROXY_QLEN,
23871f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23886b3f8674SThomas Graf 				break;
23896b3f8674SThomas Graf 			case NDTPA_APP_PROBES:
23901f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, APP_PROBES,
23911f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23926b3f8674SThomas Graf 				break;
23936b3f8674SThomas Graf 			case NDTPA_UCAST_PROBES:
23941f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, UCAST_PROBES,
23951f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23966b3f8674SThomas Graf 				break;
23976b3f8674SThomas Graf 			case NDTPA_MCAST_PROBES:
23981f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, MCAST_PROBES,
23991f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
24006b3f8674SThomas Graf 				break;
24018da86466SYOSHIFUJI Hideaki/吉藤英明 			case NDTPA_MCAST_REPROBES:
24028da86466SYOSHIFUJI Hideaki/吉藤英明 				NEIGH_VAR_SET(p, MCAST_REPROBES,
24038da86466SYOSHIFUJI Hideaki/吉藤英明 					      nla_get_u32(tbp[i]));
24048da86466SYOSHIFUJI Hideaki/吉藤英明 				break;
24056b3f8674SThomas Graf 			case NDTPA_BASE_REACHABLE_TIME:
24061f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,
24071f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
24084bf6980dSJean-Francois Remy 				/* update reachable_time as well, otherwise, the change will
24094bf6980dSJean-Francois Remy 				 * only be effective after the next time neigh_periodic_work
24104bf6980dSJean-Francois Remy 				 * decides to recompute it (can be multiple minutes)
24114bf6980dSJean-Francois Remy 				 */
24124bf6980dSJean-Francois Remy 				p->reachable_time =
24134bf6980dSJean-Francois Remy 					neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
24146b3f8674SThomas Graf 				break;
24156b3f8674SThomas Graf 			case NDTPA_GC_STALETIME:
24161f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, GC_STALETIME,
24171f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
24186b3f8674SThomas Graf 				break;
24196b3f8674SThomas Graf 			case NDTPA_DELAY_PROBE_TIME:
24201f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, DELAY_PROBE_TIME,
24211f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
24222a4501aeSIdo Schimmel 				call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
24236b3f8674SThomas Graf 				break;
2424211da42eSYuwei Wang 			case NDTPA_INTERVAL_PROBE_TIME_MS:
2425211da42eSYuwei Wang 				NEIGH_VAR_SET(p, INTERVAL_PROBE_TIME_MS,
2426211da42eSYuwei Wang 					      nla_get_msecs(tbp[i]));
2427211da42eSYuwei Wang 				break;
24286b3f8674SThomas Graf 			case NDTPA_RETRANS_TIME:
24291f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, RETRANS_TIME,
24301f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
24316b3f8674SThomas Graf 				break;
24326b3f8674SThomas Graf 			case NDTPA_ANYCAST_DELAY:
24333977458cSJiri Pirko 				NEIGH_VAR_SET(p, ANYCAST_DELAY,
24343977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
24356b3f8674SThomas Graf 				break;
24366b3f8674SThomas Graf 			case NDTPA_PROXY_DELAY:
24373977458cSJiri Pirko 				NEIGH_VAR_SET(p, PROXY_DELAY,
24383977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
24396b3f8674SThomas Graf 				break;
24406b3f8674SThomas Graf 			case NDTPA_LOCKTIME:
24413977458cSJiri Pirko 				NEIGH_VAR_SET(p, LOCKTIME,
24423977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
24436b3f8674SThomas Graf 				break;
2444c7fb64dbSThomas Graf 			}
24456b3f8674SThomas Graf 		}
24466b3f8674SThomas Graf 	}
24476b3f8674SThomas Graf 
2448dc25c676SGao feng 	err = -ENOENT;
2449dc25c676SGao feng 	if ((tb[NDTA_THRESH1] || tb[NDTA_THRESH2] ||
2450dc25c676SGao feng 	     tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]) &&
2451dc25c676SGao feng 	    !net_eq(net, &init_net))
2452dc25c676SGao feng 		goto errout_tbl_lock;
2453dc25c676SGao feng 
24546b3f8674SThomas Graf 	if (tb[NDTA_THRESH1])
24556b3f8674SThomas Graf 		tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
24566b3f8674SThomas Graf 
24576b3f8674SThomas Graf 	if (tb[NDTA_THRESH2])
24586b3f8674SThomas Graf 		tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
24596b3f8674SThomas Graf 
24606b3f8674SThomas Graf 	if (tb[NDTA_THRESH3])
24616b3f8674SThomas Graf 		tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
24626b3f8674SThomas Graf 
24636b3f8674SThomas Graf 	if (tb[NDTA_GC_INTERVAL])
24646b3f8674SThomas Graf 		tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2465c7fb64dbSThomas Graf 
2466c7fb64dbSThomas Graf 	err = 0;
2467c7fb64dbSThomas Graf 
24686b3f8674SThomas Graf errout_tbl_lock:
2469c7fb64dbSThomas Graf 	write_unlock_bh(&tbl->lock);
24706b3f8674SThomas Graf errout:
2471c7fb64dbSThomas Graf 	return err;
2472c7fb64dbSThomas Graf }
2473c7fb64dbSThomas Graf 
24749632d47fSDavid Ahern static int neightbl_valid_dump_info(const struct nlmsghdr *nlh,
24759632d47fSDavid Ahern 				    struct netlink_ext_ack *extack)
24769632d47fSDavid Ahern {
24779632d47fSDavid Ahern 	struct ndtmsg *ndtm;
24789632d47fSDavid Ahern 
24799632d47fSDavid Ahern 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndtm))) {
24809632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid header for neighbor table dump request");
24819632d47fSDavid Ahern 		return -EINVAL;
24829632d47fSDavid Ahern 	}
24839632d47fSDavid Ahern 
24849632d47fSDavid Ahern 	ndtm = nlmsg_data(nlh);
24859632d47fSDavid Ahern 	if (ndtm->ndtm_pad1  || ndtm->ndtm_pad2) {
24869632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor table dump request");
24879632d47fSDavid Ahern 		return -EINVAL;
24889632d47fSDavid Ahern 	}
24899632d47fSDavid Ahern 
24909632d47fSDavid Ahern 	if (nlmsg_attrlen(nlh, sizeof(*ndtm))) {
24919632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid data after header in neighbor table dump request");
24929632d47fSDavid Ahern 		return -EINVAL;
24939632d47fSDavid Ahern 	}
24949632d47fSDavid Ahern 
24959632d47fSDavid Ahern 	return 0;
24969632d47fSDavid Ahern }
24979632d47fSDavid Ahern 
2498c8822a4eSThomas Graf static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
2499c7fb64dbSThomas Graf {
25009632d47fSDavid Ahern 	const struct nlmsghdr *nlh = cb->nlh;
25013b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
2502ca860fb3SThomas Graf 	int family, tidx, nidx = 0;
2503ca860fb3SThomas Graf 	int tbl_skip = cb->args[0];
2504ca860fb3SThomas Graf 	int neigh_skip = cb->args[1];
2505c7fb64dbSThomas Graf 	struct neigh_table *tbl;
2506c7fb64dbSThomas Graf 
25079632d47fSDavid Ahern 	if (cb->strict_check) {
25089632d47fSDavid Ahern 		int err = neightbl_valid_dump_info(nlh, cb->extack);
25099632d47fSDavid Ahern 
25109632d47fSDavid Ahern 		if (err < 0)
25119632d47fSDavid Ahern 			return err;
25129632d47fSDavid Ahern 	}
25139632d47fSDavid Ahern 
25149632d47fSDavid Ahern 	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
2515c7fb64dbSThomas Graf 
2516d7480fd3SWANG Cong 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2517c7fb64dbSThomas Graf 		struct neigh_parms *p;
2518c7fb64dbSThomas Graf 
2519d7480fd3SWANG Cong 		tbl = neigh_tables[tidx];
2520d7480fd3SWANG Cong 		if (!tbl)
2521d7480fd3SWANG Cong 			continue;
2522d7480fd3SWANG Cong 
2523ca860fb3SThomas Graf 		if (tidx < tbl_skip || (family && tbl->family != family))
2524c7fb64dbSThomas Graf 			continue;
2525c7fb64dbSThomas Graf 
252615e47304SEric W. Biederman 		if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
25279632d47fSDavid Ahern 				       nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
25287b46a644SDavid S. Miller 				       NLM_F_MULTI) < 0)
2529c7fb64dbSThomas Graf 			break;
2530c7fb64dbSThomas Graf 
253175fbfd33SNicolas Dichtel 		nidx = 0;
253275fbfd33SNicolas Dichtel 		p = list_next_entry(&tbl->parms, list);
253375fbfd33SNicolas Dichtel 		list_for_each_entry_from(p, &tbl->parms_list, list) {
2534878628fbSYOSHIFUJI Hideaki 			if (!net_eq(neigh_parms_net(p), net))
2535426b5303SEric W. Biederman 				continue;
2536426b5303SEric W. Biederman 
2537efc683fcSGautam Kachroo 			if (nidx < neigh_skip)
2538efc683fcSGautam Kachroo 				goto next;
2539c7fb64dbSThomas Graf 
2540ca860fb3SThomas Graf 			if (neightbl_fill_param_info(skb, tbl, p,
254115e47304SEric W. Biederman 						     NETLINK_CB(cb->skb).portid,
25429632d47fSDavid Ahern 						     nlh->nlmsg_seq,
2543ca860fb3SThomas Graf 						     RTM_NEWNEIGHTBL,
25447b46a644SDavid S. Miller 						     NLM_F_MULTI) < 0)
2545c7fb64dbSThomas Graf 				goto out;
2546efc683fcSGautam Kachroo 		next:
2547efc683fcSGautam Kachroo 			nidx++;
2548c7fb64dbSThomas Graf 		}
2549c7fb64dbSThomas Graf 
2550ca860fb3SThomas Graf 		neigh_skip = 0;
2551c7fb64dbSThomas Graf 	}
2552c7fb64dbSThomas Graf out:
2553ca860fb3SThomas Graf 	cb->args[0] = tidx;
2554ca860fb3SThomas Graf 	cb->args[1] = nidx;
2555c7fb64dbSThomas Graf 
2556c7fb64dbSThomas Graf 	return skb->len;
2557c7fb64dbSThomas Graf }
25581da177e4SLinus Torvalds 
25598b8aec50SThomas Graf static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
25608b8aec50SThomas Graf 			   u32 pid, u32 seq, int type, unsigned int flags)
25611da177e4SLinus Torvalds {
25622c611ad9SRoopa Prabhu 	u32 neigh_flags, neigh_flags_ext;
25631da177e4SLinus Torvalds 	unsigned long now = jiffies;
25641da177e4SLinus Torvalds 	struct nda_cacheinfo ci;
25658b8aec50SThomas Graf 	struct nlmsghdr *nlh;
25668b8aec50SThomas Graf 	struct ndmsg *ndm;
25671da177e4SLinus Torvalds 
25688b8aec50SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
25698b8aec50SThomas Graf 	if (nlh == NULL)
257026932566SPatrick McHardy 		return -EMSGSIZE;
25718b8aec50SThomas Graf 
25722c611ad9SRoopa Prabhu 	neigh_flags_ext = neigh->flags >> NTF_EXT_SHIFT;
25732c611ad9SRoopa Prabhu 	neigh_flags     = neigh->flags & NTF_OLD_MASK;
25742c611ad9SRoopa Prabhu 
25758b8aec50SThomas Graf 	ndm = nlmsg_data(nlh);
25768b8aec50SThomas Graf 	ndm->ndm_family	 = neigh->ops->family;
25779ef1d4c7SPatrick McHardy 	ndm->ndm_pad1    = 0;
25789ef1d4c7SPatrick McHardy 	ndm->ndm_pad2    = 0;
25792c611ad9SRoopa Prabhu 	ndm->ndm_flags	 = neigh_flags;
25808b8aec50SThomas Graf 	ndm->ndm_type	 = neigh->type;
25818b8aec50SThomas Graf 	ndm->ndm_ifindex = neigh->dev->ifindex;
25821da177e4SLinus Torvalds 
25839a6308d7SDavid S. Miller 	if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
25849a6308d7SDavid S. Miller 		goto nla_put_failure;
25858b8aec50SThomas Graf 
25868b8aec50SThomas Graf 	read_lock_bh(&neigh->lock);
25878b8aec50SThomas Graf 	ndm->ndm_state	 = neigh->nud_state;
25880ed8ddf4SEric Dumazet 	if (neigh->nud_state & NUD_VALID) {
25890ed8ddf4SEric Dumazet 		char haddr[MAX_ADDR_LEN];
25900ed8ddf4SEric Dumazet 
25910ed8ddf4SEric Dumazet 		neigh_ha_snapshot(haddr, neigh, neigh->dev);
25920ed8ddf4SEric Dumazet 		if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
25938b8aec50SThomas Graf 			read_unlock_bh(&neigh->lock);
25948b8aec50SThomas Graf 			goto nla_put_failure;
25958b8aec50SThomas Graf 		}
25960ed8ddf4SEric Dumazet 	}
25978b8aec50SThomas Graf 
2598b9f5f52cSStephen Hemminger 	ci.ndm_used	 = jiffies_to_clock_t(now - neigh->used);
2599b9f5f52cSStephen Hemminger 	ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2600b9f5f52cSStephen Hemminger 	ci.ndm_updated	 = jiffies_to_clock_t(now - neigh->updated);
26019f237430SReshetova, Elena 	ci.ndm_refcnt	 = refcount_read(&neigh->refcnt) - 1;
26028b8aec50SThomas Graf 	read_unlock_bh(&neigh->lock);
26038b8aec50SThomas Graf 
26049a6308d7SDavid S. Miller 	if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
26059a6308d7SDavid S. Miller 	    nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
26069a6308d7SDavid S. Miller 		goto nla_put_failure;
26078b8aec50SThomas Graf 
2608df9b0e30SDavid Ahern 	if (neigh->protocol && nla_put_u8(skb, NDA_PROTOCOL, neigh->protocol))
2609df9b0e30SDavid Ahern 		goto nla_put_failure;
26102c611ad9SRoopa Prabhu 	if (neigh_flags_ext && nla_put_u32(skb, NDA_FLAGS_EXT, neigh_flags_ext))
26112c611ad9SRoopa Prabhu 		goto nla_put_failure;
2612df9b0e30SDavid Ahern 
2613053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2614053c095aSJohannes Berg 	return 0;
26158b8aec50SThomas Graf 
26168b8aec50SThomas Graf nla_put_failure:
261726932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
261826932566SPatrick McHardy 	return -EMSGSIZE;
26191da177e4SLinus Torvalds }
26201da177e4SLinus Torvalds 
262184920c14STony Zelenoff static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
262284920c14STony Zelenoff 			    u32 pid, u32 seq, int type, unsigned int flags,
262384920c14STony Zelenoff 			    struct neigh_table *tbl)
262484920c14STony Zelenoff {
26252c611ad9SRoopa Prabhu 	u32 neigh_flags, neigh_flags_ext;
262684920c14STony Zelenoff 	struct nlmsghdr *nlh;
262784920c14STony Zelenoff 	struct ndmsg *ndm;
262884920c14STony Zelenoff 
262984920c14STony Zelenoff 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
263084920c14STony Zelenoff 	if (nlh == NULL)
263184920c14STony Zelenoff 		return -EMSGSIZE;
263284920c14STony Zelenoff 
26332c611ad9SRoopa Prabhu 	neigh_flags_ext = pn->flags >> NTF_EXT_SHIFT;
26342c611ad9SRoopa Prabhu 	neigh_flags     = pn->flags & NTF_OLD_MASK;
26352c611ad9SRoopa Prabhu 
263684920c14STony Zelenoff 	ndm = nlmsg_data(nlh);
263784920c14STony Zelenoff 	ndm->ndm_family	 = tbl->family;
263884920c14STony Zelenoff 	ndm->ndm_pad1    = 0;
263984920c14STony Zelenoff 	ndm->ndm_pad2    = 0;
26402c611ad9SRoopa Prabhu 	ndm->ndm_flags	 = neigh_flags | NTF_PROXY;
2641545469f7SJun Zhao 	ndm->ndm_type	 = RTN_UNICAST;
26426adc5fd6SKonstantin Khlebnikov 	ndm->ndm_ifindex = pn->dev ? pn->dev->ifindex : 0;
264384920c14STony Zelenoff 	ndm->ndm_state	 = NUD_NONE;
264484920c14STony Zelenoff 
26459a6308d7SDavid S. Miller 	if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
26469a6308d7SDavid S. Miller 		goto nla_put_failure;
264784920c14STony Zelenoff 
2648df9b0e30SDavid Ahern 	if (pn->protocol && nla_put_u8(skb, NDA_PROTOCOL, pn->protocol))
2649df9b0e30SDavid Ahern 		goto nla_put_failure;
26502c611ad9SRoopa Prabhu 	if (neigh_flags_ext && nla_put_u32(skb, NDA_FLAGS_EXT, neigh_flags_ext))
26512c611ad9SRoopa Prabhu 		goto nla_put_failure;
2652df9b0e30SDavid Ahern 
2653053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2654053c095aSJohannes Berg 	return 0;
265584920c14STony Zelenoff 
265684920c14STony Zelenoff nla_put_failure:
265784920c14STony Zelenoff 	nlmsg_cancel(skb, nlh);
265884920c14STony Zelenoff 	return -EMSGSIZE;
265984920c14STony Zelenoff }
266084920c14STony Zelenoff 
26617b8f7a40SRoopa Prabhu static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid)
2662d961db35SThomas Graf {
2663d961db35SThomas Graf 	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
26647b8f7a40SRoopa Prabhu 	__neigh_notify(neigh, RTM_NEWNEIGH, 0, nlmsg_pid);
2665d961db35SThomas Graf }
26661da177e4SLinus Torvalds 
266721fdd092SDavid Ahern static bool neigh_master_filtered(struct net_device *dev, int master_idx)
266821fdd092SDavid Ahern {
266921fdd092SDavid Ahern 	struct net_device *master;
267021fdd092SDavid Ahern 
267121fdd092SDavid Ahern 	if (!master_idx)
267221fdd092SDavid Ahern 		return false;
267321fdd092SDavid Ahern 
2674aab456dfSEric Dumazet 	master = dev ? netdev_master_upper_dev_get(dev) : NULL;
2675d3432bf1SLahav Schlesinger 
2676d3432bf1SLahav Schlesinger 	/* 0 is already used to denote NDA_MASTER wasn't passed, therefore need another
2677d3432bf1SLahav Schlesinger 	 * invalid value for ifindex to denote "no master".
2678d3432bf1SLahav Schlesinger 	 */
2679d3432bf1SLahav Schlesinger 	if (master_idx == -1)
2680d3432bf1SLahav Schlesinger 		return !!master;
2681d3432bf1SLahav Schlesinger 
268221fdd092SDavid Ahern 	if (!master || master->ifindex != master_idx)
268321fdd092SDavid Ahern 		return true;
268421fdd092SDavid Ahern 
268521fdd092SDavid Ahern 	return false;
268621fdd092SDavid Ahern }
268721fdd092SDavid Ahern 
268816660f0bSDavid Ahern static bool neigh_ifindex_filtered(struct net_device *dev, int filter_idx)
268916660f0bSDavid Ahern {
2690aab456dfSEric Dumazet 	if (filter_idx && (!dev || dev->ifindex != filter_idx))
269116660f0bSDavid Ahern 		return true;
269216660f0bSDavid Ahern 
269316660f0bSDavid Ahern 	return false;
269416660f0bSDavid Ahern }
269516660f0bSDavid Ahern 
26966f52f80eSDavid Ahern struct neigh_dump_filter {
26976f52f80eSDavid Ahern 	int master_idx;
26986f52f80eSDavid Ahern 	int dev_idx;
26996f52f80eSDavid Ahern };
27006f52f80eSDavid Ahern 
27011da177e4SLinus Torvalds static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
27026f52f80eSDavid Ahern 			    struct netlink_callback *cb,
27036f52f80eSDavid Ahern 			    struct neigh_dump_filter *filter)
27041da177e4SLinus Torvalds {
27053b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
27061da177e4SLinus Torvalds 	struct neighbour *n;
27071da177e4SLinus Torvalds 	int rc, h, s_h = cb->args[1];
27081da177e4SLinus Torvalds 	int idx, s_idx = idx = cb->args[2];
2709d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
271021fdd092SDavid Ahern 	unsigned int flags = NLM_F_MULTI;
271121fdd092SDavid Ahern 
27126f52f80eSDavid Ahern 	if (filter->dev_idx || filter->master_idx)
271321fdd092SDavid Ahern 		flags |= NLM_F_DUMP_FILTERED;
27141da177e4SLinus Torvalds 
2715d6bf7817SEric Dumazet 	rcu_read_lock_bh();
2716d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
2717d6bf7817SEric Dumazet 
27184bd6683bSEric Dumazet 	for (h = s_h; h < (1 << nht->hash_shift); h++) {
27191da177e4SLinus Torvalds 		if (h > s_h)
27201da177e4SLinus Torvalds 			s_idx = 0;
2721767e97e1SEric Dumazet 		for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2722767e97e1SEric Dumazet 		     n != NULL;
2723767e97e1SEric Dumazet 		     n = rcu_dereference_bh(n->next)) {
272418502acdSZhang Shengju 			if (idx < s_idx || !net_eq(dev_net(n->dev), net))
272518502acdSZhang Shengju 				goto next;
27266f52f80eSDavid Ahern 			if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
27276f52f80eSDavid Ahern 			    neigh_master_filtered(n->dev, filter->master_idx))
2728efc683fcSGautam Kachroo 				goto next;
272915e47304SEric W. Biederman 			if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
27301da177e4SLinus Torvalds 					    cb->nlh->nlmsg_seq,
2731b6544c0bSJamal Hadi Salim 					    RTM_NEWNEIGH,
273221fdd092SDavid Ahern 					    flags) < 0) {
27331da177e4SLinus Torvalds 				rc = -1;
27341da177e4SLinus Torvalds 				goto out;
27351da177e4SLinus Torvalds 			}
2736efc683fcSGautam Kachroo next:
2737efc683fcSGautam Kachroo 			idx++;
27381da177e4SLinus Torvalds 		}
27391da177e4SLinus Torvalds 	}
27401da177e4SLinus Torvalds 	rc = skb->len;
27411da177e4SLinus Torvalds out:
2742d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
27431da177e4SLinus Torvalds 	cb->args[1] = h;
27441da177e4SLinus Torvalds 	cb->args[2] = idx;
27451da177e4SLinus Torvalds 	return rc;
27461da177e4SLinus Torvalds }
27471da177e4SLinus Torvalds 
274884920c14STony Zelenoff static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
27496f52f80eSDavid Ahern 			     struct netlink_callback *cb,
27506f52f80eSDavid Ahern 			     struct neigh_dump_filter *filter)
275184920c14STony Zelenoff {
275284920c14STony Zelenoff 	struct pneigh_entry *n;
275384920c14STony Zelenoff 	struct net *net = sock_net(skb->sk);
275484920c14STony Zelenoff 	int rc, h, s_h = cb->args[3];
275584920c14STony Zelenoff 	int idx, s_idx = idx = cb->args[4];
27566f52f80eSDavid Ahern 	unsigned int flags = NLM_F_MULTI;
27576f52f80eSDavid Ahern 
27586f52f80eSDavid Ahern 	if (filter->dev_idx || filter->master_idx)
27596f52f80eSDavid Ahern 		flags |= NLM_F_DUMP_FILTERED;
276084920c14STony Zelenoff 
276184920c14STony Zelenoff 	read_lock_bh(&tbl->lock);
276284920c14STony Zelenoff 
27634bd6683bSEric Dumazet 	for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
276484920c14STony Zelenoff 		if (h > s_h)
276584920c14STony Zelenoff 			s_idx = 0;
276684920c14STony Zelenoff 		for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
276718502acdSZhang Shengju 			if (idx < s_idx || pneigh_net(n) != net)
276884920c14STony Zelenoff 				goto next;
27696f52f80eSDavid Ahern 			if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
27706f52f80eSDavid Ahern 			    neigh_master_filtered(n->dev, filter->master_idx))
27716f52f80eSDavid Ahern 				goto next;
277215e47304SEric W. Biederman 			if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
277384920c14STony Zelenoff 					    cb->nlh->nlmsg_seq,
27746f52f80eSDavid Ahern 					    RTM_NEWNEIGH, flags, tbl) < 0) {
277584920c14STony Zelenoff 				read_unlock_bh(&tbl->lock);
277684920c14STony Zelenoff 				rc = -1;
277784920c14STony Zelenoff 				goto out;
277884920c14STony Zelenoff 			}
277984920c14STony Zelenoff 		next:
278084920c14STony Zelenoff 			idx++;
278184920c14STony Zelenoff 		}
278284920c14STony Zelenoff 	}
278384920c14STony Zelenoff 
278484920c14STony Zelenoff 	read_unlock_bh(&tbl->lock);
278584920c14STony Zelenoff 	rc = skb->len;
278684920c14STony Zelenoff out:
278784920c14STony Zelenoff 	cb->args[3] = h;
278884920c14STony Zelenoff 	cb->args[4] = idx;
278984920c14STony Zelenoff 	return rc;
279084920c14STony Zelenoff 
279184920c14STony Zelenoff }
279284920c14STony Zelenoff 
279351183d23SDavid Ahern static int neigh_valid_dump_req(const struct nlmsghdr *nlh,
279451183d23SDavid Ahern 				bool strict_check,
279551183d23SDavid Ahern 				struct neigh_dump_filter *filter,
279651183d23SDavid Ahern 				struct netlink_ext_ack *extack)
279751183d23SDavid Ahern {
279851183d23SDavid Ahern 	struct nlattr *tb[NDA_MAX + 1];
279951183d23SDavid Ahern 	int err, i;
280051183d23SDavid Ahern 
280151183d23SDavid Ahern 	if (strict_check) {
280251183d23SDavid Ahern 		struct ndmsg *ndm;
280351183d23SDavid Ahern 
280451183d23SDavid Ahern 		if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
280551183d23SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid header for neighbor dump request");
280651183d23SDavid Ahern 			return -EINVAL;
280751183d23SDavid Ahern 		}
280851183d23SDavid Ahern 
280951183d23SDavid Ahern 		ndm = nlmsg_data(nlh);
281051183d23SDavid Ahern 		if (ndm->ndm_pad1  || ndm->ndm_pad2  || ndm->ndm_ifindex ||
2811c0fde870SDavid Ahern 		    ndm->ndm_state || ndm->ndm_type) {
281251183d23SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor dump request");
281351183d23SDavid Ahern 			return -EINVAL;
281451183d23SDavid Ahern 		}
281551183d23SDavid Ahern 
2816c0fde870SDavid Ahern 		if (ndm->ndm_flags & ~NTF_PROXY) {
2817c0fde870SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor dump request");
2818c0fde870SDavid Ahern 			return -EINVAL;
2819c0fde870SDavid Ahern 		}
2820c0fde870SDavid Ahern 
28218cb08174SJohannes Berg 		err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg),
28228cb08174SJohannes Berg 						    tb, NDA_MAX, nda_policy,
28238cb08174SJohannes Berg 						    extack);
282451183d23SDavid Ahern 	} else {
28258cb08174SJohannes Berg 		err = nlmsg_parse_deprecated(nlh, sizeof(struct ndmsg), tb,
28268cb08174SJohannes Berg 					     NDA_MAX, nda_policy, extack);
282751183d23SDavid Ahern 	}
282851183d23SDavid Ahern 	if (err < 0)
282951183d23SDavid Ahern 		return err;
283051183d23SDavid Ahern 
283151183d23SDavid Ahern 	for (i = 0; i <= NDA_MAX; ++i) {
283251183d23SDavid Ahern 		if (!tb[i])
283351183d23SDavid Ahern 			continue;
283451183d23SDavid Ahern 
283551183d23SDavid Ahern 		/* all new attributes should require strict_check */
283651183d23SDavid Ahern 		switch (i) {
283751183d23SDavid Ahern 		case NDA_IFINDEX:
283851183d23SDavid Ahern 			filter->dev_idx = nla_get_u32(tb[i]);
283951183d23SDavid Ahern 			break;
284051183d23SDavid Ahern 		case NDA_MASTER:
284151183d23SDavid Ahern 			filter->master_idx = nla_get_u32(tb[i]);
284251183d23SDavid Ahern 			break;
284351183d23SDavid Ahern 		default:
284451183d23SDavid Ahern 			if (strict_check) {
284551183d23SDavid Ahern 				NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor dump request");
284651183d23SDavid Ahern 				return -EINVAL;
284751183d23SDavid Ahern 			}
284851183d23SDavid Ahern 		}
284951183d23SDavid Ahern 	}
285051183d23SDavid Ahern 
285151183d23SDavid Ahern 	return 0;
285251183d23SDavid Ahern }
285351183d23SDavid Ahern 
2854c8822a4eSThomas Graf static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
28551da177e4SLinus Torvalds {
28566f52f80eSDavid Ahern 	const struct nlmsghdr *nlh = cb->nlh;
28576f52f80eSDavid Ahern 	struct neigh_dump_filter filter = {};
28581da177e4SLinus Torvalds 	struct neigh_table *tbl;
28591da177e4SLinus Torvalds 	int t, family, s_t;
286084920c14STony Zelenoff 	int proxy = 0;
28614bd6683bSEric Dumazet 	int err;
28621da177e4SLinus Torvalds 
28636f52f80eSDavid Ahern 	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
286484920c14STony Zelenoff 
286584920c14STony Zelenoff 	/* check for full ndmsg structure presence, family member is
286684920c14STony Zelenoff 	 * the same for both structures
286784920c14STony Zelenoff 	 */
28686f52f80eSDavid Ahern 	if (nlmsg_len(nlh) >= sizeof(struct ndmsg) &&
28696f52f80eSDavid Ahern 	    ((struct ndmsg *)nlmsg_data(nlh))->ndm_flags == NTF_PROXY)
287084920c14STony Zelenoff 		proxy = 1;
287184920c14STony Zelenoff 
287251183d23SDavid Ahern 	err = neigh_valid_dump_req(nlh, cb->strict_check, &filter, cb->extack);
287351183d23SDavid Ahern 	if (err < 0 && cb->strict_check)
287451183d23SDavid Ahern 		return err;
287551183d23SDavid Ahern 
28761da177e4SLinus Torvalds 	s_t = cb->args[0];
28771da177e4SLinus Torvalds 
2878d7480fd3SWANG Cong 	for (t = 0; t < NEIGH_NR_TABLES; t++) {
2879d7480fd3SWANG Cong 		tbl = neigh_tables[t];
2880d7480fd3SWANG Cong 
2881d7480fd3SWANG Cong 		if (!tbl)
2882d7480fd3SWANG Cong 			continue;
28831da177e4SLinus Torvalds 		if (t < s_t || (family && tbl->family != family))
28841da177e4SLinus Torvalds 			continue;
28851da177e4SLinus Torvalds 		if (t > s_t)
28861da177e4SLinus Torvalds 			memset(&cb->args[1], 0, sizeof(cb->args) -
28871da177e4SLinus Torvalds 						sizeof(cb->args[0]));
288884920c14STony Zelenoff 		if (proxy)
28896f52f80eSDavid Ahern 			err = pneigh_dump_table(tbl, skb, cb, &filter);
289084920c14STony Zelenoff 		else
28916f52f80eSDavid Ahern 			err = neigh_dump_table(tbl, skb, cb, &filter);
28924bd6683bSEric Dumazet 		if (err < 0)
28934bd6683bSEric Dumazet 			break;
28941da177e4SLinus Torvalds 	}
28951da177e4SLinus Torvalds 
28961da177e4SLinus Torvalds 	cb->args[0] = t;
28971da177e4SLinus Torvalds 	return skb->len;
28981da177e4SLinus Torvalds }
28991da177e4SLinus Torvalds 
290082cbb5c6SRoopa Prabhu static int neigh_valid_get_req(const struct nlmsghdr *nlh,
290182cbb5c6SRoopa Prabhu 			       struct neigh_table **tbl,
290282cbb5c6SRoopa Prabhu 			       void **dst, int *dev_idx, u8 *ndm_flags,
290382cbb5c6SRoopa Prabhu 			       struct netlink_ext_ack *extack)
290482cbb5c6SRoopa Prabhu {
290582cbb5c6SRoopa Prabhu 	struct nlattr *tb[NDA_MAX + 1];
290682cbb5c6SRoopa Prabhu 	struct ndmsg *ndm;
290782cbb5c6SRoopa Prabhu 	int err, i;
290882cbb5c6SRoopa Prabhu 
290982cbb5c6SRoopa Prabhu 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
291082cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid header for neighbor get request");
291182cbb5c6SRoopa Prabhu 		return -EINVAL;
291282cbb5c6SRoopa Prabhu 	}
291382cbb5c6SRoopa Prabhu 
291482cbb5c6SRoopa Prabhu 	ndm = nlmsg_data(nlh);
291582cbb5c6SRoopa Prabhu 	if (ndm->ndm_pad1  || ndm->ndm_pad2  || ndm->ndm_state ||
291682cbb5c6SRoopa Prabhu 	    ndm->ndm_type) {
291782cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor get request");
291882cbb5c6SRoopa Prabhu 		return -EINVAL;
291982cbb5c6SRoopa Prabhu 	}
292082cbb5c6SRoopa Prabhu 
292182cbb5c6SRoopa Prabhu 	if (ndm->ndm_flags & ~NTF_PROXY) {
292282cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor get request");
292382cbb5c6SRoopa Prabhu 		return -EINVAL;
292482cbb5c6SRoopa Prabhu 	}
292582cbb5c6SRoopa Prabhu 
29268cb08174SJohannes Berg 	err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb,
29278cb08174SJohannes Berg 					    NDA_MAX, nda_policy, extack);
292882cbb5c6SRoopa Prabhu 	if (err < 0)
292982cbb5c6SRoopa Prabhu 		return err;
293082cbb5c6SRoopa Prabhu 
293182cbb5c6SRoopa Prabhu 	*ndm_flags = ndm->ndm_flags;
293282cbb5c6SRoopa Prabhu 	*dev_idx = ndm->ndm_ifindex;
293382cbb5c6SRoopa Prabhu 	*tbl = neigh_find_table(ndm->ndm_family);
293482cbb5c6SRoopa Prabhu 	if (*tbl == NULL) {
293582cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
293682cbb5c6SRoopa Prabhu 		return -EAFNOSUPPORT;
293782cbb5c6SRoopa Prabhu 	}
293882cbb5c6SRoopa Prabhu 
293982cbb5c6SRoopa Prabhu 	for (i = 0; i <= NDA_MAX; ++i) {
294082cbb5c6SRoopa Prabhu 		if (!tb[i])
294182cbb5c6SRoopa Prabhu 			continue;
294282cbb5c6SRoopa Prabhu 
294382cbb5c6SRoopa Prabhu 		switch (i) {
294482cbb5c6SRoopa Prabhu 		case NDA_DST:
294582cbb5c6SRoopa Prabhu 			if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
294682cbb5c6SRoopa Prabhu 				NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
294782cbb5c6SRoopa Prabhu 				return -EINVAL;
294882cbb5c6SRoopa Prabhu 			}
294982cbb5c6SRoopa Prabhu 			*dst = nla_data(tb[i]);
295082cbb5c6SRoopa Prabhu 			break;
295182cbb5c6SRoopa Prabhu 		default:
295282cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request");
295382cbb5c6SRoopa Prabhu 			return -EINVAL;
295482cbb5c6SRoopa Prabhu 		}
295582cbb5c6SRoopa Prabhu 	}
295682cbb5c6SRoopa Prabhu 
295782cbb5c6SRoopa Prabhu 	return 0;
295882cbb5c6SRoopa Prabhu }
295982cbb5c6SRoopa Prabhu 
296082cbb5c6SRoopa Prabhu static inline size_t neigh_nlmsg_size(void)
296182cbb5c6SRoopa Prabhu {
296282cbb5c6SRoopa Prabhu 	return NLMSG_ALIGN(sizeof(struct ndmsg))
296382cbb5c6SRoopa Prabhu 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
296482cbb5c6SRoopa Prabhu 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
296582cbb5c6SRoopa Prabhu 	       + nla_total_size(sizeof(struct nda_cacheinfo))
296682cbb5c6SRoopa Prabhu 	       + nla_total_size(4)  /* NDA_PROBES */
29672c611ad9SRoopa Prabhu 	       + nla_total_size(4)  /* NDA_FLAGS_EXT */
296882cbb5c6SRoopa Prabhu 	       + nla_total_size(1); /* NDA_PROTOCOL */
296982cbb5c6SRoopa Prabhu }
297082cbb5c6SRoopa Prabhu 
297182cbb5c6SRoopa Prabhu static int neigh_get_reply(struct net *net, struct neighbour *neigh,
297282cbb5c6SRoopa Prabhu 			   u32 pid, u32 seq)
297382cbb5c6SRoopa Prabhu {
297482cbb5c6SRoopa Prabhu 	struct sk_buff *skb;
297582cbb5c6SRoopa Prabhu 	int err = 0;
297682cbb5c6SRoopa Prabhu 
297782cbb5c6SRoopa Prabhu 	skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL);
297882cbb5c6SRoopa Prabhu 	if (!skb)
297982cbb5c6SRoopa Prabhu 		return -ENOBUFS;
298082cbb5c6SRoopa Prabhu 
298182cbb5c6SRoopa Prabhu 	err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0);
298282cbb5c6SRoopa Prabhu 	if (err) {
298382cbb5c6SRoopa Prabhu 		kfree_skb(skb);
298482cbb5c6SRoopa Prabhu 		goto errout;
298582cbb5c6SRoopa Prabhu 	}
298682cbb5c6SRoopa Prabhu 
298782cbb5c6SRoopa Prabhu 	err = rtnl_unicast(skb, net, pid);
298882cbb5c6SRoopa Prabhu errout:
298982cbb5c6SRoopa Prabhu 	return err;
299082cbb5c6SRoopa Prabhu }
299182cbb5c6SRoopa Prabhu 
299282cbb5c6SRoopa Prabhu static inline size_t pneigh_nlmsg_size(void)
299382cbb5c6SRoopa Prabhu {
299482cbb5c6SRoopa Prabhu 	return NLMSG_ALIGN(sizeof(struct ndmsg))
2995463561e6SColin Ian King 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
29962c611ad9SRoopa Prabhu 	       + nla_total_size(4)  /* NDA_FLAGS_EXT */
299782cbb5c6SRoopa Prabhu 	       + nla_total_size(1); /* NDA_PROTOCOL */
299882cbb5c6SRoopa Prabhu }
299982cbb5c6SRoopa Prabhu 
300082cbb5c6SRoopa Prabhu static int pneigh_get_reply(struct net *net, struct pneigh_entry *neigh,
300182cbb5c6SRoopa Prabhu 			    u32 pid, u32 seq, struct neigh_table *tbl)
300282cbb5c6SRoopa Prabhu {
300382cbb5c6SRoopa Prabhu 	struct sk_buff *skb;
300482cbb5c6SRoopa Prabhu 	int err = 0;
300582cbb5c6SRoopa Prabhu 
300682cbb5c6SRoopa Prabhu 	skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL);
300782cbb5c6SRoopa Prabhu 	if (!skb)
300882cbb5c6SRoopa Prabhu 		return -ENOBUFS;
300982cbb5c6SRoopa Prabhu 
301082cbb5c6SRoopa Prabhu 	err = pneigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0, tbl);
301182cbb5c6SRoopa Prabhu 	if (err) {
301282cbb5c6SRoopa Prabhu 		kfree_skb(skb);
301382cbb5c6SRoopa Prabhu 		goto errout;
301482cbb5c6SRoopa Prabhu 	}
301582cbb5c6SRoopa Prabhu 
301682cbb5c6SRoopa Prabhu 	err = rtnl_unicast(skb, net, pid);
301782cbb5c6SRoopa Prabhu errout:
301882cbb5c6SRoopa Prabhu 	return err;
301982cbb5c6SRoopa Prabhu }
302082cbb5c6SRoopa Prabhu 
302182cbb5c6SRoopa Prabhu static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
302282cbb5c6SRoopa Prabhu 		     struct netlink_ext_ack *extack)
302382cbb5c6SRoopa Prabhu {
302482cbb5c6SRoopa Prabhu 	struct net *net = sock_net(in_skb->sk);
302582cbb5c6SRoopa Prabhu 	struct net_device *dev = NULL;
302682cbb5c6SRoopa Prabhu 	struct neigh_table *tbl = NULL;
302782cbb5c6SRoopa Prabhu 	struct neighbour *neigh;
302882cbb5c6SRoopa Prabhu 	void *dst = NULL;
302982cbb5c6SRoopa Prabhu 	u8 ndm_flags = 0;
303082cbb5c6SRoopa Prabhu 	int dev_idx = 0;
303182cbb5c6SRoopa Prabhu 	int err;
303282cbb5c6SRoopa Prabhu 
303382cbb5c6SRoopa Prabhu 	err = neigh_valid_get_req(nlh, &tbl, &dst, &dev_idx, &ndm_flags,
303482cbb5c6SRoopa Prabhu 				  extack);
303582cbb5c6SRoopa Prabhu 	if (err < 0)
303682cbb5c6SRoopa Prabhu 		return err;
303782cbb5c6SRoopa Prabhu 
303882cbb5c6SRoopa Prabhu 	if (dev_idx) {
303982cbb5c6SRoopa Prabhu 		dev = __dev_get_by_index(net, dev_idx);
304082cbb5c6SRoopa Prabhu 		if (!dev) {
304182cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Unknown device ifindex");
304282cbb5c6SRoopa Prabhu 			return -ENODEV;
304382cbb5c6SRoopa Prabhu 		}
304482cbb5c6SRoopa Prabhu 	}
304582cbb5c6SRoopa Prabhu 
304682cbb5c6SRoopa Prabhu 	if (!dst) {
304782cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Network address not specified");
304882cbb5c6SRoopa Prabhu 		return -EINVAL;
304982cbb5c6SRoopa Prabhu 	}
305082cbb5c6SRoopa Prabhu 
305182cbb5c6SRoopa Prabhu 	if (ndm_flags & NTF_PROXY) {
305282cbb5c6SRoopa Prabhu 		struct pneigh_entry *pn;
305382cbb5c6SRoopa Prabhu 
305482cbb5c6SRoopa Prabhu 		pn = pneigh_lookup(tbl, net, dst, dev, 0);
305582cbb5c6SRoopa Prabhu 		if (!pn) {
305682cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Proxy neighbour entry not found");
305782cbb5c6SRoopa Prabhu 			return -ENOENT;
305882cbb5c6SRoopa Prabhu 		}
305982cbb5c6SRoopa Prabhu 		return pneigh_get_reply(net, pn, NETLINK_CB(in_skb).portid,
306082cbb5c6SRoopa Prabhu 					nlh->nlmsg_seq, tbl);
306182cbb5c6SRoopa Prabhu 	}
306282cbb5c6SRoopa Prabhu 
306382cbb5c6SRoopa Prabhu 	if (!dev) {
306482cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "No device specified");
306582cbb5c6SRoopa Prabhu 		return -EINVAL;
306682cbb5c6SRoopa Prabhu 	}
306782cbb5c6SRoopa Prabhu 
306882cbb5c6SRoopa Prabhu 	neigh = neigh_lookup(tbl, dst, dev);
306982cbb5c6SRoopa Prabhu 	if (!neigh) {
307082cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Neighbour entry not found");
307182cbb5c6SRoopa Prabhu 		return -ENOENT;
307282cbb5c6SRoopa Prabhu 	}
307382cbb5c6SRoopa Prabhu 
307482cbb5c6SRoopa Prabhu 	err = neigh_get_reply(net, neigh, NETLINK_CB(in_skb).portid,
307582cbb5c6SRoopa Prabhu 			      nlh->nlmsg_seq);
307682cbb5c6SRoopa Prabhu 
307782cbb5c6SRoopa Prabhu 	neigh_release(neigh);
307882cbb5c6SRoopa Prabhu 
307982cbb5c6SRoopa Prabhu 	return err;
308082cbb5c6SRoopa Prabhu }
308182cbb5c6SRoopa Prabhu 
30821da177e4SLinus Torvalds void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
30831da177e4SLinus Torvalds {
30841da177e4SLinus Torvalds 	int chain;
3085d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
30861da177e4SLinus Torvalds 
3087d6bf7817SEric Dumazet 	rcu_read_lock_bh();
3088d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
3089d6bf7817SEric Dumazet 
3090767e97e1SEric Dumazet 	read_lock(&tbl->lock); /* avoid resizes */
3091cd089336SDavid S. Miller 	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
30921da177e4SLinus Torvalds 		struct neighbour *n;
30931da177e4SLinus Torvalds 
3094767e97e1SEric Dumazet 		for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
3095767e97e1SEric Dumazet 		     n != NULL;
3096767e97e1SEric Dumazet 		     n = rcu_dereference_bh(n->next))
30971da177e4SLinus Torvalds 			cb(n, cookie);
30981da177e4SLinus Torvalds 	}
3099d6bf7817SEric Dumazet 	read_unlock(&tbl->lock);
3100d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
31011da177e4SLinus Torvalds }
31021da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_for_each);
31031da177e4SLinus Torvalds 
31041da177e4SLinus Torvalds /* The tbl->lock must be held as a writer and BH disabled. */
31051da177e4SLinus Torvalds void __neigh_for_each_release(struct neigh_table *tbl,
31061da177e4SLinus Torvalds 			      int (*cb)(struct neighbour *))
31071da177e4SLinus Torvalds {
31081da177e4SLinus Torvalds 	int chain;
3109d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
31101da177e4SLinus Torvalds 
3111d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
3112d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
3113cd089336SDavid S. Miller 	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
3114767e97e1SEric Dumazet 		struct neighbour *n;
3115767e97e1SEric Dumazet 		struct neighbour __rcu **np;
31161da177e4SLinus Torvalds 
3117d6bf7817SEric Dumazet 		np = &nht->hash_buckets[chain];
3118767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
3119767e97e1SEric Dumazet 					lockdep_is_held(&tbl->lock))) != NULL) {
31201da177e4SLinus Torvalds 			int release;
31211da177e4SLinus Torvalds 
31221da177e4SLinus Torvalds 			write_lock(&n->lock);
31231da177e4SLinus Torvalds 			release = cb(n);
31241da177e4SLinus Torvalds 			if (release) {
3125767e97e1SEric Dumazet 				rcu_assign_pointer(*np,
3126767e97e1SEric Dumazet 					rcu_dereference_protected(n->next,
3127767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
312858956317SDavid Ahern 				neigh_mark_dead(n);
31291da177e4SLinus Torvalds 			} else
31301da177e4SLinus Torvalds 				np = &n->next;
31311da177e4SLinus Torvalds 			write_unlock(&n->lock);
31324f494554SThomas Graf 			if (release)
31334f494554SThomas Graf 				neigh_cleanup_and_release(n);
31341da177e4SLinus Torvalds 		}
31351da177e4SLinus Torvalds 	}
3136ecbb4169SAlexey Kuznetsov }
31371da177e4SLinus Torvalds EXPORT_SYMBOL(__neigh_for_each_release);
31381da177e4SLinus Torvalds 
3139b79bda3dSEric W. Biederman int neigh_xmit(int index, struct net_device *dev,
31404fd3d7d9SEric W. Biederman 	       const void *addr, struct sk_buff *skb)
31414fd3d7d9SEric W. Biederman {
3142b79bda3dSEric W. Biederman 	int err = -EAFNOSUPPORT;
3143b79bda3dSEric W. Biederman 	if (likely(index < NEIGH_NR_TABLES)) {
31444fd3d7d9SEric W. Biederman 		struct neigh_table *tbl;
31454fd3d7d9SEric W. Biederman 		struct neighbour *neigh;
31464fd3d7d9SEric W. Biederman 
3147b79bda3dSEric W. Biederman 		tbl = neigh_tables[index];
31484fd3d7d9SEric W. Biederman 		if (!tbl)
31494fd3d7d9SEric W. Biederman 			goto out;
3150b560f03dSDavid Barroso 		rcu_read_lock_bh();
31514b2a2bfeSDavid Ahern 		if (index == NEIGH_ARP_TABLE) {
31524b2a2bfeSDavid Ahern 			u32 key = *((u32 *)addr);
31534b2a2bfeSDavid Ahern 
31544b2a2bfeSDavid Ahern 			neigh = __ipv4_neigh_lookup_noref(dev, key);
31554b2a2bfeSDavid Ahern 		} else {
31564fd3d7d9SEric W. Biederman 			neigh = __neigh_lookup_noref(tbl, addr, dev);
31574b2a2bfeSDavid Ahern 		}
31584fd3d7d9SEric W. Biederman 		if (!neigh)
31594fd3d7d9SEric W. Biederman 			neigh = __neigh_create(tbl, addr, dev, false);
31604fd3d7d9SEric W. Biederman 		err = PTR_ERR(neigh);
3161b560f03dSDavid Barroso 		if (IS_ERR(neigh)) {
3162b560f03dSDavid Barroso 			rcu_read_unlock_bh();
31634fd3d7d9SEric W. Biederman 			goto out_kfree_skb;
3164b560f03dSDavid Barroso 		}
31654fd3d7d9SEric W. Biederman 		err = neigh->output(neigh, skb);
3166b560f03dSDavid Barroso 		rcu_read_unlock_bh();
31674fd3d7d9SEric W. Biederman 	}
3168b79bda3dSEric W. Biederman 	else if (index == NEIGH_LINK_TABLE) {
3169b79bda3dSEric W. Biederman 		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
3170b79bda3dSEric W. Biederman 				      addr, NULL, skb->len);
3171b79bda3dSEric W. Biederman 		if (err < 0)
3172b79bda3dSEric W. Biederman 			goto out_kfree_skb;
3173b79bda3dSEric W. Biederman 		err = dev_queue_xmit(skb);
3174b79bda3dSEric W. Biederman 	}
31754fd3d7d9SEric W. Biederman out:
31764fd3d7d9SEric W. Biederman 	return err;
31774fd3d7d9SEric W. Biederman out_kfree_skb:
31784fd3d7d9SEric W. Biederman 	kfree_skb(skb);
31794fd3d7d9SEric W. Biederman 	goto out;
31804fd3d7d9SEric W. Biederman }
31814fd3d7d9SEric W. Biederman EXPORT_SYMBOL(neigh_xmit);
31824fd3d7d9SEric W. Biederman 
31831da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
31841da177e4SLinus Torvalds 
31851da177e4SLinus Torvalds static struct neighbour *neigh_get_first(struct seq_file *seq)
31861da177e4SLinus Torvalds {
31871da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
31881218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
3189d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = state->nht;
31901da177e4SLinus Torvalds 	struct neighbour *n = NULL;
3191f530eed6SColin Ian King 	int bucket;
31921da177e4SLinus Torvalds 
31931da177e4SLinus Torvalds 	state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
3194cd089336SDavid S. Miller 	for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
3195767e97e1SEric Dumazet 		n = rcu_dereference_bh(nht->hash_buckets[bucket]);
31961da177e4SLinus Torvalds 
31971da177e4SLinus Torvalds 		while (n) {
3198878628fbSYOSHIFUJI Hideaki 			if (!net_eq(dev_net(n->dev), net))
3199426b5303SEric W. Biederman 				goto next;
32001da177e4SLinus Torvalds 			if (state->neigh_sub_iter) {
32011da177e4SLinus Torvalds 				loff_t fakep = 0;
32021da177e4SLinus Torvalds 				void *v;
32031da177e4SLinus Torvalds 
32041da177e4SLinus Torvalds 				v = state->neigh_sub_iter(state, n, &fakep);
32051da177e4SLinus Torvalds 				if (!v)
32061da177e4SLinus Torvalds 					goto next;
32071da177e4SLinus Torvalds 			}
32081da177e4SLinus Torvalds 			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
32091da177e4SLinus Torvalds 				break;
32101da177e4SLinus Torvalds 			if (n->nud_state & ~NUD_NOARP)
32111da177e4SLinus Torvalds 				break;
32121da177e4SLinus Torvalds next:
3213767e97e1SEric Dumazet 			n = rcu_dereference_bh(n->next);
32141da177e4SLinus Torvalds 		}
32151da177e4SLinus Torvalds 
32161da177e4SLinus Torvalds 		if (n)
32171da177e4SLinus Torvalds 			break;
32181da177e4SLinus Torvalds 	}
32191da177e4SLinus Torvalds 	state->bucket = bucket;
32201da177e4SLinus Torvalds 
32211da177e4SLinus Torvalds 	return n;
32221da177e4SLinus Torvalds }
32231da177e4SLinus Torvalds 
32241da177e4SLinus Torvalds static struct neighbour *neigh_get_next(struct seq_file *seq,
32251da177e4SLinus Torvalds 					struct neighbour *n,
32261da177e4SLinus Torvalds 					loff_t *pos)
32271da177e4SLinus Torvalds {
32281da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
32291218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
3230d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = state->nht;
32311da177e4SLinus Torvalds 
32321da177e4SLinus Torvalds 	if (state->neigh_sub_iter) {
32331da177e4SLinus Torvalds 		void *v = state->neigh_sub_iter(state, n, pos);
32341da177e4SLinus Torvalds 		if (v)
32351da177e4SLinus Torvalds 			return n;
32361da177e4SLinus Torvalds 	}
3237767e97e1SEric Dumazet 	n = rcu_dereference_bh(n->next);
32381da177e4SLinus Torvalds 
32391da177e4SLinus Torvalds 	while (1) {
32401da177e4SLinus Torvalds 		while (n) {
3241878628fbSYOSHIFUJI Hideaki 			if (!net_eq(dev_net(n->dev), net))
3242426b5303SEric W. Biederman 				goto next;
32431da177e4SLinus Torvalds 			if (state->neigh_sub_iter) {
32441da177e4SLinus Torvalds 				void *v = state->neigh_sub_iter(state, n, pos);
32451da177e4SLinus Torvalds 				if (v)
32461da177e4SLinus Torvalds 					return n;
32471da177e4SLinus Torvalds 				goto next;
32481da177e4SLinus Torvalds 			}
32491da177e4SLinus Torvalds 			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
32501da177e4SLinus Torvalds 				break;
32511da177e4SLinus Torvalds 
32521da177e4SLinus Torvalds 			if (n->nud_state & ~NUD_NOARP)
32531da177e4SLinus Torvalds 				break;
32541da177e4SLinus Torvalds next:
3255767e97e1SEric Dumazet 			n = rcu_dereference_bh(n->next);
32561da177e4SLinus Torvalds 		}
32571da177e4SLinus Torvalds 
32581da177e4SLinus Torvalds 		if (n)
32591da177e4SLinus Torvalds 			break;
32601da177e4SLinus Torvalds 
3261cd089336SDavid S. Miller 		if (++state->bucket >= (1 << nht->hash_shift))
32621da177e4SLinus Torvalds 			break;
32631da177e4SLinus Torvalds 
3264767e97e1SEric Dumazet 		n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
32651da177e4SLinus Torvalds 	}
32661da177e4SLinus Torvalds 
32671da177e4SLinus Torvalds 	if (n && pos)
32681da177e4SLinus Torvalds 		--(*pos);
32691da177e4SLinus Torvalds 	return n;
32701da177e4SLinus Torvalds }
32711da177e4SLinus Torvalds 
32721da177e4SLinus Torvalds static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
32731da177e4SLinus Torvalds {
32741da177e4SLinus Torvalds 	struct neighbour *n = neigh_get_first(seq);
32751da177e4SLinus Torvalds 
32761da177e4SLinus Torvalds 	if (n) {
3277745e2031SChris Larson 		--(*pos);
32781da177e4SLinus Torvalds 		while (*pos) {
32791da177e4SLinus Torvalds 			n = neigh_get_next(seq, n, pos);
32801da177e4SLinus Torvalds 			if (!n)
32811da177e4SLinus Torvalds 				break;
32821da177e4SLinus Torvalds 		}
32831da177e4SLinus Torvalds 	}
32841da177e4SLinus Torvalds 	return *pos ? NULL : n;
32851da177e4SLinus Torvalds }
32861da177e4SLinus Torvalds 
32871da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
32881da177e4SLinus Torvalds {
32891da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
32901218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
32911da177e4SLinus Torvalds 	struct neigh_table *tbl = state->tbl;
32921da177e4SLinus Torvalds 	struct pneigh_entry *pn = NULL;
329348de7c0cSYang Li 	int bucket;
32941da177e4SLinus Torvalds 
32951da177e4SLinus Torvalds 	state->flags |= NEIGH_SEQ_IS_PNEIGH;
32961da177e4SLinus Torvalds 	for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
32971da177e4SLinus Torvalds 		pn = tbl->phash_buckets[bucket];
3298878628fbSYOSHIFUJI Hideaki 		while (pn && !net_eq(pneigh_net(pn), net))
3299426b5303SEric W. Biederman 			pn = pn->next;
33001da177e4SLinus Torvalds 		if (pn)
33011da177e4SLinus Torvalds 			break;
33021da177e4SLinus Torvalds 	}
33031da177e4SLinus Torvalds 	state->bucket = bucket;
33041da177e4SLinus Torvalds 
33051da177e4SLinus Torvalds 	return pn;
33061da177e4SLinus Torvalds }
33071da177e4SLinus Torvalds 
33081da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
33091da177e4SLinus Torvalds 					    struct pneigh_entry *pn,
33101da177e4SLinus Torvalds 					    loff_t *pos)
33111da177e4SLinus Torvalds {
33121da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
33131218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
33141da177e4SLinus Torvalds 	struct neigh_table *tbl = state->tbl;
33151da177e4SLinus Torvalds 
3316df07a94cSJorge Boncompte [DTI2] 	do {
33171da177e4SLinus Torvalds 		pn = pn->next;
3318df07a94cSJorge Boncompte [DTI2] 	} while (pn && !net_eq(pneigh_net(pn), net));
3319df07a94cSJorge Boncompte [DTI2] 
33201da177e4SLinus Torvalds 	while (!pn) {
33211da177e4SLinus Torvalds 		if (++state->bucket > PNEIGH_HASHMASK)
33221da177e4SLinus Torvalds 			break;
33231da177e4SLinus Torvalds 		pn = tbl->phash_buckets[state->bucket];
3324878628fbSYOSHIFUJI Hideaki 		while (pn && !net_eq(pneigh_net(pn), net))
3325426b5303SEric W. Biederman 			pn = pn->next;
33261da177e4SLinus Torvalds 		if (pn)
33271da177e4SLinus Torvalds 			break;
33281da177e4SLinus Torvalds 	}
33291da177e4SLinus Torvalds 
33301da177e4SLinus Torvalds 	if (pn && pos)
33311da177e4SLinus Torvalds 		--(*pos);
33321da177e4SLinus Torvalds 
33331da177e4SLinus Torvalds 	return pn;
33341da177e4SLinus Torvalds }
33351da177e4SLinus Torvalds 
33361da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
33371da177e4SLinus Torvalds {
33381da177e4SLinus Torvalds 	struct pneigh_entry *pn = pneigh_get_first(seq);
33391da177e4SLinus Torvalds 
33401da177e4SLinus Torvalds 	if (pn) {
3341745e2031SChris Larson 		--(*pos);
33421da177e4SLinus Torvalds 		while (*pos) {
33431da177e4SLinus Torvalds 			pn = pneigh_get_next(seq, pn, pos);
33441da177e4SLinus Torvalds 			if (!pn)
33451da177e4SLinus Torvalds 				break;
33461da177e4SLinus Torvalds 		}
33471da177e4SLinus Torvalds 	}
33481da177e4SLinus Torvalds 	return *pos ? NULL : pn;
33491da177e4SLinus Torvalds }
33501da177e4SLinus Torvalds 
33511da177e4SLinus Torvalds static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
33521da177e4SLinus Torvalds {
33531da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
33541da177e4SLinus Torvalds 	void *rc;
3355745e2031SChris Larson 	loff_t idxpos = *pos;
33561da177e4SLinus Torvalds 
3357745e2031SChris Larson 	rc = neigh_get_idx(seq, &idxpos);
33581da177e4SLinus Torvalds 	if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
3359745e2031SChris Larson 		rc = pneigh_get_idx(seq, &idxpos);
33601da177e4SLinus Torvalds 
33611da177e4SLinus Torvalds 	return rc;
33621da177e4SLinus Torvalds }
33631da177e4SLinus Torvalds 
33641da177e4SLinus Torvalds void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags)
3365f3e92cb8SEric Dumazet 	__acquires(tbl->lock)
3366d6bf7817SEric Dumazet 	__acquires(rcu_bh)
33671da177e4SLinus Torvalds {
33681da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
33691da177e4SLinus Torvalds 
33701da177e4SLinus Torvalds 	state->tbl = tbl;
33711da177e4SLinus Torvalds 	state->bucket = 0;
33721da177e4SLinus Torvalds 	state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
33731da177e4SLinus Torvalds 
3374d6bf7817SEric Dumazet 	rcu_read_lock_bh();
3375d6bf7817SEric Dumazet 	state->nht = rcu_dereference_bh(tbl->nht);
3376f3e92cb8SEric Dumazet 	read_lock(&tbl->lock);
3377767e97e1SEric Dumazet 
3378745e2031SChris Larson 	return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
33791da177e4SLinus Torvalds }
33801da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_start);
33811da177e4SLinus Torvalds 
33821da177e4SLinus Torvalds void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
33831da177e4SLinus Torvalds {
33841da177e4SLinus Torvalds 	struct neigh_seq_state *state;
33851da177e4SLinus Torvalds 	void *rc;
33861da177e4SLinus Torvalds 
33871da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN) {
3388bff69732SChris Larson 		rc = neigh_get_first(seq);
33891da177e4SLinus Torvalds 		goto out;
33901da177e4SLinus Torvalds 	}
33911da177e4SLinus Torvalds 
33921da177e4SLinus Torvalds 	state = seq->private;
33931da177e4SLinus Torvalds 	if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
33941da177e4SLinus Torvalds 		rc = neigh_get_next(seq, v, NULL);
33951da177e4SLinus Torvalds 		if (rc)
33961da177e4SLinus Torvalds 			goto out;
33971da177e4SLinus Torvalds 		if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
33981da177e4SLinus Torvalds 			rc = pneigh_get_first(seq);
33991da177e4SLinus Torvalds 	} else {
34001da177e4SLinus Torvalds 		BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
34011da177e4SLinus Torvalds 		rc = pneigh_get_next(seq, v, NULL);
34021da177e4SLinus Torvalds 	}
34031da177e4SLinus Torvalds out:
34041da177e4SLinus Torvalds 	++(*pos);
34051da177e4SLinus Torvalds 	return rc;
34061da177e4SLinus Torvalds }
34071da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_next);
34081da177e4SLinus Torvalds 
34091da177e4SLinus Torvalds void neigh_seq_stop(struct seq_file *seq, void *v)
3410f3e92cb8SEric Dumazet 	__releases(tbl->lock)
3411d6bf7817SEric Dumazet 	__releases(rcu_bh)
34121da177e4SLinus Torvalds {
3413f3e92cb8SEric Dumazet 	struct neigh_seq_state *state = seq->private;
3414f3e92cb8SEric Dumazet 	struct neigh_table *tbl = state->tbl;
3415f3e92cb8SEric Dumazet 
3416f3e92cb8SEric Dumazet 	read_unlock(&tbl->lock);
3417d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
34181da177e4SLinus Torvalds }
34191da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_stop);
34201da177e4SLinus Torvalds 
34211da177e4SLinus Torvalds /* statistics via seq_file */
34221da177e4SLinus Torvalds 
34231da177e4SLinus Torvalds static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
34241da177e4SLinus Torvalds {
3425359745d7SMuchun Song 	struct neigh_table *tbl = pde_data(file_inode(seq->file));
34261da177e4SLinus Torvalds 	int cpu;
34271da177e4SLinus Torvalds 
34281da177e4SLinus Torvalds 	if (*pos == 0)
34291da177e4SLinus Torvalds 		return SEQ_START_TOKEN;
34301da177e4SLinus Torvalds 
34310f23174aSRusty Russell 	for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
34321da177e4SLinus Torvalds 		if (!cpu_possible(cpu))
34331da177e4SLinus Torvalds 			continue;
34341da177e4SLinus Torvalds 		*pos = cpu+1;
34351da177e4SLinus Torvalds 		return per_cpu_ptr(tbl->stats, cpu);
34361da177e4SLinus Torvalds 	}
34371da177e4SLinus Torvalds 	return NULL;
34381da177e4SLinus Torvalds }
34391da177e4SLinus Torvalds 
34401da177e4SLinus Torvalds static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
34411da177e4SLinus Torvalds {
3442359745d7SMuchun Song 	struct neigh_table *tbl = pde_data(file_inode(seq->file));
34431da177e4SLinus Torvalds 	int cpu;
34441da177e4SLinus Torvalds 
34450f23174aSRusty Russell 	for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
34461da177e4SLinus Torvalds 		if (!cpu_possible(cpu))
34471da177e4SLinus Torvalds 			continue;
34481da177e4SLinus Torvalds 		*pos = cpu+1;
34491da177e4SLinus Torvalds 		return per_cpu_ptr(tbl->stats, cpu);
34501da177e4SLinus Torvalds 	}
34511e3f9f07SVasily Averin 	(*pos)++;
34521da177e4SLinus Torvalds 	return NULL;
34531da177e4SLinus Torvalds }
34541da177e4SLinus Torvalds 
34551da177e4SLinus Torvalds static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
34561da177e4SLinus Torvalds {
34571da177e4SLinus Torvalds 
34581da177e4SLinus Torvalds }
34591da177e4SLinus Torvalds 
34601da177e4SLinus Torvalds static int neigh_stat_seq_show(struct seq_file *seq, void *v)
34611da177e4SLinus Torvalds {
3462359745d7SMuchun Song 	struct neigh_table *tbl = pde_data(file_inode(seq->file));
34631da177e4SLinus Torvalds 	struct neigh_statistics *st = v;
34641da177e4SLinus Torvalds 
34651da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN) {
34660547ffe6SYajun 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");
34671da177e4SLinus Torvalds 		return 0;
34681da177e4SLinus Torvalds 	}
34691da177e4SLinus Torvalds 
34701da177e4SLinus Torvalds 	seq_printf(seq, "%08x %08lx %08lx %08lx   %08lx %08lx %08lx   "
34710547ffe6SYajun Deng 			"%08lx         %08lx         %08lx         "
34720547ffe6SYajun Deng 			"%08lx       %08lx            %08lx\n",
34731da177e4SLinus Torvalds 		   atomic_read(&tbl->entries),
34741da177e4SLinus Torvalds 
34751da177e4SLinus Torvalds 		   st->allocs,
34761da177e4SLinus Torvalds 		   st->destroys,
34771da177e4SLinus Torvalds 		   st->hash_grows,
34781da177e4SLinus Torvalds 
34791da177e4SLinus Torvalds 		   st->lookups,
34801da177e4SLinus Torvalds 		   st->hits,
34811da177e4SLinus Torvalds 
34821da177e4SLinus Torvalds 		   st->res_failed,
34831da177e4SLinus Torvalds 
34841da177e4SLinus Torvalds 		   st->rcv_probes_mcast,
34851da177e4SLinus Torvalds 		   st->rcv_probes_ucast,
34861da177e4SLinus Torvalds 
34871da177e4SLinus Torvalds 		   st->periodic_gc_runs,
34889a6d276eSNeil Horman 		   st->forced_gc_runs,
3489fb811395SRick Jones 		   st->unres_discards,
3490fb811395SRick Jones 		   st->table_fulls
34911da177e4SLinus Torvalds 		   );
34921da177e4SLinus Torvalds 
34931da177e4SLinus Torvalds 	return 0;
34941da177e4SLinus Torvalds }
34951da177e4SLinus Torvalds 
3496f690808eSStephen Hemminger static const struct seq_operations neigh_stat_seq_ops = {
34971da177e4SLinus Torvalds 	.start	= neigh_stat_seq_start,
34981da177e4SLinus Torvalds 	.next	= neigh_stat_seq_next,
34991da177e4SLinus Torvalds 	.stop	= neigh_stat_seq_stop,
35001da177e4SLinus Torvalds 	.show	= neigh_stat_seq_show,
35011da177e4SLinus Torvalds };
35021da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */
35031da177e4SLinus Torvalds 
35047b8f7a40SRoopa Prabhu static void __neigh_notify(struct neighbour *n, int type, int flags,
35057b8f7a40SRoopa Prabhu 			   u32 pid)
35061da177e4SLinus Torvalds {
3507c346dca1SYOSHIFUJI Hideaki 	struct net *net = dev_net(n->dev);
35088b8aec50SThomas Graf 	struct sk_buff *skb;
3509b8673311SThomas Graf 	int err = -ENOBUFS;
35101da177e4SLinus Torvalds 
3511339bf98fSThomas Graf 	skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
35128b8aec50SThomas Graf 	if (skb == NULL)
3513b8673311SThomas Graf 		goto errout;
35141da177e4SLinus Torvalds 
35157b8f7a40SRoopa Prabhu 	err = neigh_fill_info(skb, n, pid, 0, type, flags);
351626932566SPatrick McHardy 	if (err < 0) {
351726932566SPatrick McHardy 		/* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
351826932566SPatrick McHardy 		WARN_ON(err == -EMSGSIZE);
351926932566SPatrick McHardy 		kfree_skb(skb);
352026932566SPatrick McHardy 		goto errout;
352126932566SPatrick McHardy 	}
35221ce85fe4SPablo Neira Ayuso 	rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
35231ce85fe4SPablo Neira Ayuso 	return;
3524b8673311SThomas Graf errout:
3525b8673311SThomas Graf 	if (err < 0)
3526426b5303SEric W. Biederman 		rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
3527b8673311SThomas Graf }
3528b8673311SThomas Graf 
3529b8673311SThomas Graf void neigh_app_ns(struct neighbour *n)
3530b8673311SThomas Graf {
35317b8f7a40SRoopa Prabhu 	__neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST, 0);
35328b8aec50SThomas Graf }
35330a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_app_ns);
35341da177e4SLinus Torvalds 
35351da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL
3536b93196dcSCong Wang static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
35371da177e4SLinus Torvalds 
3538fe2c6338SJoe Perches static int proc_unres_qlen(struct ctl_table *ctl, int write,
353932927393SChristoph Hellwig 			   void *buffer, size_t *lenp, loff_t *ppos)
35408b5c171bSEric Dumazet {
35418b5c171bSEric Dumazet 	int size, ret;
3542fe2c6338SJoe Perches 	struct ctl_table tmp = *ctl;
35438b5c171bSEric Dumazet 
3544eec4844fSMatteo Croce 	tmp.extra1 = SYSCTL_ZERO;
3545ce46cc64SShan Wei 	tmp.extra2 = &unres_qlen_max;
35468b5c171bSEric Dumazet 	tmp.data = &size;
3547ce46cc64SShan Wei 
3548ce46cc64SShan Wei 	size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN);
3549ce46cc64SShan Wei 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
3550ce46cc64SShan Wei 
35518b5c171bSEric Dumazet 	if (write && !ret)
35528b5c171bSEric Dumazet 		*(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
35538b5c171bSEric Dumazet 	return ret;
35548b5c171bSEric Dumazet }
35558b5c171bSEric Dumazet 
35561d4c8c29SJiri Pirko static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
35571d4c8c29SJiri Pirko 				  int index)
35581d4c8c29SJiri Pirko {
35591d4c8c29SJiri Pirko 	struct net_device *dev;
35601d4c8c29SJiri Pirko 	int family = neigh_parms_family(p);
35611d4c8c29SJiri Pirko 
35621d4c8c29SJiri Pirko 	rcu_read_lock();
35631d4c8c29SJiri Pirko 	for_each_netdev_rcu(net, dev) {
35641d4c8c29SJiri Pirko 		struct neigh_parms *dst_p =
35651d4c8c29SJiri Pirko 				neigh_get_dev_parms_rcu(dev, family);
35661d4c8c29SJiri Pirko 
35671d4c8c29SJiri Pirko 		if (dst_p && !test_bit(index, dst_p->data_state))
35681d4c8c29SJiri Pirko 			dst_p->data[index] = p->data[index];
35691d4c8c29SJiri Pirko 	}
35701d4c8c29SJiri Pirko 	rcu_read_unlock();
35711d4c8c29SJiri Pirko }
35721d4c8c29SJiri Pirko 
35731d4c8c29SJiri Pirko static void neigh_proc_update(struct ctl_table *ctl, int write)
35741d4c8c29SJiri Pirko {
35751d4c8c29SJiri Pirko 	struct net_device *dev = ctl->extra1;
35761d4c8c29SJiri Pirko 	struct neigh_parms *p = ctl->extra2;
357777d47afbSJiri Pirko 	struct net *net = neigh_parms_net(p);
35781d4c8c29SJiri Pirko 	int index = (int *) ctl->data - p->data;
35791d4c8c29SJiri Pirko 
35801d4c8c29SJiri Pirko 	if (!write)
35811d4c8c29SJiri Pirko 		return;
35821d4c8c29SJiri Pirko 
35831d4c8c29SJiri Pirko 	set_bit(index, p->data_state);
35847627ae60SMarcus Huewe 	if (index == NEIGH_VAR_DELAY_PROBE_TIME)
35852a4501aeSIdo Schimmel 		call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
35861d4c8c29SJiri Pirko 	if (!dev) /* NULL dev means this is default value */
35871d4c8c29SJiri Pirko 		neigh_copy_dflt_parms(net, p, index);
35881d4c8c29SJiri Pirko }
35891d4c8c29SJiri Pirko 
35901f9248e5SJiri Pirko static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
359132927393SChristoph Hellwig 					   void *buffer, size_t *lenp,
359232927393SChristoph Hellwig 					   loff_t *ppos)
35931f9248e5SJiri Pirko {
35941f9248e5SJiri Pirko 	struct ctl_table tmp = *ctl;
35951d4c8c29SJiri Pirko 	int ret;
35961f9248e5SJiri Pirko 
3597eec4844fSMatteo Croce 	tmp.extra1 = SYSCTL_ZERO;
3598eec4844fSMatteo Croce 	tmp.extra2 = SYSCTL_INT_MAX;
35991f9248e5SJiri Pirko 
36001d4c8c29SJiri Pirko 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
36011d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36021d4c8c29SJiri Pirko 	return ret;
36031f9248e5SJiri Pirko }
36041f9248e5SJiri Pirko 
3605211da42eSYuwei Wang static int neigh_proc_dointvec_ms_jiffies_positive(struct ctl_table *ctl, int write,
3606211da42eSYuwei Wang 						   void *buffer, size_t *lenp, loff_t *ppos)
3607211da42eSYuwei Wang {
3608211da42eSYuwei Wang 	struct ctl_table tmp = *ctl;
3609211da42eSYuwei Wang 	int ret;
3610211da42eSYuwei Wang 
3611211da42eSYuwei Wang 	int min = msecs_to_jiffies(1);
3612211da42eSYuwei Wang 
3613211da42eSYuwei Wang 	tmp.extra1 = &min;
3614211da42eSYuwei Wang 	tmp.extra2 = NULL;
3615211da42eSYuwei Wang 
3616211da42eSYuwei Wang 	ret = proc_dointvec_ms_jiffies_minmax(&tmp, write, buffer, lenp, ppos);
3617211da42eSYuwei Wang 	neigh_proc_update(ctl, write);
3618211da42eSYuwei Wang 	return ret;
3619211da42eSYuwei Wang }
3620211da42eSYuwei Wang 
362132927393SChristoph Hellwig int neigh_proc_dointvec(struct ctl_table *ctl, int write, void *buffer,
362232927393SChristoph Hellwig 			size_t *lenp, loff_t *ppos)
3623cb5b09c1SJiri Pirko {
36241d4c8c29SJiri Pirko 	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
36251d4c8c29SJiri Pirko 
36261d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36271d4c8c29SJiri Pirko 	return ret;
3628cb5b09c1SJiri Pirko }
3629cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec);
3630cb5b09c1SJiri Pirko 
363132927393SChristoph Hellwig int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, void *buffer,
3632cb5b09c1SJiri Pirko 				size_t *lenp, loff_t *ppos)
3633cb5b09c1SJiri Pirko {
36341d4c8c29SJiri Pirko 	int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
36351d4c8c29SJiri Pirko 
36361d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36371d4c8c29SJiri Pirko 	return ret;
3638cb5b09c1SJiri Pirko }
3639cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
3640cb5b09c1SJiri Pirko 
3641cb5b09c1SJiri Pirko static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write,
364232927393SChristoph Hellwig 					      void *buffer, size_t *lenp,
364332927393SChristoph Hellwig 					      loff_t *ppos)
3644cb5b09c1SJiri Pirko {
36451d4c8c29SJiri Pirko 	int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
36461d4c8c29SJiri Pirko 
36471d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36481d4c8c29SJiri Pirko 	return ret;
3649cb5b09c1SJiri Pirko }
3650cb5b09c1SJiri Pirko 
3651cb5b09c1SJiri Pirko int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
365232927393SChristoph Hellwig 				   void *buffer, size_t *lenp, loff_t *ppos)
3653cb5b09c1SJiri Pirko {
36541d4c8c29SJiri Pirko 	int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
36551d4c8c29SJiri Pirko 
36561d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36571d4c8c29SJiri Pirko 	return ret;
3658cb5b09c1SJiri Pirko }
3659cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
3660cb5b09c1SJiri Pirko 
3661cb5b09c1SJiri Pirko static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
366232927393SChristoph Hellwig 					  void *buffer, size_t *lenp,
366332927393SChristoph Hellwig 					  loff_t *ppos)
3664cb5b09c1SJiri Pirko {
36651d4c8c29SJiri Pirko 	int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
36661d4c8c29SJiri Pirko 
36671d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36681d4c8c29SJiri Pirko 	return ret;
3669cb5b09c1SJiri Pirko }
3670cb5b09c1SJiri Pirko 
36714bf6980dSJean-Francois Remy static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write,
367232927393SChristoph Hellwig 					  void *buffer, size_t *lenp,
367332927393SChristoph Hellwig 					  loff_t *ppos)
36744bf6980dSJean-Francois Remy {
36754bf6980dSJean-Francois Remy 	struct neigh_parms *p = ctl->extra2;
36764bf6980dSJean-Francois Remy 	int ret;
36774bf6980dSJean-Francois Remy 
36784bf6980dSJean-Francois Remy 	if (strcmp(ctl->procname, "base_reachable_time") == 0)
36794bf6980dSJean-Francois Remy 		ret = neigh_proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
36804bf6980dSJean-Francois Remy 	else if (strcmp(ctl->procname, "base_reachable_time_ms") == 0)
36814bf6980dSJean-Francois Remy 		ret = neigh_proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
36824bf6980dSJean-Francois Remy 	else
36834bf6980dSJean-Francois Remy 		ret = -1;
36844bf6980dSJean-Francois Remy 
36854bf6980dSJean-Francois Remy 	if (write && ret == 0) {
36864bf6980dSJean-Francois Remy 		/* update reachable_time as well, otherwise, the change will
36874bf6980dSJean-Francois Remy 		 * only be effective after the next time neigh_periodic_work
36884bf6980dSJean-Francois Remy 		 * decides to recompute it
36894bf6980dSJean-Francois Remy 		 */
36904bf6980dSJean-Francois Remy 		p->reachable_time =
36914bf6980dSJean-Francois Remy 			neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
36924bf6980dSJean-Francois Remy 	}
36934bf6980dSJean-Francois Remy 	return ret;
36944bf6980dSJean-Francois Remy }
36954bf6980dSJean-Francois Remy 
36961f9248e5SJiri Pirko #define NEIGH_PARMS_DATA_OFFSET(index)	\
36971f9248e5SJiri Pirko 	(&((struct neigh_parms *) 0)->data[index])
36981f9248e5SJiri Pirko 
36991f9248e5SJiri Pirko #define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \
37001f9248e5SJiri Pirko 	[NEIGH_VAR_ ## attr] = { \
37011f9248e5SJiri Pirko 		.procname	= name, \
37021f9248e5SJiri Pirko 		.data		= NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \
37031f9248e5SJiri Pirko 		.maxlen		= sizeof(int), \
37041f9248e5SJiri Pirko 		.mode		= mval, \
37051f9248e5SJiri Pirko 		.proc_handler	= proc, \
37061f9248e5SJiri Pirko 	}
37071f9248e5SJiri Pirko 
37081f9248e5SJiri Pirko #define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \
37091f9248e5SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax)
37101f9248e5SJiri Pirko 
37111f9248e5SJiri Pirko #define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \
3712cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies)
37131f9248e5SJiri Pirko 
37141f9248e5SJiri Pirko #define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
3715cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)
37161f9248e5SJiri Pirko 
3717211da42eSYuwei Wang #define NEIGH_SYSCTL_MS_JIFFIES_POSITIVE_ENTRY(attr, name) \
3718211da42eSYuwei Wang 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_ms_jiffies_positive)
3719211da42eSYuwei Wang 
37201f9248e5SJiri Pirko #define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \
3721cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
37221f9248e5SJiri Pirko 
37231f9248e5SJiri Pirko #define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \
3724cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_unres_qlen)
372554716e3bSEric W. Biederman 
37261da177e4SLinus Torvalds static struct neigh_sysctl_table {
37271da177e4SLinus Torvalds 	struct ctl_table_header *sysctl_header;
37288b5c171bSEric Dumazet 	struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
3729ab32ea5dSBrian Haley } neigh_sysctl_template __read_mostly = {
37301da177e4SLinus Torvalds 	.neigh_vars = {
37311f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"),
37321f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"),
37331f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"),
37348da86466SYOSHIFUJI Hideaki/吉藤英明 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_REPROBES, "mcast_resolicit"),
37351f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),
37361f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),
37371f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"),
3738211da42eSYuwei Wang 		NEIGH_SYSCTL_MS_JIFFIES_POSITIVE_ENTRY(INTERVAL_PROBE_TIME_MS,
3739211da42eSYuwei Wang 						       "interval_probe_time_ms"),
37401f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"),
37411f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"),
37421f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"),
37431f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"),
37441f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"),
37451f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"),
37461f9248e5SJiri Pirko 		NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"),
37471f9248e5SJiri Pirko 		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"),
37481f9248e5SJiri Pirko 		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"),
37498b5c171bSEric Dumazet 		[NEIGH_VAR_GC_INTERVAL] = {
37501da177e4SLinus Torvalds 			.procname	= "gc_interval",
37511da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
37521da177e4SLinus Torvalds 			.mode		= 0644,
37536d9f239aSAlexey Dobriyan 			.proc_handler	= proc_dointvec_jiffies,
37541da177e4SLinus Torvalds 		},
37558b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH1] = {
37561da177e4SLinus Torvalds 			.procname	= "gc_thresh1",
37571da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
37581da177e4SLinus Torvalds 			.mode		= 0644,
3759eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3760eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3761555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
37621da177e4SLinus Torvalds 		},
37638b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH2] = {
37641da177e4SLinus Torvalds 			.procname	= "gc_thresh2",
37651da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
37661da177e4SLinus Torvalds 			.mode		= 0644,
3767eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3768eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3769555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
37701da177e4SLinus Torvalds 		},
37718b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH3] = {
37721da177e4SLinus Torvalds 			.procname	= "gc_thresh3",
37731da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
37741da177e4SLinus Torvalds 			.mode		= 0644,
3775eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3776eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3777555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
37781da177e4SLinus Torvalds 		},
3779c3bac5a7SPavel Emelyanov 		{},
37801da177e4SLinus Torvalds 	},
37811da177e4SLinus Torvalds };
37821da177e4SLinus Torvalds 
37831da177e4SLinus Torvalds int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
378473af614aSJiri Pirko 			  proc_handler *handler)
37851da177e4SLinus Torvalds {
37861f9248e5SJiri Pirko 	int i;
37873c607bbbSPavel Emelyanov 	struct neigh_sysctl_table *t;
37881f9248e5SJiri Pirko 	const char *dev_name_source;
37898f40a1f9SEric W. Biederman 	char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
379073af614aSJiri Pirko 	char *p_name;
37911da177e4SLinus Torvalds 
3792425b9c7fSVasily Averin 	t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL_ACCOUNT);
37931da177e4SLinus Torvalds 	if (!t)
37943c607bbbSPavel Emelyanov 		goto err;
37953c607bbbSPavel Emelyanov 
3796b194c1f1SJiri Pirko 	for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
37971f9248e5SJiri Pirko 		t->neigh_vars[i].data += (long) p;
3798cb5b09c1SJiri Pirko 		t->neigh_vars[i].extra1 = dev;
37991d4c8c29SJiri Pirko 		t->neigh_vars[i].extra2 = p;
3800cb5b09c1SJiri Pirko 	}
38011da177e4SLinus Torvalds 
38021da177e4SLinus Torvalds 	if (dev) {
38031da177e4SLinus Torvalds 		dev_name_source = dev->name;
3804d12af679SEric W. Biederman 		/* Terminate the table early */
38058b5c171bSEric Dumazet 		memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
38068b5c171bSEric Dumazet 		       sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
38071da177e4SLinus Torvalds 	} else {
38089ecf07a1SMathias Krause 		struct neigh_table *tbl = p->tbl;
38098f40a1f9SEric W. Biederman 		dev_name_source = "default";
38109ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = &tbl->gc_interval;
38119ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = &tbl->gc_thresh1;
38129ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = &tbl->gc_thresh2;
38139ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = &tbl->gc_thresh3;
38141da177e4SLinus Torvalds 	}
38151da177e4SLinus Torvalds 
3816f8572d8fSEric W. Biederman 	if (handler) {
38171da177e4SLinus Torvalds 		/* RetransTime */
38188b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
38191da177e4SLinus Torvalds 		/* ReachableTime */
38208b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
38211da177e4SLinus Torvalds 		/* RetransTime (in milliseconds)*/
38228b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
38231da177e4SLinus Torvalds 		/* ReachableTime (in milliseconds) */
38248b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
38254bf6980dSJean-Francois Remy 	} else {
38264bf6980dSJean-Francois Remy 		/* Those handlers will update p->reachable_time after
38274bf6980dSJean-Francois Remy 		 * base_reachable_time(_ms) is set to ensure the new timer starts being
38284bf6980dSJean-Francois Remy 		 * applied after the next neighbour update instead of waiting for
38294bf6980dSJean-Francois Remy 		 * neigh_periodic_work to update its value (can be multiple minutes)
38304bf6980dSJean-Francois Remy 		 * So any handler that replaces them should do this as well
38314bf6980dSJean-Francois Remy 		 */
38324bf6980dSJean-Francois Remy 		/* ReachableTime */
38334bf6980dSJean-Francois Remy 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler =
38344bf6980dSJean-Francois Remy 			neigh_proc_base_reachable_time;
38354bf6980dSJean-Francois Remy 		/* ReachableTime (in milliseconds) */
38364bf6980dSJean-Francois Remy 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler =
38374bf6980dSJean-Francois Remy 			neigh_proc_base_reachable_time;
38381da177e4SLinus Torvalds 	}
38391da177e4SLinus Torvalds 
384073af614aSJiri Pirko 	switch (neigh_parms_family(p)) {
384173af614aSJiri Pirko 	case AF_INET:
384273af614aSJiri Pirko 	      p_name = "ipv4";
384373af614aSJiri Pirko 	      break;
384473af614aSJiri Pirko 	case AF_INET6:
384573af614aSJiri Pirko 	      p_name = "ipv6";
384673af614aSJiri Pirko 	      break;
384773af614aSJiri Pirko 	default:
384873af614aSJiri Pirko 	      BUG();
384973af614aSJiri Pirko 	}
385073af614aSJiri Pirko 
38518f40a1f9SEric W. Biederman 	snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
38528f40a1f9SEric W. Biederman 		p_name, dev_name_source);
38534ab438fcSDenis V. Lunev 	t->sysctl_header =
38548f40a1f9SEric W. Biederman 		register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
38553c607bbbSPavel Emelyanov 	if (!t->sysctl_header)
38568f40a1f9SEric W. Biederman 		goto free;
38573c607bbbSPavel Emelyanov 
38581da177e4SLinus Torvalds 	p->sysctl_table = t;
38591da177e4SLinus Torvalds 	return 0;
38601da177e4SLinus Torvalds 
38611da177e4SLinus Torvalds free:
38621da177e4SLinus Torvalds 	kfree(t);
38633c607bbbSPavel Emelyanov err:
38643c607bbbSPavel Emelyanov 	return -ENOBUFS;
38651da177e4SLinus Torvalds }
38660a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_sysctl_register);
38671da177e4SLinus Torvalds 
38681da177e4SLinus Torvalds void neigh_sysctl_unregister(struct neigh_parms *p)
38691da177e4SLinus Torvalds {
38701da177e4SLinus Torvalds 	if (p->sysctl_table) {
38711da177e4SLinus Torvalds 		struct neigh_sysctl_table *t = p->sysctl_table;
38721da177e4SLinus Torvalds 		p->sysctl_table = NULL;
38735dd3df10SEric W. Biederman 		unregister_net_sysctl_table(t->sysctl_header);
38741da177e4SLinus Torvalds 		kfree(t);
38751da177e4SLinus Torvalds 	}
38761da177e4SLinus Torvalds }
38770a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_sysctl_unregister);
38781da177e4SLinus Torvalds 
38791da177e4SLinus Torvalds #endif	/* CONFIG_SYSCTL */
38801da177e4SLinus Torvalds 
3881c8822a4eSThomas Graf static int __init neigh_init(void)
3882c8822a4eSThomas Graf {
3883b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0);
3884b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0);
388582cbb5c6SRoopa Prabhu 	rtnl_register(PF_UNSPEC, RTM_GETNEIGH, neigh_get, neigh_dump_info, 0);
3886c8822a4eSThomas Graf 
3887c7ac8679SGreg Rose 	rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
3888b97bac64SFlorian Westphal 		      0);
3889b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, 0);
3890c8822a4eSThomas Graf 
3891c8822a4eSThomas Graf 	return 0;
3892c8822a4eSThomas Graf }
3893c8822a4eSThomas Graf 
3894c8822a4eSThomas Graf subsys_initcall(neigh_init);
3895