xref: /openbmc/linux/net/core/neighbour.c (revision 66ba215c)
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 {
11463862b5bSAruna-Hewapathirane 	return base ? (prandom_u32() % 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*66ba215cSDenis V. Lunev static void pneigh_queue_purge(struct sk_buff_head *list, struct net *net)
3111da177e4SLinus Torvalds {
312*66ba215cSDenis V. Lunev 	unsigned long flags;
3131da177e4SLinus Torvalds 	struct sk_buff *skb;
3141da177e4SLinus Torvalds 
315*66ba215cSDenis V. Lunev 	spin_lock_irqsave(&list->lock, flags);
316*66ba215cSDenis V. Lunev 	skb = skb_peek(list);
317*66ba215cSDenis V. Lunev 	while (skb != NULL) {
318*66ba215cSDenis V. Lunev 		struct sk_buff *skb_next = skb_peek_next(skb, list);
319*66ba215cSDenis V. Lunev 		if (net == NULL || net_eq(dev_net(skb->dev), net)) {
320*66ba215cSDenis V. Lunev 			__skb_unlink(skb, list);
3211da177e4SLinus Torvalds 			dev_put(skb->dev);
3221da177e4SLinus Torvalds 			kfree_skb(skb);
3231da177e4SLinus Torvalds 		}
324*66ba215cSDenis V. Lunev 		skb = skb_next;
325*66ba215cSDenis V. Lunev 	}
326*66ba215cSDenis V. Lunev 	spin_unlock_irqrestore(&list->lock, flags);
3271da177e4SLinus Torvalds }
3281da177e4SLinus Torvalds 
329859bd2efSDavid Ahern static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev,
330859bd2efSDavid Ahern 			    bool skip_perm)
3311da177e4SLinus Torvalds {
3321da177e4SLinus Torvalds 	int i;
333d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
3341da177e4SLinus Torvalds 
335d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
336d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
337d6bf7817SEric Dumazet 
338cd089336SDavid S. Miller 	for (i = 0; i < (1 << nht->hash_shift); i++) {
339767e97e1SEric Dumazet 		struct neighbour *n;
340767e97e1SEric Dumazet 		struct neighbour __rcu **np = &nht->hash_buckets[i];
3411da177e4SLinus Torvalds 
342767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
343767e97e1SEric Dumazet 					lockdep_is_held(&tbl->lock))) != NULL) {
3441da177e4SLinus Torvalds 			if (dev && n->dev != dev) {
3451da177e4SLinus Torvalds 				np = &n->next;
3461da177e4SLinus Torvalds 				continue;
3471da177e4SLinus Torvalds 			}
348859bd2efSDavid Ahern 			if (skip_perm && n->nud_state & NUD_PERMANENT) {
349859bd2efSDavid Ahern 				np = &n->next;
350859bd2efSDavid Ahern 				continue;
351859bd2efSDavid Ahern 			}
352767e97e1SEric Dumazet 			rcu_assign_pointer(*np,
353767e97e1SEric Dumazet 				   rcu_dereference_protected(n->next,
354767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
3551da177e4SLinus Torvalds 			write_lock(&n->lock);
3561da177e4SLinus Torvalds 			neigh_del_timer(n);
35758956317SDavid Ahern 			neigh_mark_dead(n);
3589f237430SReshetova, Elena 			if (refcount_read(&n->refcnt) != 1) {
3591da177e4SLinus Torvalds 				/* The most unpleasant situation.
3601da177e4SLinus Torvalds 				   We must destroy neighbour entry,
3611da177e4SLinus Torvalds 				   but someone still uses it.
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds 				   The destroy will be delayed until
3641da177e4SLinus Torvalds 				   the last user releases us, but
3651da177e4SLinus Torvalds 				   we must kill timers etc. and move
3661da177e4SLinus Torvalds 				   it to safe state.
3671da177e4SLinus Torvalds 				 */
368c9ab4d85SEric Dumazet 				__skb_queue_purge(&n->arp_queue);
3698b5c171bSEric Dumazet 				n->arp_queue_len_bytes = 0;
3701da177e4SLinus Torvalds 				n->output = neigh_blackhole;
3711da177e4SLinus Torvalds 				if (n->nud_state & NUD_VALID)
3721da177e4SLinus Torvalds 					n->nud_state = NUD_NOARP;
3731da177e4SLinus Torvalds 				else
3741da177e4SLinus Torvalds 					n->nud_state = NUD_NONE;
375d5d427cdSJoe Perches 				neigh_dbg(2, "neigh %p is stray\n", n);
3761da177e4SLinus Torvalds 			}
3771da177e4SLinus Torvalds 			write_unlock(&n->lock);
3784f494554SThomas Graf 			neigh_cleanup_and_release(n);
3791da177e4SLinus Torvalds 		}
3801da177e4SLinus Torvalds 	}
38149636bb1SHerbert Xu }
3821da177e4SLinus Torvalds 
38349636bb1SHerbert Xu void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
38449636bb1SHerbert Xu {
38549636bb1SHerbert Xu 	write_lock_bh(&tbl->lock);
386859bd2efSDavid Ahern 	neigh_flush_dev(tbl, dev, false);
38749636bb1SHerbert Xu 	write_unlock_bh(&tbl->lock);
38849636bb1SHerbert Xu }
3890a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_changeaddr);
39049636bb1SHerbert Xu 
391859bd2efSDavid Ahern static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
392859bd2efSDavid Ahern 			  bool skip_perm)
39349636bb1SHerbert Xu {
39449636bb1SHerbert Xu 	write_lock_bh(&tbl->lock);
395859bd2efSDavid Ahern 	neigh_flush_dev(tbl, dev, skip_perm);
39653b76cdfSWolfgang Bumiller 	pneigh_ifdown_and_unlock(tbl, dev);
397*66ba215cSDenis V. Lunev 	pneigh_queue_purge(&tbl->proxy_queue, dev_net(dev));
398*66ba215cSDenis V. Lunev 	if (skb_queue_empty_lockless(&tbl->proxy_queue))
3991da177e4SLinus Torvalds 		del_timer_sync(&tbl->proxy_timer);
4001da177e4SLinus Torvalds 	return 0;
4011da177e4SLinus Torvalds }
402859bd2efSDavid Ahern 
403859bd2efSDavid Ahern int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev)
404859bd2efSDavid Ahern {
405859bd2efSDavid Ahern 	__neigh_ifdown(tbl, dev, true);
406859bd2efSDavid Ahern 	return 0;
407859bd2efSDavid Ahern }
408859bd2efSDavid Ahern EXPORT_SYMBOL(neigh_carrier_down);
409859bd2efSDavid Ahern 
410859bd2efSDavid Ahern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
411859bd2efSDavid Ahern {
412859bd2efSDavid Ahern 	__neigh_ifdown(tbl, dev, false);
413859bd2efSDavid Ahern 	return 0;
414859bd2efSDavid Ahern }
4150a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_ifdown);
4161da177e4SLinus Torvalds 
41758956317SDavid Ahern static struct neighbour *neigh_alloc(struct neigh_table *tbl,
41858956317SDavid Ahern 				     struct net_device *dev,
4192c611ad9SRoopa Prabhu 				     u32 flags, bool exempt_from_gc)
4201da177e4SLinus Torvalds {
4211da177e4SLinus Torvalds 	struct neighbour *n = NULL;
4221da177e4SLinus Torvalds 	unsigned long now = jiffies;
4231da177e4SLinus Torvalds 	int entries;
4241da177e4SLinus Torvalds 
425e997f8a2SDavid Ahern 	if (exempt_from_gc)
42658956317SDavid Ahern 		goto do_alloc;
42758956317SDavid Ahern 
42858956317SDavid Ahern 	entries = atomic_inc_return(&tbl->gc_entries) - 1;
4291da177e4SLinus Torvalds 	if (entries >= tbl->gc_thresh3 ||
4301da177e4SLinus Torvalds 	    (entries >= tbl->gc_thresh2 &&
4311da177e4SLinus Torvalds 	     time_after(now, tbl->last_flush + 5 * HZ))) {
4321da177e4SLinus Torvalds 		if (!neigh_forced_gc(tbl) &&
433fb811395SRick Jones 		    entries >= tbl->gc_thresh3) {
434fb811395SRick Jones 			net_info_ratelimited("%s: neighbor table overflow!\n",
435fb811395SRick Jones 					     tbl->id);
436fb811395SRick Jones 			NEIGH_CACHE_STAT_INC(tbl, table_fulls);
4371da177e4SLinus Torvalds 			goto out_entries;
4381da177e4SLinus Torvalds 		}
439fb811395SRick Jones 	}
4401da177e4SLinus Torvalds 
44158956317SDavid Ahern do_alloc:
44208433effSYOSHIFUJI Hideaki / 吉藤英明 	n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
4431da177e4SLinus Torvalds 	if (!n)
4441da177e4SLinus Torvalds 		goto out_entries;
4451da177e4SLinus Torvalds 
446c9ab4d85SEric Dumazet 	__skb_queue_head_init(&n->arp_queue);
4471da177e4SLinus Torvalds 	rwlock_init(&n->lock);
4480ed8ddf4SEric Dumazet 	seqlock_init(&n->ha_lock);
4491da177e4SLinus Torvalds 	n->updated	  = n->used = now;
4501da177e4SLinus Torvalds 	n->nud_state	  = NUD_NONE;
4511da177e4SLinus Torvalds 	n->output	  = neigh_blackhole;
452e4400bbfSDaniel Borkmann 	n->flags	  = flags;
453f6b72b62SDavid S. Miller 	seqlock_init(&n->hh.hh_lock);
4541da177e4SLinus Torvalds 	n->parms	  = neigh_parms_clone(&tbl->parms);
455e99e88a9SKees Cook 	timer_setup(&n->timer, neigh_timer_handler, 0);
4561da177e4SLinus Torvalds 
4571da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, allocs);
4581da177e4SLinus Torvalds 	n->tbl		  = tbl;
4599f237430SReshetova, Elena 	refcount_set(&n->refcnt, 1);
4601da177e4SLinus Torvalds 	n->dead		  = 1;
46158956317SDavid Ahern 	INIT_LIST_HEAD(&n->gc_list);
4627482e384SDaniel Borkmann 	INIT_LIST_HEAD(&n->managed_list);
46358956317SDavid Ahern 
46458956317SDavid Ahern 	atomic_inc(&tbl->entries);
4651da177e4SLinus Torvalds out:
4661da177e4SLinus Torvalds 	return n;
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds out_entries:
469e997f8a2SDavid Ahern 	if (!exempt_from_gc)
47058956317SDavid Ahern 		atomic_dec(&tbl->gc_entries);
4711da177e4SLinus Torvalds 	goto out;
4721da177e4SLinus Torvalds }
4731da177e4SLinus Torvalds 
4742c2aba6cSDavid S. Miller static void neigh_get_hash_rnd(u32 *x)
4752c2aba6cSDavid S. Miller {
476b3d0f789SJason A. Donenfeld 	*x = get_random_u32() | 1;
4772c2aba6cSDavid S. Miller }
4782c2aba6cSDavid S. Miller 
479cd089336SDavid S. Miller static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
4801da177e4SLinus Torvalds {
481cd089336SDavid S. Miller 	size_t size = (1 << shift) * sizeof(struct neighbour *);
482d6bf7817SEric Dumazet 	struct neigh_hash_table *ret;
4836193d2beSEric Dumazet 	struct neighbour __rcu **buckets;
4842c2aba6cSDavid S. Miller 	int i;
4851da177e4SLinus Torvalds 
486d6bf7817SEric Dumazet 	ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
487d6bf7817SEric Dumazet 	if (!ret)
488d6bf7817SEric Dumazet 		return NULL;
48985704cb8SKonstantin Khlebnikov 	if (size <= PAGE_SIZE) {
490d6bf7817SEric Dumazet 		buckets = kzalloc(size, GFP_ATOMIC);
49185704cb8SKonstantin Khlebnikov 	} else {
4926193d2beSEric Dumazet 		buckets = (struct neighbour __rcu **)
493d6bf7817SEric Dumazet 			  __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
494d6bf7817SEric Dumazet 					   get_order(size));
49501b833abSKonstantin Khlebnikov 		kmemleak_alloc(buckets, size, 1, GFP_ATOMIC);
49685704cb8SKonstantin Khlebnikov 	}
497d6bf7817SEric Dumazet 	if (!buckets) {
498d6bf7817SEric Dumazet 		kfree(ret);
499d6bf7817SEric Dumazet 		return NULL;
5001da177e4SLinus Torvalds 	}
5016193d2beSEric Dumazet 	ret->hash_buckets = buckets;
502cd089336SDavid S. Miller 	ret->hash_shift = shift;
5032c2aba6cSDavid S. Miller 	for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
5042c2aba6cSDavid S. Miller 		neigh_get_hash_rnd(&ret->hash_rnd[i]);
5051da177e4SLinus Torvalds 	return ret;
5061da177e4SLinus Torvalds }
5071da177e4SLinus Torvalds 
508d6bf7817SEric Dumazet static void neigh_hash_free_rcu(struct rcu_head *head)
5091da177e4SLinus Torvalds {
510d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = container_of(head,
511d6bf7817SEric Dumazet 						    struct neigh_hash_table,
512d6bf7817SEric Dumazet 						    rcu);
513cd089336SDavid S. Miller 	size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
5146193d2beSEric Dumazet 	struct neighbour __rcu **buckets = nht->hash_buckets;
5151da177e4SLinus Torvalds 
51685704cb8SKonstantin Khlebnikov 	if (size <= PAGE_SIZE) {
517d6bf7817SEric Dumazet 		kfree(buckets);
51885704cb8SKonstantin Khlebnikov 	} else {
51985704cb8SKonstantin Khlebnikov 		kmemleak_free(buckets);
520d6bf7817SEric Dumazet 		free_pages((unsigned long)buckets, get_order(size));
52185704cb8SKonstantin Khlebnikov 	}
522d6bf7817SEric Dumazet 	kfree(nht);
5231da177e4SLinus Torvalds }
5241da177e4SLinus Torvalds 
525d6bf7817SEric Dumazet static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
526cd089336SDavid S. Miller 						unsigned long new_shift)
5271da177e4SLinus Torvalds {
528d6bf7817SEric Dumazet 	unsigned int i, hash;
529d6bf7817SEric Dumazet 	struct neigh_hash_table *new_nht, *old_nht;
5301da177e4SLinus Torvalds 
5311da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, hash_grows);
5321da177e4SLinus Torvalds 
533d6bf7817SEric Dumazet 	old_nht = rcu_dereference_protected(tbl->nht,
534d6bf7817SEric Dumazet 					    lockdep_is_held(&tbl->lock));
535cd089336SDavid S. Miller 	new_nht = neigh_hash_alloc(new_shift);
536d6bf7817SEric Dumazet 	if (!new_nht)
537d6bf7817SEric Dumazet 		return old_nht;
5381da177e4SLinus Torvalds 
539cd089336SDavid S. Miller 	for (i = 0; i < (1 << old_nht->hash_shift); i++) {
5401da177e4SLinus Torvalds 		struct neighbour *n, *next;
5411da177e4SLinus Torvalds 
542767e97e1SEric Dumazet 		for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
543767e97e1SEric Dumazet 						   lockdep_is_held(&tbl->lock));
544d6bf7817SEric Dumazet 		     n != NULL;
545d6bf7817SEric Dumazet 		     n = next) {
546d6bf7817SEric Dumazet 			hash = tbl->hash(n->primary_key, n->dev,
547d6bf7817SEric Dumazet 					 new_nht->hash_rnd);
5481da177e4SLinus Torvalds 
549cd089336SDavid S. Miller 			hash >>= (32 - new_nht->hash_shift);
550767e97e1SEric Dumazet 			next = rcu_dereference_protected(n->next,
551767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock));
5521da177e4SLinus Torvalds 
553767e97e1SEric Dumazet 			rcu_assign_pointer(n->next,
554767e97e1SEric Dumazet 					   rcu_dereference_protected(
555767e97e1SEric Dumazet 						new_nht->hash_buckets[hash],
556767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
557767e97e1SEric Dumazet 			rcu_assign_pointer(new_nht->hash_buckets[hash], n);
5581da177e4SLinus Torvalds 		}
5591da177e4SLinus Torvalds 	}
5601da177e4SLinus Torvalds 
561d6bf7817SEric Dumazet 	rcu_assign_pointer(tbl->nht, new_nht);
562d6bf7817SEric Dumazet 	call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
563d6bf7817SEric Dumazet 	return new_nht;
5641da177e4SLinus Torvalds }
5651da177e4SLinus Torvalds 
5661da177e4SLinus Torvalds struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
5671da177e4SLinus Torvalds 			       struct net_device *dev)
5681da177e4SLinus Torvalds {
5691da177e4SLinus Torvalds 	struct neighbour *n;
5701da177e4SLinus Torvalds 
5711da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, lookups);
5721da177e4SLinus Torvalds 
573d6bf7817SEric Dumazet 	rcu_read_lock_bh();
57460395a20SEric W. Biederman 	n = __neigh_lookup_noref(tbl, pkey, dev);
57560395a20SEric W. Biederman 	if (n) {
5769f237430SReshetova, Elena 		if (!refcount_inc_not_zero(&n->refcnt))
577767e97e1SEric Dumazet 			n = NULL;
5781da177e4SLinus Torvalds 		NEIGH_CACHE_STAT_INC(tbl, hits);
5791da177e4SLinus Torvalds 	}
580767e97e1SEric Dumazet 
581d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
5821da177e4SLinus Torvalds 	return n;
5831da177e4SLinus Torvalds }
5840a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_lookup);
5851da177e4SLinus Torvalds 
586426b5303SEric W. Biederman struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
587426b5303SEric W. Biederman 				     const void *pkey)
5881da177e4SLinus Torvalds {
5891da177e4SLinus Torvalds 	struct neighbour *n;
59001ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
591bc4bf5f3SPavel Emelyanov 	u32 hash_val;
592d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
5931da177e4SLinus Torvalds 
5941da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, lookups);
5951da177e4SLinus Torvalds 
596d6bf7817SEric Dumazet 	rcu_read_lock_bh();
597d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
598cd089336SDavid S. Miller 	hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
599767e97e1SEric Dumazet 
600767e97e1SEric Dumazet 	for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
601767e97e1SEric Dumazet 	     n != NULL;
602767e97e1SEric Dumazet 	     n = rcu_dereference_bh(n->next)) {
603426b5303SEric W. Biederman 		if (!memcmp(n->primary_key, pkey, key_len) &&
604878628fbSYOSHIFUJI Hideaki 		    net_eq(dev_net(n->dev), net)) {
6059f237430SReshetova, Elena 			if (!refcount_inc_not_zero(&n->refcnt))
606767e97e1SEric Dumazet 				n = NULL;
6071da177e4SLinus Torvalds 			NEIGH_CACHE_STAT_INC(tbl, hits);
6081da177e4SLinus Torvalds 			break;
6091da177e4SLinus Torvalds 		}
6101da177e4SLinus Torvalds 	}
611767e97e1SEric Dumazet 
612d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
6131da177e4SLinus Torvalds 	return n;
6141da177e4SLinus Torvalds }
6150a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_lookup_nodev);
6161da177e4SLinus Torvalds 
617e4400bbfSDaniel Borkmann static struct neighbour *
618e4400bbfSDaniel Borkmann ___neigh_create(struct neigh_table *tbl, const void *pkey,
6192c611ad9SRoopa Prabhu 		struct net_device *dev, u32 flags,
620e997f8a2SDavid Ahern 		bool exempt_from_gc, bool want_ref)
6211da177e4SLinus Torvalds {
622e4400bbfSDaniel Borkmann 	u32 hash_val, key_len = tbl->key_len;
623e4400bbfSDaniel Borkmann 	struct neighbour *n1, *rc, *n;
624d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
625e4400bbfSDaniel Borkmann 	int error;
6261da177e4SLinus Torvalds 
627e4400bbfSDaniel Borkmann 	n = neigh_alloc(tbl, dev, flags, exempt_from_gc);
628fc651001SDavid Ahern 	trace_neigh_create(tbl, dev, pkey, n, exempt_from_gc);
6291da177e4SLinus Torvalds 	if (!n) {
6301da177e4SLinus Torvalds 		rc = ERR_PTR(-ENOBUFS);
6311da177e4SLinus Torvalds 		goto out;
6321da177e4SLinus Torvalds 	}
6331da177e4SLinus Torvalds 
6341da177e4SLinus Torvalds 	memcpy(n->primary_key, pkey, key_len);
6351da177e4SLinus Torvalds 	n->dev = dev;
636d62607c3SJakub Kicinski 	netdev_hold(dev, &n->dev_tracker, GFP_ATOMIC);
6371da177e4SLinus Torvalds 
6381da177e4SLinus Torvalds 	/* Protocol specific setup. */
6391da177e4SLinus Torvalds 	if (tbl->constructor &&	(error = tbl->constructor(n)) < 0) {
6401da177e4SLinus Torvalds 		rc = ERR_PTR(error);
6411da177e4SLinus Torvalds 		goto out_neigh_release;
6421da177e4SLinus Torvalds 	}
6431da177e4SLinus Torvalds 
644da6a8fa0SDavid Miller 	if (dev->netdev_ops->ndo_neigh_construct) {
645503eebc2SJiri Pirko 		error = dev->netdev_ops->ndo_neigh_construct(dev, n);
646da6a8fa0SDavid Miller 		if (error < 0) {
647da6a8fa0SDavid Miller 			rc = ERR_PTR(error);
648da6a8fa0SDavid Miller 			goto out_neigh_release;
649da6a8fa0SDavid Miller 		}
650da6a8fa0SDavid Miller 	}
651da6a8fa0SDavid Miller 
652447f2191SDavid S. Miller 	/* Device specific setup. */
653447f2191SDavid S. Miller 	if (n->parms->neigh_setup &&
654447f2191SDavid S. Miller 	    (error = n->parms->neigh_setup(n)) < 0) {
655447f2191SDavid S. Miller 		rc = ERR_PTR(error);
656447f2191SDavid S. Miller 		goto out_neigh_release;
657447f2191SDavid S. Miller 	}
658447f2191SDavid S. Miller 
6591f9248e5SJiri Pirko 	n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1);
6601da177e4SLinus Torvalds 
6611da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
662d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
663d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
6641da177e4SLinus Torvalds 
665cd089336SDavid S. Miller 	if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
666cd089336SDavid S. Miller 		nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
6671da177e4SLinus Torvalds 
668096b9854SJim Westfall 	hash_val = tbl->hash(n->primary_key, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
6691da177e4SLinus Torvalds 
6701da177e4SLinus Torvalds 	if (n->parms->dead) {
6711da177e4SLinus Torvalds 		rc = ERR_PTR(-EINVAL);
6721da177e4SLinus Torvalds 		goto out_tbl_unlock;
6731da177e4SLinus Torvalds 	}
6741da177e4SLinus Torvalds 
675767e97e1SEric Dumazet 	for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
676767e97e1SEric Dumazet 					    lockdep_is_held(&tbl->lock));
677767e97e1SEric Dumazet 	     n1 != NULL;
678767e97e1SEric Dumazet 	     n1 = rcu_dereference_protected(n1->next,
679767e97e1SEric Dumazet 			lockdep_is_held(&tbl->lock))) {
680096b9854SJim Westfall 		if (dev == n1->dev && !memcmp(n1->primary_key, n->primary_key, key_len)) {
681a263b309SDavid S. Miller 			if (want_ref)
6821da177e4SLinus Torvalds 				neigh_hold(n1);
6831da177e4SLinus Torvalds 			rc = n1;
6841da177e4SLinus Torvalds 			goto out_tbl_unlock;
6851da177e4SLinus Torvalds 		}
6861da177e4SLinus Torvalds 	}
6871da177e4SLinus Torvalds 
6881da177e4SLinus Torvalds 	n->dead = 0;
689e997f8a2SDavid Ahern 	if (!exempt_from_gc)
6908cc196d6SDavid Ahern 		list_add_tail(&n->gc_list, &n->tbl->gc_list);
6917482e384SDaniel Borkmann 	if (n->flags & NTF_MANAGED)
6927482e384SDaniel Borkmann 		list_add_tail(&n->managed_list, &n->tbl->managed_list);
693a263b309SDavid S. Miller 	if (want_ref)
6941da177e4SLinus Torvalds 		neigh_hold(n);
695767e97e1SEric Dumazet 	rcu_assign_pointer(n->next,
696767e97e1SEric Dumazet 			   rcu_dereference_protected(nht->hash_buckets[hash_val],
697767e97e1SEric Dumazet 						     lockdep_is_held(&tbl->lock)));
698767e97e1SEric Dumazet 	rcu_assign_pointer(nht->hash_buckets[hash_val], n);
6991da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
700d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is created\n", n);
7011da177e4SLinus Torvalds 	rc = n;
7021da177e4SLinus Torvalds out:
7031da177e4SLinus Torvalds 	return rc;
7041da177e4SLinus Torvalds out_tbl_unlock:
7051da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
7061da177e4SLinus Torvalds out_neigh_release:
70764c6f4bbSDavid Ahern 	if (!exempt_from_gc)
70864c6f4bbSDavid Ahern 		atomic_dec(&tbl->gc_entries);
7091da177e4SLinus Torvalds 	neigh_release(n);
7101da177e4SLinus Torvalds 	goto out;
7111da177e4SLinus Torvalds }
71258956317SDavid Ahern 
71358956317SDavid Ahern struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
71458956317SDavid Ahern 				 struct net_device *dev, bool want_ref)
71558956317SDavid Ahern {
716e4400bbfSDaniel Borkmann 	return ___neigh_create(tbl, pkey, dev, 0, false, want_ref);
71758956317SDavid Ahern }
718a263b309SDavid S. Miller EXPORT_SYMBOL(__neigh_create);
7191da177e4SLinus Torvalds 
72001ccdf12SAlexey Dobriyan static u32 pneigh_hash(const void *pkey, unsigned int key_len)
721fa86d322SPavel Emelyanov {
722fa86d322SPavel Emelyanov 	u32 hash_val = *(u32 *)(pkey + key_len - 4);
723fa86d322SPavel Emelyanov 	hash_val ^= (hash_val >> 16);
724fa86d322SPavel Emelyanov 	hash_val ^= hash_val >> 8;
725fa86d322SPavel Emelyanov 	hash_val ^= hash_val >> 4;
726fa86d322SPavel Emelyanov 	hash_val &= PNEIGH_HASHMASK;
727be01d655SYOSHIFUJI Hideaki 	return hash_val;
728fa86d322SPavel Emelyanov }
729fa86d322SPavel Emelyanov 
730be01d655SYOSHIFUJI Hideaki static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
731be01d655SYOSHIFUJI Hideaki 					      struct net *net,
732be01d655SYOSHIFUJI Hideaki 					      const void *pkey,
73301ccdf12SAlexey Dobriyan 					      unsigned int key_len,
734be01d655SYOSHIFUJI Hideaki 					      struct net_device *dev)
735be01d655SYOSHIFUJI Hideaki {
736be01d655SYOSHIFUJI Hideaki 	while (n) {
737be01d655SYOSHIFUJI Hideaki 		if (!memcmp(n->key, pkey, key_len) &&
738be01d655SYOSHIFUJI Hideaki 		    net_eq(pneigh_net(n), net) &&
739be01d655SYOSHIFUJI Hideaki 		    (n->dev == dev || !n->dev))
740fa86d322SPavel Emelyanov 			return n;
741be01d655SYOSHIFUJI Hideaki 		n = n->next;
742be01d655SYOSHIFUJI Hideaki 	}
743be01d655SYOSHIFUJI Hideaki 	return NULL;
744be01d655SYOSHIFUJI Hideaki }
745be01d655SYOSHIFUJI Hideaki 
746be01d655SYOSHIFUJI Hideaki struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
747be01d655SYOSHIFUJI Hideaki 		struct net *net, const void *pkey, struct net_device *dev)
748be01d655SYOSHIFUJI Hideaki {
74901ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
750be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
751be01d655SYOSHIFUJI Hideaki 
752be01d655SYOSHIFUJI Hideaki 	return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
753be01d655SYOSHIFUJI Hideaki 				 net, pkey, key_len, dev);
754fa86d322SPavel Emelyanov }
7550a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL_GPL(__pneigh_lookup);
756fa86d322SPavel Emelyanov 
757426b5303SEric W. Biederman struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
758426b5303SEric W. Biederman 				    struct net *net, const void *pkey,
7591da177e4SLinus Torvalds 				    struct net_device *dev, int creat)
7601da177e4SLinus Torvalds {
7611da177e4SLinus Torvalds 	struct pneigh_entry *n;
76201ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
763be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
7641da177e4SLinus Torvalds 
7651da177e4SLinus Torvalds 	read_lock_bh(&tbl->lock);
766be01d655SYOSHIFUJI Hideaki 	n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
767be01d655SYOSHIFUJI Hideaki 			      net, pkey, key_len, dev);
768be01d655SYOSHIFUJI Hideaki 	read_unlock_bh(&tbl->lock);
7691da177e4SLinus Torvalds 
770be01d655SYOSHIFUJI Hideaki 	if (n || !creat)
7711da177e4SLinus Torvalds 		goto out;
7721da177e4SLinus Torvalds 
7734ae28944SPavel Emelyanov 	ASSERT_RTNL();
7744ae28944SPavel Emelyanov 
775e195e9b5SEric Dumazet 	n = kzalloc(sizeof(*n) + key_len, GFP_KERNEL);
7761da177e4SLinus Torvalds 	if (!n)
7771da177e4SLinus Torvalds 		goto out;
7781da177e4SLinus Torvalds 
779efd7ef1cSEric W. Biederman 	write_pnet(&n->net, net);
7801da177e4SLinus Torvalds 	memcpy(n->key, pkey, key_len);
7811da177e4SLinus Torvalds 	n->dev = dev;
782d62607c3SJakub Kicinski 	netdev_hold(dev, &n->dev_tracker, GFP_KERNEL);
7831da177e4SLinus Torvalds 
7841da177e4SLinus Torvalds 	if (tbl->pconstructor && tbl->pconstructor(n)) {
785d62607c3SJakub Kicinski 		netdev_put(dev, &n->dev_tracker);
7861da177e4SLinus Torvalds 		kfree(n);
7871da177e4SLinus Torvalds 		n = NULL;
7881da177e4SLinus Torvalds 		goto out;
7891da177e4SLinus Torvalds 	}
7901da177e4SLinus Torvalds 
7911da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
7921da177e4SLinus Torvalds 	n->next = tbl->phash_buckets[hash_val];
7931da177e4SLinus Torvalds 	tbl->phash_buckets[hash_val] = n;
7941da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
7951da177e4SLinus Torvalds out:
7961da177e4SLinus Torvalds 	return n;
7971da177e4SLinus Torvalds }
7980a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(pneigh_lookup);
7991da177e4SLinus Torvalds 
8001da177e4SLinus Torvalds 
801426b5303SEric W. Biederman int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
8021da177e4SLinus Torvalds 		  struct net_device *dev)
8031da177e4SLinus Torvalds {
8041da177e4SLinus Torvalds 	struct pneigh_entry *n, **np;
80501ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
806be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
8071da177e4SLinus Torvalds 
8081da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
8091da177e4SLinus Torvalds 	for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
8101da177e4SLinus Torvalds 	     np = &n->next) {
811426b5303SEric W. Biederman 		if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
812878628fbSYOSHIFUJI Hideaki 		    net_eq(pneigh_net(n), net)) {
8131da177e4SLinus Torvalds 			*np = n->next;
8141da177e4SLinus Torvalds 			write_unlock_bh(&tbl->lock);
8151da177e4SLinus Torvalds 			if (tbl->pdestructor)
8161da177e4SLinus Torvalds 				tbl->pdestructor(n);
817d62607c3SJakub Kicinski 			netdev_put(n->dev, &n->dev_tracker);
8181da177e4SLinus Torvalds 			kfree(n);
8191da177e4SLinus Torvalds 			return 0;
8201da177e4SLinus Torvalds 		}
8211da177e4SLinus Torvalds 	}
8221da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
8231da177e4SLinus Torvalds 	return -ENOENT;
8241da177e4SLinus Torvalds }
8251da177e4SLinus Torvalds 
82653b76cdfSWolfgang Bumiller static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
82753b76cdfSWolfgang Bumiller 				    struct net_device *dev)
8281da177e4SLinus Torvalds {
82953b76cdfSWolfgang Bumiller 	struct pneigh_entry *n, **np, *freelist = NULL;
8301da177e4SLinus Torvalds 	u32 h;
8311da177e4SLinus Torvalds 
8321da177e4SLinus Torvalds 	for (h = 0; h <= PNEIGH_HASHMASK; h++) {
8331da177e4SLinus Torvalds 		np = &tbl->phash_buckets[h];
8341da177e4SLinus Torvalds 		while ((n = *np) != NULL) {
8351da177e4SLinus Torvalds 			if (!dev || n->dev == dev) {
8361da177e4SLinus Torvalds 				*np = n->next;
83753b76cdfSWolfgang Bumiller 				n->next = freelist;
83853b76cdfSWolfgang Bumiller 				freelist = n;
83953b76cdfSWolfgang Bumiller 				continue;
84053b76cdfSWolfgang Bumiller 			}
84153b76cdfSWolfgang Bumiller 			np = &n->next;
84253b76cdfSWolfgang Bumiller 		}
84353b76cdfSWolfgang Bumiller 	}
84453b76cdfSWolfgang Bumiller 	write_unlock_bh(&tbl->lock);
84553b76cdfSWolfgang Bumiller 	while ((n = freelist)) {
84653b76cdfSWolfgang Bumiller 		freelist = n->next;
84753b76cdfSWolfgang Bumiller 		n->next = NULL;
8481da177e4SLinus Torvalds 		if (tbl->pdestructor)
8491da177e4SLinus Torvalds 			tbl->pdestructor(n);
850d62607c3SJakub Kicinski 		netdev_put(n->dev, &n->dev_tracker);
8511da177e4SLinus Torvalds 		kfree(n);
8521da177e4SLinus Torvalds 	}
8531da177e4SLinus Torvalds 	return -ENOENT;
8541da177e4SLinus Torvalds }
8551da177e4SLinus Torvalds 
85606f0511dSDenis V. Lunev static void neigh_parms_destroy(struct neigh_parms *parms);
85706f0511dSDenis V. Lunev 
85806f0511dSDenis V. Lunev static inline void neigh_parms_put(struct neigh_parms *parms)
85906f0511dSDenis V. Lunev {
8606343944bSReshetova, Elena 	if (refcount_dec_and_test(&parms->refcnt))
86106f0511dSDenis V. Lunev 		neigh_parms_destroy(parms);
86206f0511dSDenis V. Lunev }
8631da177e4SLinus Torvalds 
8641da177e4SLinus Torvalds /*
8651da177e4SLinus Torvalds  *	neighbour must already be out of the table;
8661da177e4SLinus Torvalds  *
8671da177e4SLinus Torvalds  */
8681da177e4SLinus Torvalds void neigh_destroy(struct neighbour *neigh)
8691da177e4SLinus Torvalds {
870da6a8fa0SDavid Miller 	struct net_device *dev = neigh->dev;
871da6a8fa0SDavid Miller 
8721da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
8731da177e4SLinus Torvalds 
8741da177e4SLinus Torvalds 	if (!neigh->dead) {
875e005d193SJoe Perches 		pr_warn("Destroying alive neighbour %p\n", neigh);
8761da177e4SLinus Torvalds 		dump_stack();
8771da177e4SLinus Torvalds 		return;
8781da177e4SLinus Torvalds 	}
8791da177e4SLinus Torvalds 
8801da177e4SLinus Torvalds 	if (neigh_del_timer(neigh))
881e005d193SJoe Perches 		pr_warn("Impossible event\n");
8821da177e4SLinus Torvalds 
883c9ab4d85SEric Dumazet 	write_lock_bh(&neigh->lock);
884c9ab4d85SEric Dumazet 	__skb_queue_purge(&neigh->arp_queue);
885c9ab4d85SEric Dumazet 	write_unlock_bh(&neigh->lock);
8868b5c171bSEric Dumazet 	neigh->arp_queue_len_bytes = 0;
8871da177e4SLinus Torvalds 
888447f2191SDavid S. Miller 	if (dev->netdev_ops->ndo_neigh_destroy)
889503eebc2SJiri Pirko 		dev->netdev_ops->ndo_neigh_destroy(dev, neigh);
890447f2191SDavid S. Miller 
891d62607c3SJakub Kicinski 	netdev_put(dev, &neigh->dev_tracker);
8921da177e4SLinus Torvalds 	neigh_parms_put(neigh->parms);
8931da177e4SLinus Torvalds 
894d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is destroyed\n", neigh);
8951da177e4SLinus Torvalds 
8961da177e4SLinus Torvalds 	atomic_dec(&neigh->tbl->entries);
8975b8b0060SDavid Miller 	kfree_rcu(neigh, rcu);
8981da177e4SLinus Torvalds }
8990a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_destroy);
9001da177e4SLinus Torvalds 
9011da177e4SLinus Torvalds /* Neighbour state is suspicious;
9021da177e4SLinus Torvalds    disable fast path.
9031da177e4SLinus Torvalds 
9041da177e4SLinus Torvalds    Called with write_locked neigh.
9051da177e4SLinus Torvalds  */
9061da177e4SLinus Torvalds static void neigh_suspect(struct neighbour *neigh)
9071da177e4SLinus Torvalds {
908d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is suspected\n", neigh);
9091da177e4SLinus Torvalds 
9101da177e4SLinus Torvalds 	neigh->output = neigh->ops->output;
9111da177e4SLinus Torvalds }
9121da177e4SLinus Torvalds 
9131da177e4SLinus Torvalds /* Neighbour state is OK;
9141da177e4SLinus Torvalds    enable fast path.
9151da177e4SLinus Torvalds 
9161da177e4SLinus Torvalds    Called with write_locked neigh.
9171da177e4SLinus Torvalds  */
9181da177e4SLinus Torvalds static void neigh_connect(struct neighbour *neigh)
9191da177e4SLinus Torvalds {
920d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is connected\n", neigh);
9211da177e4SLinus Torvalds 
9221da177e4SLinus Torvalds 	neigh->output = neigh->ops->connected_output;
9231da177e4SLinus Torvalds }
9241da177e4SLinus Torvalds 
925e4c4e448SEric Dumazet static void neigh_periodic_work(struct work_struct *work)
9261da177e4SLinus Torvalds {
927e4c4e448SEric Dumazet 	struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
928767e97e1SEric Dumazet 	struct neighbour *n;
929767e97e1SEric Dumazet 	struct neighbour __rcu **np;
930e4c4e448SEric Dumazet 	unsigned int i;
931d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
9321da177e4SLinus Torvalds 
9331da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
9341da177e4SLinus Torvalds 
935e4c4e448SEric Dumazet 	write_lock_bh(&tbl->lock);
936d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
937d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
9381da177e4SLinus Torvalds 
9391da177e4SLinus Torvalds 	/*
9401da177e4SLinus Torvalds 	 *	periodically recompute ReachableTime from random function
9411da177e4SLinus Torvalds 	 */
9421da177e4SLinus Torvalds 
943e4c4e448SEric Dumazet 	if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
9441da177e4SLinus Torvalds 		struct neigh_parms *p;
945e4c4e448SEric Dumazet 		tbl->last_rand = jiffies;
94675fbfd33SNicolas Dichtel 		list_for_each_entry(p, &tbl->parms_list, list)
9471da177e4SLinus Torvalds 			p->reachable_time =
9481f9248e5SJiri Pirko 				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
9491da177e4SLinus Torvalds 	}
9501da177e4SLinus Torvalds 
951feff9ab2SDuan Jiong 	if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
952feff9ab2SDuan Jiong 		goto out;
953feff9ab2SDuan Jiong 
954cd089336SDavid S. Miller 	for (i = 0 ; i < (1 << nht->hash_shift); i++) {
955d6bf7817SEric Dumazet 		np = &nht->hash_buckets[i];
9561da177e4SLinus Torvalds 
957767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
958767e97e1SEric Dumazet 				lockdep_is_held(&tbl->lock))) != NULL) {
9591da177e4SLinus Torvalds 			unsigned int state;
9601da177e4SLinus Torvalds 
9611da177e4SLinus Torvalds 			write_lock(&n->lock);
9621da177e4SLinus Torvalds 
9631da177e4SLinus Torvalds 			state = n->nud_state;
9649ce33e46SRoopa Prabhu 			if ((state & (NUD_PERMANENT | NUD_IN_TIMER)) ||
9659ce33e46SRoopa Prabhu 			    (n->flags & NTF_EXT_LEARNED)) {
9661da177e4SLinus Torvalds 				write_unlock(&n->lock);
9671da177e4SLinus Torvalds 				goto next_elt;
9681da177e4SLinus Torvalds 			}
9691da177e4SLinus Torvalds 
9701da177e4SLinus Torvalds 			if (time_before(n->used, n->confirmed))
9711da177e4SLinus Torvalds 				n->used = n->confirmed;
9721da177e4SLinus Torvalds 
9739f237430SReshetova, Elena 			if (refcount_read(&n->refcnt) == 1 &&
9741da177e4SLinus Torvalds 			    (state == NUD_FAILED ||
9751f9248e5SJiri Pirko 			     time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
9761da177e4SLinus Torvalds 				*np = n->next;
97758956317SDavid Ahern 				neigh_mark_dead(n);
9781da177e4SLinus Torvalds 				write_unlock(&n->lock);
9794f494554SThomas Graf 				neigh_cleanup_and_release(n);
9801da177e4SLinus Torvalds 				continue;
9811da177e4SLinus Torvalds 			}
9821da177e4SLinus Torvalds 			write_unlock(&n->lock);
9831da177e4SLinus Torvalds 
9841da177e4SLinus Torvalds next_elt:
9851da177e4SLinus Torvalds 			np = &n->next;
9861da177e4SLinus Torvalds 		}
987e4c4e448SEric Dumazet 		/*
988e4c4e448SEric Dumazet 		 * It's fine to release lock here, even if hash table
989e4c4e448SEric Dumazet 		 * grows while we are preempted.
990e4c4e448SEric Dumazet 		 */
991e4c4e448SEric Dumazet 		write_unlock_bh(&tbl->lock);
992e4c4e448SEric Dumazet 		cond_resched();
993e4c4e448SEric Dumazet 		write_lock_bh(&tbl->lock);
99484338a6cSMichel Machado 		nht = rcu_dereference_protected(tbl->nht,
99584338a6cSMichel Machado 						lockdep_is_held(&tbl->lock));
996e4c4e448SEric Dumazet 	}
9972724680bSYOSHIFUJI Hideaki / 吉藤英明 out:
9981f9248e5SJiri Pirko 	/* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks.
9991f9248e5SJiri Pirko 	 * ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2
10001f9248e5SJiri Pirko 	 * BASE_REACHABLE_TIME.
10011da177e4SLinus Torvalds 	 */
1002f618002bSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
10031f9248e5SJiri Pirko 			      NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1);
1004e4c4e448SEric Dumazet 	write_unlock_bh(&tbl->lock);
10051da177e4SLinus Torvalds }
10061da177e4SLinus Torvalds 
10071da177e4SLinus Torvalds static __inline__ int neigh_max_probes(struct neighbour *n)
10081da177e4SLinus Torvalds {
10091da177e4SLinus Torvalds 	struct neigh_parms *p = n->parms;
10108da86466SYOSHIFUJI Hideaki/吉藤英明 	return NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) +
10118da86466SYOSHIFUJI Hideaki/吉藤英明 	       (n->nud_state & NUD_PROBE ? NEIGH_VAR(p, MCAST_REPROBES) :
10128da86466SYOSHIFUJI Hideaki/吉藤英明 	        NEIGH_VAR(p, MCAST_PROBES));
10131da177e4SLinus Torvalds }
10141da177e4SLinus Torvalds 
10155ef12d98STimo Teras static void neigh_invalidate(struct neighbour *neigh)
10160a141509SEric Dumazet 	__releases(neigh->lock)
10170a141509SEric Dumazet 	__acquires(neigh->lock)
10185ef12d98STimo Teras {
10195ef12d98STimo Teras 	struct sk_buff *skb;
10205ef12d98STimo Teras 
10215ef12d98STimo Teras 	NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
1022d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is failed\n", neigh);
10235ef12d98STimo Teras 	neigh->updated = jiffies;
10245ef12d98STimo Teras 
10255ef12d98STimo Teras 	/* It is very thin place. report_unreachable is very complicated
10265ef12d98STimo Teras 	   routine. Particularly, it can hit the same neighbour entry!
10275ef12d98STimo Teras 
10285ef12d98STimo Teras 	   So that, we try to be accurate and avoid dead loop. --ANK
10295ef12d98STimo Teras 	 */
10305ef12d98STimo Teras 	while (neigh->nud_state == NUD_FAILED &&
10315ef12d98STimo Teras 	       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
10325ef12d98STimo Teras 		write_unlock(&neigh->lock);
10335ef12d98STimo Teras 		neigh->ops->error_report(neigh, skb);
10345ef12d98STimo Teras 		write_lock(&neigh->lock);
10355ef12d98STimo Teras 	}
1036c9ab4d85SEric Dumazet 	__skb_queue_purge(&neigh->arp_queue);
10378b5c171bSEric Dumazet 	neigh->arp_queue_len_bytes = 0;
10385ef12d98STimo Teras }
10395ef12d98STimo Teras 
1040cd28ca0aSEric Dumazet static void neigh_probe(struct neighbour *neigh)
1041cd28ca0aSEric Dumazet 	__releases(neigh->lock)
1042cd28ca0aSEric Dumazet {
10434ed377e3SHannes Frederic Sowa 	struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);
1044cd28ca0aSEric Dumazet 	/* keep skb alive even if arp_queue overflows */
1045cd28ca0aSEric Dumazet 	if (skb)
104619125c1aSMartin Zhang 		skb = skb_clone(skb, GFP_ATOMIC);
1047cd28ca0aSEric Dumazet 	write_unlock(&neigh->lock);
104848481c8fSEric Dumazet 	if (neigh->ops->solicit)
1049cd28ca0aSEric Dumazet 		neigh->ops->solicit(neigh, skb);
1050cd28ca0aSEric Dumazet 	atomic_inc(&neigh->probes);
105187fff3caSYang Wei 	consume_skb(skb);
1052cd28ca0aSEric Dumazet }
1053cd28ca0aSEric Dumazet 
10541da177e4SLinus Torvalds /* Called when a timer expires for a neighbour entry. */
10551da177e4SLinus Torvalds 
1056e99e88a9SKees Cook static void neigh_timer_handler(struct timer_list *t)
10571da177e4SLinus Torvalds {
10581da177e4SLinus Torvalds 	unsigned long now, next;
1059e99e88a9SKees Cook 	struct neighbour *neigh = from_timer(neigh, t, timer);
106095c96174SEric Dumazet 	unsigned int state;
10611da177e4SLinus Torvalds 	int notify = 0;
10621da177e4SLinus Torvalds 
10631da177e4SLinus Torvalds 	write_lock(&neigh->lock);
10641da177e4SLinus Torvalds 
10651da177e4SLinus Torvalds 	state = neigh->nud_state;
10661da177e4SLinus Torvalds 	now = jiffies;
10671da177e4SLinus Torvalds 	next = now + HZ;
10681da177e4SLinus Torvalds 
1069045f7b3bSDavid S. Miller 	if (!(state & NUD_IN_TIMER))
10701da177e4SLinus Torvalds 		goto out;
10711da177e4SLinus Torvalds 
10721da177e4SLinus Torvalds 	if (state & NUD_REACHABLE) {
10731da177e4SLinus Torvalds 		if (time_before_eq(now,
10741da177e4SLinus Torvalds 				   neigh->confirmed + neigh->parms->reachable_time)) {
1075d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is still alive\n", neigh);
10761da177e4SLinus Torvalds 			next = neigh->confirmed + neigh->parms->reachable_time;
10771da177e4SLinus Torvalds 		} else if (time_before_eq(now,
10781f9248e5SJiri Pirko 					  neigh->used +
10791f9248e5SJiri Pirko 					  NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
1080d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is delayed\n", neigh);
10811da177e4SLinus Torvalds 			neigh->nud_state = NUD_DELAY;
1082955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10831da177e4SLinus Torvalds 			neigh_suspect(neigh);
10841f9248e5SJiri Pirko 			next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME);
10851da177e4SLinus Torvalds 		} else {
1086d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is suspected\n", neigh);
10871da177e4SLinus Torvalds 			neigh->nud_state = NUD_STALE;
1088955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10891da177e4SLinus Torvalds 			neigh_suspect(neigh);
10908d71740cSTom Tucker 			notify = 1;
10911da177e4SLinus Torvalds 		}
10921da177e4SLinus Torvalds 	} else if (state & NUD_DELAY) {
10931da177e4SLinus Torvalds 		if (time_before_eq(now,
10941f9248e5SJiri Pirko 				   neigh->confirmed +
10951f9248e5SJiri Pirko 				   NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
1096d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is now reachable\n", neigh);
10971da177e4SLinus Torvalds 			neigh->nud_state = NUD_REACHABLE;
1098955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10991da177e4SLinus Torvalds 			neigh_connect(neigh);
11008d71740cSTom Tucker 			notify = 1;
11011da177e4SLinus Torvalds 			next = neigh->confirmed + neigh->parms->reachable_time;
11021da177e4SLinus Torvalds 		} else {
1103d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is probed\n", neigh);
11041da177e4SLinus Torvalds 			neigh->nud_state = NUD_PROBE;
1105955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
11061da177e4SLinus Torvalds 			atomic_set(&neigh->probes, 0);
1107765c9c63SErik Kline 			notify = 1;
110819e16d22SHangbin Liu 			next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
110919e16d22SHangbin Liu 					 HZ/100);
11101da177e4SLinus Torvalds 		}
11111da177e4SLinus Torvalds 	} else {
11121da177e4SLinus Torvalds 		/* NUD_PROBE|NUD_INCOMPLETE */
111319e16d22SHangbin Liu 		next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME), HZ/100);
11141da177e4SLinus Torvalds 	}
11151da177e4SLinus Torvalds 
11161da177e4SLinus Torvalds 	if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
11171da177e4SLinus Torvalds 	    atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
11181da177e4SLinus Torvalds 		neigh->nud_state = NUD_FAILED;
11191da177e4SLinus Torvalds 		notify = 1;
11205ef12d98STimo Teras 		neigh_invalidate(neigh);
11215e2c21dcSDuan Jiong 		goto out;
11221da177e4SLinus Torvalds 	}
11231da177e4SLinus Torvalds 
11241da177e4SLinus Torvalds 	if (neigh->nud_state & NUD_IN_TIMER) {
112596d10d5bSHangbin Liu 		if (time_before(next, jiffies + HZ/100))
112696d10d5bSHangbin Liu 			next = jiffies + HZ/100;
11276fb9974fSHerbert Xu 		if (!mod_timer(&neigh->timer, next))
11286fb9974fSHerbert Xu 			neigh_hold(neigh);
11291da177e4SLinus Torvalds 	}
11301da177e4SLinus Torvalds 	if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
1131cd28ca0aSEric Dumazet 		neigh_probe(neigh);
11329ff56607SDavid S. Miller 	} else {
11331da177e4SLinus Torvalds out:
11341da177e4SLinus Torvalds 		write_unlock(&neigh->lock);
11359ff56607SDavid S. Miller 	}
11361da177e4SLinus Torvalds 
1137d961db35SThomas Graf 	if (notify)
11387b8f7a40SRoopa Prabhu 		neigh_update_notify(neigh, 0);
1139d961db35SThomas Graf 
114056dd18a4SRoopa Prabhu 	trace_neigh_timer_handler(neigh, 0);
114156dd18a4SRoopa Prabhu 
11421da177e4SLinus Torvalds 	neigh_release(neigh);
11431da177e4SLinus Torvalds }
11441da177e4SLinus Torvalds 
11454a81f6daSDaniel Borkmann int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb,
11464a81f6daSDaniel Borkmann 		       const bool immediate_ok)
11471da177e4SLinus Torvalds {
11481da177e4SLinus Torvalds 	int rc;
1149cd28ca0aSEric Dumazet 	bool immediate_probe = false;
11501da177e4SLinus Torvalds 
11511da177e4SLinus Torvalds 	write_lock_bh(&neigh->lock);
11521da177e4SLinus Torvalds 
11531da177e4SLinus Torvalds 	rc = 0;
11541da177e4SLinus Torvalds 	if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
11551da177e4SLinus Torvalds 		goto out_unlock_bh;
11562c51a97fSJulian Anastasov 	if (neigh->dead)
11572c51a97fSJulian Anastasov 		goto out_dead;
11581da177e4SLinus Torvalds 
11591da177e4SLinus Torvalds 	if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
11601f9248e5SJiri Pirko 		if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
11611f9248e5SJiri Pirko 		    NEIGH_VAR(neigh->parms, APP_PROBES)) {
1162cd28ca0aSEric Dumazet 			unsigned long next, now = jiffies;
1163cd28ca0aSEric Dumazet 
11641f9248e5SJiri Pirko 			atomic_set(&neigh->probes,
11651f9248e5SJiri Pirko 				   NEIGH_VAR(neigh->parms, UCAST_PROBES));
1166071c3798SLorenzo Bianconi 			neigh_del_timer(neigh);
11671da177e4SLinus Torvalds 			neigh->nud_state = NUD_INCOMPLETE;
1168cd28ca0aSEric Dumazet 			neigh->updated = now;
11694a81f6daSDaniel Borkmann 			if (!immediate_ok) {
11704a81f6daSDaniel Borkmann 				next = now + 1;
11714a81f6daSDaniel Borkmann 			} else {
1172cd28ca0aSEric Dumazet 				immediate_probe = true;
11734a81f6daSDaniel Borkmann 				next = now + max(NEIGH_VAR(neigh->parms,
11744a81f6daSDaniel Borkmann 							   RETRANS_TIME),
11754a81f6daSDaniel Borkmann 						 HZ / 100);
11764a81f6daSDaniel Borkmann 			}
11774a81f6daSDaniel Borkmann 			neigh_add_timer(neigh, next);
11781da177e4SLinus Torvalds 		} else {
11791da177e4SLinus Torvalds 			neigh->nud_state = NUD_FAILED;
1180955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
11811da177e4SLinus Torvalds 			write_unlock_bh(&neigh->lock);
11821da177e4SLinus Torvalds 
1183a5736eddSMenglong Dong 			kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_FAILED);
11841da177e4SLinus Torvalds 			return 1;
11851da177e4SLinus Torvalds 		}
11861da177e4SLinus Torvalds 	} else if (neigh->nud_state & NUD_STALE) {
1187d5d427cdSJoe Perches 		neigh_dbg(2, "neigh %p is delayed\n", neigh);
1188071c3798SLorenzo Bianconi 		neigh_del_timer(neigh);
11891da177e4SLinus Torvalds 		neigh->nud_state = NUD_DELAY;
1190955aaa2fSYOSHIFUJI Hideaki 		neigh->updated = jiffies;
11911f9248e5SJiri Pirko 		neigh_add_timer(neigh, jiffies +
11921f9248e5SJiri Pirko 				NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME));
11931da177e4SLinus Torvalds 	}
11941da177e4SLinus Torvalds 
11951da177e4SLinus Torvalds 	if (neigh->nud_state == NUD_INCOMPLETE) {
11961da177e4SLinus Torvalds 		if (skb) {
11978b5c171bSEric Dumazet 			while (neigh->arp_queue_len_bytes + skb->truesize >
11981f9248e5SJiri Pirko 			       NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) {
11991da177e4SLinus Torvalds 				struct sk_buff *buff;
12008b5c171bSEric Dumazet 
1201f72051b0SDavid S. Miller 				buff = __skb_dequeue(&neigh->arp_queue);
12028b5c171bSEric Dumazet 				if (!buff)
12038b5c171bSEric Dumazet 					break;
12048b5c171bSEric Dumazet 				neigh->arp_queue_len_bytes -= buff->truesize;
1205a5736eddSMenglong Dong 				kfree_skb_reason(buff, SKB_DROP_REASON_NEIGH_QUEUEFULL);
12069a6d276eSNeil Horman 				NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
12071da177e4SLinus Torvalds 			}
1208a4731138SEric Dumazet 			skb_dst_force(skb);
12091da177e4SLinus Torvalds 			__skb_queue_tail(&neigh->arp_queue, skb);
12108b5c171bSEric Dumazet 			neigh->arp_queue_len_bytes += skb->truesize;
12111da177e4SLinus Torvalds 		}
12121da177e4SLinus Torvalds 		rc = 1;
12131da177e4SLinus Torvalds 	}
12141da177e4SLinus Torvalds out_unlock_bh:
1215cd28ca0aSEric Dumazet 	if (immediate_probe)
1216cd28ca0aSEric Dumazet 		neigh_probe(neigh);
1217cd28ca0aSEric Dumazet 	else
1218cd28ca0aSEric Dumazet 		write_unlock(&neigh->lock);
1219cd28ca0aSEric Dumazet 	local_bh_enable();
122056dd18a4SRoopa Prabhu 	trace_neigh_event_send_done(neigh, rc);
12211da177e4SLinus Torvalds 	return rc;
12222c51a97fSJulian Anastasov 
12232c51a97fSJulian Anastasov out_dead:
12242c51a97fSJulian Anastasov 	if (neigh->nud_state & NUD_STALE)
12252c51a97fSJulian Anastasov 		goto out_unlock_bh;
12262c51a97fSJulian Anastasov 	write_unlock_bh(&neigh->lock);
1227a5736eddSMenglong Dong 	kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_DEAD);
122856dd18a4SRoopa Prabhu 	trace_neigh_event_send_dead(neigh, 1);
12292c51a97fSJulian Anastasov 	return 1;
12301da177e4SLinus Torvalds }
12310a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(__neigh_event_send);
12321da177e4SLinus Torvalds 
1233f6b72b62SDavid S. Miller static void neigh_update_hhs(struct neighbour *neigh)
12341da177e4SLinus Torvalds {
12351da177e4SLinus Torvalds 	struct hh_cache *hh;
12363b04dddeSStephen Hemminger 	void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
123791a72a70SDoug Kehn 		= NULL;
123891a72a70SDoug Kehn 
123991a72a70SDoug Kehn 	if (neigh->dev->header_ops)
124091a72a70SDoug Kehn 		update = neigh->dev->header_ops->cache_update;
12411da177e4SLinus Torvalds 
12421da177e4SLinus Torvalds 	if (update) {
1243f6b72b62SDavid S. Miller 		hh = &neigh->hh;
1244c305c6aeSEric Dumazet 		if (READ_ONCE(hh->hh_len)) {
12453644f0ceSStephen Hemminger 			write_seqlock_bh(&hh->hh_lock);
12461da177e4SLinus Torvalds 			update(hh, neigh->dev, neigh->ha);
12473644f0ceSStephen Hemminger 			write_sequnlock_bh(&hh->hh_lock);
12481da177e4SLinus Torvalds 		}
12491da177e4SLinus Torvalds 	}
12501da177e4SLinus Torvalds }
12511da177e4SLinus Torvalds 
12521da177e4SLinus Torvalds /* Generic update routine.
12531da177e4SLinus Torvalds    -- lladdr is new lladdr or NULL, if it is not supplied.
12541da177e4SLinus Torvalds    -- new    is new state.
12551da177e4SLinus Torvalds    -- flags
12561da177e4SLinus Torvalds 	NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
12571da177e4SLinus Torvalds 				if it is different.
12581da177e4SLinus Torvalds 	NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
12591da177e4SLinus Torvalds 				lladdr instead of overriding it
12601da177e4SLinus Torvalds 				if it is different.
12611da177e4SLinus Torvalds 	NEIGH_UPDATE_F_ADMIN	means that the change is administrative.
12623dc20f47SDaniel Borkmann 	NEIGH_UPDATE_F_USE	means that the entry is user triggered.
12637482e384SDaniel Borkmann 	NEIGH_UPDATE_F_MANAGED	means that the entry will be auto-refreshed.
12641da177e4SLinus Torvalds 	NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
12651da177e4SLinus Torvalds 				NTF_ROUTER flag.
12661da177e4SLinus Torvalds 	NEIGH_UPDATE_F_ISROUTER	indicates if the neighbour is known as
12671da177e4SLinus Torvalds 				a router.
12681da177e4SLinus Torvalds 
12691da177e4SLinus Torvalds    Caller MUST hold reference count on the entry.
12701da177e4SLinus Torvalds  */
12717a35a50dSDavid Ahern static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
12727a35a50dSDavid Ahern 			  u8 new, u32 flags, u32 nlmsg_pid,
12737a35a50dSDavid Ahern 			  struct netlink_ext_ack *extack)
12741da177e4SLinus Torvalds {
12757482e384SDaniel Borkmann 	bool gc_update = false, managed_update = false;
12761da177e4SLinus Torvalds 	int update_isrouter = 0;
12777482e384SDaniel Borkmann 	struct net_device *dev;
12787482e384SDaniel Borkmann 	int err, notify = 0;
12797482e384SDaniel Borkmann 	u8 old;
12801da177e4SLinus Torvalds 
128156dd18a4SRoopa Prabhu 	trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid);
128256dd18a4SRoopa Prabhu 
12831da177e4SLinus Torvalds 	write_lock_bh(&neigh->lock);
12841da177e4SLinus Torvalds 
12851da177e4SLinus Torvalds 	dev    = neigh->dev;
12861da177e4SLinus Torvalds 	old    = neigh->nud_state;
12871da177e4SLinus Torvalds 	err    = -EPERM;
12881da177e4SLinus Torvalds 
1289eb4e8facSChinmay Agarwal 	if (neigh->dead) {
1290eb4e8facSChinmay Agarwal 		NL_SET_ERR_MSG(extack, "Neighbor entry is now dead");
1291eb4e8facSChinmay Agarwal 		new = old;
1292eb4e8facSChinmay Agarwal 		goto out;
1293eb4e8facSChinmay Agarwal 	}
12941da177e4SLinus Torvalds 	if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
12951da177e4SLinus Torvalds 	    (old & (NUD_NOARP | NUD_PERMANENT)))
12961da177e4SLinus Torvalds 		goto out;
12971da177e4SLinus Torvalds 
12987482e384SDaniel Borkmann 	neigh_update_flags(neigh, flags, &notify, &gc_update, &managed_update);
12997482e384SDaniel Borkmann 	if (flags & (NEIGH_UPDATE_F_USE | NEIGH_UPDATE_F_MANAGED)) {
13003dc20f47SDaniel Borkmann 		new = old & ~NUD_PERMANENT;
13013dc20f47SDaniel Borkmann 		neigh->nud_state = new;
13023dc20f47SDaniel Borkmann 		err = 0;
13033dc20f47SDaniel Borkmann 		goto out;
13043dc20f47SDaniel Borkmann 	}
13059ce33e46SRoopa Prabhu 
13061da177e4SLinus Torvalds 	if (!(new & NUD_VALID)) {
13071da177e4SLinus Torvalds 		neigh_del_timer(neigh);
13081da177e4SLinus Torvalds 		if (old & NUD_CONNECTED)
13091da177e4SLinus Torvalds 			neigh_suspect(neigh);
13109c29a2f5SDavid Ahern 		neigh->nud_state = new;
13111da177e4SLinus Torvalds 		err = 0;
13121da177e4SLinus Torvalds 		notify = old & NUD_VALID;
1313d2fb4fb8SRoopa Prabhu 		if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
13145ef12d98STimo Teras 		    (new & NUD_FAILED)) {
13155ef12d98STimo Teras 			neigh_invalidate(neigh);
13165ef12d98STimo Teras 			notify = 1;
13175ef12d98STimo Teras 		}
13181da177e4SLinus Torvalds 		goto out;
13191da177e4SLinus Torvalds 	}
13201da177e4SLinus Torvalds 
13211da177e4SLinus Torvalds 	/* Compare new lladdr with cached one */
13221da177e4SLinus Torvalds 	if (!dev->addr_len) {
13231da177e4SLinus Torvalds 		/* First case: device needs no address. */
13241da177e4SLinus Torvalds 		lladdr = neigh->ha;
13251da177e4SLinus Torvalds 	} else if (lladdr) {
13261da177e4SLinus Torvalds 		/* The second case: if something is already cached
13271da177e4SLinus Torvalds 		   and a new address is proposed:
13281da177e4SLinus Torvalds 		   - compare new & old
13291da177e4SLinus Torvalds 		   - if they are different, check override flag
13301da177e4SLinus Torvalds 		 */
13311da177e4SLinus Torvalds 		if ((old & NUD_VALID) &&
13321da177e4SLinus Torvalds 		    !memcmp(lladdr, neigh->ha, dev->addr_len))
13331da177e4SLinus Torvalds 			lladdr = neigh->ha;
13341da177e4SLinus Torvalds 	} else {
13351da177e4SLinus Torvalds 		/* No address is supplied; if we know something,
13361da177e4SLinus Torvalds 		   use it, otherwise discard the request.
13371da177e4SLinus Torvalds 		 */
13381da177e4SLinus Torvalds 		err = -EINVAL;
13397a35a50dSDavid Ahern 		if (!(old & NUD_VALID)) {
13407a35a50dSDavid Ahern 			NL_SET_ERR_MSG(extack, "No link layer address given");
13411da177e4SLinus Torvalds 			goto out;
13427a35a50dSDavid Ahern 		}
13431da177e4SLinus Torvalds 		lladdr = neigh->ha;
13441da177e4SLinus Torvalds 	}
13451da177e4SLinus Torvalds 
1346f0e0d044SVasily Khoruzhick 	/* Update confirmed timestamp for neighbour entry after we
1347f0e0d044SVasily Khoruzhick 	 * received ARP packet even if it doesn't change IP to MAC binding.
1348f0e0d044SVasily Khoruzhick 	 */
1349f0e0d044SVasily Khoruzhick 	if (new & NUD_CONNECTED)
1350f0e0d044SVasily Khoruzhick 		neigh->confirmed = jiffies;
1351f0e0d044SVasily Khoruzhick 
13521da177e4SLinus Torvalds 	/* If entry was valid and address is not changed,
13531da177e4SLinus Torvalds 	   do not change entry state, if new one is STALE.
13541da177e4SLinus Torvalds 	 */
13551da177e4SLinus Torvalds 	err = 0;
13561da177e4SLinus Torvalds 	update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
13571da177e4SLinus Torvalds 	if (old & NUD_VALID) {
13581da177e4SLinus Torvalds 		if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
13591da177e4SLinus Torvalds 			update_isrouter = 0;
13601da177e4SLinus Torvalds 			if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
13611da177e4SLinus Torvalds 			    (old & NUD_CONNECTED)) {
13621da177e4SLinus Torvalds 				lladdr = neigh->ha;
13631da177e4SLinus Torvalds 				new = NUD_STALE;
13641da177e4SLinus Torvalds 			} else
13651da177e4SLinus Torvalds 				goto out;
13661da177e4SLinus Torvalds 		} else {
13670e7bbcc1SJulian Anastasov 			if (lladdr == neigh->ha && new == NUD_STALE &&
13680e7bbcc1SJulian Anastasov 			    !(flags & NEIGH_UPDATE_F_ADMIN))
13691da177e4SLinus Torvalds 				new = old;
13701da177e4SLinus Torvalds 		}
13711da177e4SLinus Torvalds 	}
13721da177e4SLinus Torvalds 
1373f0e0d044SVasily Khoruzhick 	/* Update timestamp only once we know we will make a change to the
137477d71233SIhar Hrachyshka 	 * neighbour entry. Otherwise we risk to move the locktime window with
137577d71233SIhar Hrachyshka 	 * noop updates and ignore relevant ARP updates.
137677d71233SIhar Hrachyshka 	 */
1377f0e0d044SVasily Khoruzhick 	if (new != old || lladdr != neigh->ha)
137877d71233SIhar Hrachyshka 		neigh->updated = jiffies;
137977d71233SIhar Hrachyshka 
13801da177e4SLinus Torvalds 	if (new != old) {
13811da177e4SLinus Torvalds 		neigh_del_timer(neigh);
1382765c9c63SErik Kline 		if (new & NUD_PROBE)
1383765c9c63SErik Kline 			atomic_set(&neigh->probes, 0);
1384a43d8994SPavel Emelyanov 		if (new & NUD_IN_TIMER)
1385667347f1SDavid S. Miller 			neigh_add_timer(neigh, (jiffies +
13861da177e4SLinus Torvalds 						((new & NUD_REACHABLE) ?
1387667347f1SDavid S. Miller 						 neigh->parms->reachable_time :
1388667347f1SDavid S. Miller 						 0)));
13899c29a2f5SDavid Ahern 		neigh->nud_state = new;
139053385d2dSBob Gilligan 		notify = 1;
13911da177e4SLinus Torvalds 	}
13921da177e4SLinus Torvalds 
13931da177e4SLinus Torvalds 	if (lladdr != neigh->ha) {
13940ed8ddf4SEric Dumazet 		write_seqlock(&neigh->ha_lock);
13951da177e4SLinus Torvalds 		memcpy(&neigh->ha, lladdr, dev->addr_len);
13960ed8ddf4SEric Dumazet 		write_sequnlock(&neigh->ha_lock);
13971da177e4SLinus Torvalds 		neigh_update_hhs(neigh);
13981da177e4SLinus Torvalds 		if (!(new & NUD_CONNECTED))
13991da177e4SLinus Torvalds 			neigh->confirmed = jiffies -
14001f9248e5SJiri Pirko 				      (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1);
14011da177e4SLinus Torvalds 		notify = 1;
14021da177e4SLinus Torvalds 	}
14031da177e4SLinus Torvalds 	if (new == old)
14041da177e4SLinus Torvalds 		goto out;
14051da177e4SLinus Torvalds 	if (new & NUD_CONNECTED)
14061da177e4SLinus Torvalds 		neigh_connect(neigh);
14071da177e4SLinus Torvalds 	else
14081da177e4SLinus Torvalds 		neigh_suspect(neigh);
14091da177e4SLinus Torvalds 	if (!(old & NUD_VALID)) {
14101da177e4SLinus Torvalds 		struct sk_buff *skb;
14111da177e4SLinus Torvalds 
14121da177e4SLinus Torvalds 		/* Again: avoid dead loop if something went wrong */
14131da177e4SLinus Torvalds 
14141da177e4SLinus Torvalds 		while (neigh->nud_state & NUD_VALID &&
14151da177e4SLinus Torvalds 		       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
141669cce1d1SDavid S. Miller 			struct dst_entry *dst = skb_dst(skb);
141769cce1d1SDavid S. Miller 			struct neighbour *n2, *n1 = neigh;
14181da177e4SLinus Torvalds 			write_unlock_bh(&neigh->lock);
1419e049f288Sroy.qing.li@gmail.com 
1420e049f288Sroy.qing.li@gmail.com 			rcu_read_lock();
142113a43d94SDavid S. Miller 
142213a43d94SDavid S. Miller 			/* Why not just use 'neigh' as-is?  The problem is that
142313a43d94SDavid S. Miller 			 * things such as shaper, eql, and sch_teql can end up
142413a43d94SDavid S. Miller 			 * using alternative, different, neigh objects to output
142513a43d94SDavid S. Miller 			 * the packet in the output path.  So what we need to do
142613a43d94SDavid S. Miller 			 * here is re-lookup the top-level neigh in the path so
142713a43d94SDavid S. Miller 			 * we can reinject the packet there.
142813a43d94SDavid S. Miller 			 */
142913a43d94SDavid S. Miller 			n2 = NULL;
1430d47ec7a0STong Zhu 			if (dst && dst->obsolete != DST_OBSOLETE_DEAD) {
143113a43d94SDavid S. Miller 				n2 = dst_neigh_lookup_skb(dst, skb);
143213a43d94SDavid S. Miller 				if (n2)
143369cce1d1SDavid S. Miller 					n1 = n2;
143413a43d94SDavid S. Miller 			}
14358f40b161SDavid S. Miller 			n1->output(n1, skb);
143613a43d94SDavid S. Miller 			if (n2)
143713a43d94SDavid S. Miller 				neigh_release(n2);
1438e049f288Sroy.qing.li@gmail.com 			rcu_read_unlock();
1439e049f288Sroy.qing.li@gmail.com 
14401da177e4SLinus Torvalds 			write_lock_bh(&neigh->lock);
14411da177e4SLinus Torvalds 		}
1442c9ab4d85SEric Dumazet 		__skb_queue_purge(&neigh->arp_queue);
14438b5c171bSEric Dumazet 		neigh->arp_queue_len_bytes = 0;
14441da177e4SLinus Torvalds 	}
14451da177e4SLinus Torvalds out:
1446fc6e8073SRoopa Prabhu 	if (update_isrouter)
1447fc6e8073SRoopa Prabhu 		neigh_update_is_router(neigh, flags, &notify);
14481da177e4SLinus Torvalds 	write_unlock_bh(&neigh->lock);
14497482e384SDaniel Borkmann 	if (((new ^ old) & NUD_PERMANENT) || gc_update)
14509c29a2f5SDavid Ahern 		neigh_update_gc_list(neigh);
14517482e384SDaniel Borkmann 	if (managed_update)
14527482e384SDaniel Borkmann 		neigh_update_managed_list(neigh);
14538d71740cSTom Tucker 	if (notify)
14547b8f7a40SRoopa Prabhu 		neigh_update_notify(neigh, nlmsg_pid);
145556dd18a4SRoopa Prabhu 	trace_neigh_update_done(neigh, err);
14561da177e4SLinus Torvalds 	return err;
14571da177e4SLinus Torvalds }
14587a35a50dSDavid Ahern 
14597a35a50dSDavid Ahern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
14607a35a50dSDavid Ahern 		 u32 flags, u32 nlmsg_pid)
14617a35a50dSDavid Ahern {
14627a35a50dSDavid Ahern 	return __neigh_update(neigh, lladdr, new, flags, nlmsg_pid, NULL);
14637a35a50dSDavid Ahern }
14640a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_update);
14651da177e4SLinus Torvalds 
14667e980569SJiri Benc /* Update the neigh to listen temporarily for probe responses, even if it is
14677e980569SJiri Benc  * in a NUD_FAILED state. The caller has to hold neigh->lock for writing.
14687e980569SJiri Benc  */
14697e980569SJiri Benc void __neigh_set_probe_once(struct neighbour *neigh)
14707e980569SJiri Benc {
14712c51a97fSJulian Anastasov 	if (neigh->dead)
14722c51a97fSJulian Anastasov 		return;
14737e980569SJiri Benc 	neigh->updated = jiffies;
14747e980569SJiri Benc 	if (!(neigh->nud_state & NUD_FAILED))
14757e980569SJiri Benc 		return;
14762176d5d4SDuan Jiong 	neigh->nud_state = NUD_INCOMPLETE;
14772176d5d4SDuan Jiong 	atomic_set(&neigh->probes, neigh_max_probes(neigh));
14787e980569SJiri Benc 	neigh_add_timer(neigh,
147919e16d22SHangbin Liu 			jiffies + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
148019e16d22SHangbin Liu 				      HZ/100));
14817e980569SJiri Benc }
14827e980569SJiri Benc EXPORT_SYMBOL(__neigh_set_probe_once);
14837e980569SJiri Benc 
14841da177e4SLinus Torvalds struct neighbour *neigh_event_ns(struct neigh_table *tbl,
14851da177e4SLinus Torvalds 				 u8 *lladdr, void *saddr,
14861da177e4SLinus Torvalds 				 struct net_device *dev)
14871da177e4SLinus Torvalds {
14881da177e4SLinus Torvalds 	struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
14891da177e4SLinus Torvalds 						 lladdr || !dev->addr_len);
14901da177e4SLinus Torvalds 	if (neigh)
14911da177e4SLinus Torvalds 		neigh_update(neigh, lladdr, NUD_STALE,
14927b8f7a40SRoopa Prabhu 			     NEIGH_UPDATE_F_OVERRIDE, 0);
14931da177e4SLinus Torvalds 	return neigh;
14941da177e4SLinus Torvalds }
14950a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_event_ns);
14961da177e4SLinus Torvalds 
149734d101ddSEric Dumazet /* called with read_lock_bh(&n->lock); */
1498bdf53c58SEric W. Biederman static void neigh_hh_init(struct neighbour *n)
14991da177e4SLinus Torvalds {
1500bdf53c58SEric W. Biederman 	struct net_device *dev = n->dev;
1501bdf53c58SEric W. Biederman 	__be16 prot = n->tbl->protocol;
1502f6b72b62SDavid S. Miller 	struct hh_cache	*hh = &n->hh;
15030ed8ddf4SEric Dumazet 
15040ed8ddf4SEric Dumazet 	write_lock_bh(&n->lock);
150534d101ddSEric Dumazet 
1506f6b72b62SDavid S. Miller 	/* Only one thread can come in here and initialize the
1507f6b72b62SDavid S. Miller 	 * hh_cache entry.
1508f6b72b62SDavid S. Miller 	 */
1509b23b5455SDavid S. Miller 	if (!hh->hh_len)
1510b23b5455SDavid S. Miller 		dev->header_ops->cache(n, hh, prot);
1511f6b72b62SDavid S. Miller 
15120ed8ddf4SEric Dumazet 	write_unlock_bh(&n->lock);
15131da177e4SLinus Torvalds }
15141da177e4SLinus Torvalds 
15151da177e4SLinus Torvalds /* Slow and careful. */
15161da177e4SLinus Torvalds 
15178f40b161SDavid S. Miller int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
15181da177e4SLinus Torvalds {
15191da177e4SLinus Torvalds 	int rc = 0;
15201da177e4SLinus Torvalds 
15211da177e4SLinus Torvalds 	if (!neigh_event_send(neigh, skb)) {
15221da177e4SLinus Torvalds 		int err;
15231da177e4SLinus Torvalds 		struct net_device *dev = neigh->dev;
15240ed8ddf4SEric Dumazet 		unsigned int seq;
152534d101ddSEric Dumazet 
1526c305c6aeSEric Dumazet 		if (dev->header_ops->cache && !READ_ONCE(neigh->hh.hh_len))
1527bdf53c58SEric W. Biederman 			neigh_hh_init(neigh);
152834d101ddSEric Dumazet 
15290ed8ddf4SEric Dumazet 		do {
1530e1f16503Sramesh.nagappa@gmail.com 			__skb_pull(skb, skb_network_offset(skb));
15310ed8ddf4SEric Dumazet 			seq = read_seqbegin(&neigh->ha_lock);
15320c4e8581SStephen Hemminger 			err = dev_hard_header(skb, dev, ntohs(skb->protocol),
15331da177e4SLinus Torvalds 					      neigh->ha, NULL, skb->len);
15340ed8ddf4SEric Dumazet 		} while (read_seqretry(&neigh->ha_lock, seq));
153534d101ddSEric Dumazet 
15361da177e4SLinus Torvalds 		if (err >= 0)
1537542d4d68SDavid S. Miller 			rc = dev_queue_xmit(skb);
15381da177e4SLinus Torvalds 		else
15391da177e4SLinus Torvalds 			goto out_kfree_skb;
15401da177e4SLinus Torvalds 	}
15411da177e4SLinus Torvalds out:
15421da177e4SLinus Torvalds 	return rc;
15431da177e4SLinus Torvalds out_kfree_skb:
15441da177e4SLinus Torvalds 	rc = -EINVAL;
15451da177e4SLinus Torvalds 	kfree_skb(skb);
15461da177e4SLinus Torvalds 	goto out;
15471da177e4SLinus Torvalds }
15480a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_resolve_output);
15491da177e4SLinus Torvalds 
15501da177e4SLinus Torvalds /* As fast as possible without hh cache */
15511da177e4SLinus Torvalds 
15528f40b161SDavid S. Miller int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
15531da177e4SLinus Torvalds {
15541da177e4SLinus Torvalds 	struct net_device *dev = neigh->dev;
15550ed8ddf4SEric Dumazet 	unsigned int seq;
15568f40b161SDavid S. Miller 	int err;
15571da177e4SLinus Torvalds 
15580ed8ddf4SEric Dumazet 	do {
1559e1f16503Sramesh.nagappa@gmail.com 		__skb_pull(skb, skb_network_offset(skb));
15600ed8ddf4SEric Dumazet 		seq = read_seqbegin(&neigh->ha_lock);
15610c4e8581SStephen Hemminger 		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
15621da177e4SLinus Torvalds 				      neigh->ha, NULL, skb->len);
15630ed8ddf4SEric Dumazet 	} while (read_seqretry(&neigh->ha_lock, seq));
15640ed8ddf4SEric Dumazet 
15651da177e4SLinus Torvalds 	if (err >= 0)
1566542d4d68SDavid S. Miller 		err = dev_queue_xmit(skb);
15671da177e4SLinus Torvalds 	else {
15681da177e4SLinus Torvalds 		err = -EINVAL;
15691da177e4SLinus Torvalds 		kfree_skb(skb);
15701da177e4SLinus Torvalds 	}
15711da177e4SLinus Torvalds 	return err;
15721da177e4SLinus Torvalds }
15730a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_connected_output);
15741da177e4SLinus Torvalds 
15758f40b161SDavid S. Miller int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
15768f40b161SDavid S. Miller {
15778f40b161SDavid S. Miller 	return dev_queue_xmit(skb);
15788f40b161SDavid S. Miller }
15798f40b161SDavid S. Miller EXPORT_SYMBOL(neigh_direct_output);
15808f40b161SDavid S. Miller 
15817482e384SDaniel Borkmann static void neigh_managed_work(struct work_struct *work)
15827482e384SDaniel Borkmann {
15837482e384SDaniel Borkmann 	struct neigh_table *tbl = container_of(work, struct neigh_table,
15847482e384SDaniel Borkmann 					       managed_work.work);
15857482e384SDaniel Borkmann 	struct neighbour *neigh;
15867482e384SDaniel Borkmann 
15877482e384SDaniel Borkmann 	write_lock_bh(&tbl->lock);
15887482e384SDaniel Borkmann 	list_for_each_entry(neigh, &tbl->managed_list, managed_list)
15894a81f6daSDaniel Borkmann 		neigh_event_send_probe(neigh, NULL, false);
15907482e384SDaniel Borkmann 	queue_delayed_work(system_power_efficient_wq, &tbl->managed_work,
1591211da42eSYuwei Wang 			   NEIGH_VAR(&tbl->parms, INTERVAL_PROBE_TIME_MS));
15927482e384SDaniel Borkmann 	write_unlock_bh(&tbl->lock);
15937482e384SDaniel Borkmann }
15947482e384SDaniel Borkmann 
1595e99e88a9SKees Cook static void neigh_proxy_process(struct timer_list *t)
15961da177e4SLinus Torvalds {
1597e99e88a9SKees Cook 	struct neigh_table *tbl = from_timer(tbl, t, proxy_timer);
15981da177e4SLinus Torvalds 	long sched_next = 0;
15991da177e4SLinus Torvalds 	unsigned long now = jiffies;
1600f72051b0SDavid S. Miller 	struct sk_buff *skb, *n;
16011da177e4SLinus Torvalds 
16021da177e4SLinus Torvalds 	spin_lock(&tbl->proxy_queue.lock);
16031da177e4SLinus Torvalds 
1604f72051b0SDavid S. Miller 	skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1605f72051b0SDavid S. Miller 		long tdif = NEIGH_CB(skb)->sched_next - now;
16061da177e4SLinus Torvalds 
16071da177e4SLinus Torvalds 		if (tdif <= 0) {
1608f72051b0SDavid S. Miller 			struct net_device *dev = skb->dev;
160920e6074eSEric Dumazet 
1610f72051b0SDavid S. Miller 			__skb_unlink(skb, &tbl->proxy_queue);
161120e6074eSEric Dumazet 			if (tbl->proxy_redo && netif_running(dev)) {
161220e6074eSEric Dumazet 				rcu_read_lock();
1613f72051b0SDavid S. Miller 				tbl->proxy_redo(skb);
161420e6074eSEric Dumazet 				rcu_read_unlock();
161520e6074eSEric Dumazet 			} else {
1616f72051b0SDavid S. Miller 				kfree_skb(skb);
161720e6074eSEric Dumazet 			}
16181da177e4SLinus Torvalds 
16191da177e4SLinus Torvalds 			dev_put(dev);
16201da177e4SLinus Torvalds 		} else if (!sched_next || tdif < sched_next)
16211da177e4SLinus Torvalds 			sched_next = tdif;
16221da177e4SLinus Torvalds 	}
16231da177e4SLinus Torvalds 	del_timer(&tbl->proxy_timer);
16241da177e4SLinus Torvalds 	if (sched_next)
16251da177e4SLinus Torvalds 		mod_timer(&tbl->proxy_timer, jiffies + sched_next);
16261da177e4SLinus Torvalds 	spin_unlock(&tbl->proxy_queue.lock);
16271da177e4SLinus Torvalds }
16281da177e4SLinus Torvalds 
16291da177e4SLinus Torvalds void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
16301da177e4SLinus Torvalds 		    struct sk_buff *skb)
16311da177e4SLinus Torvalds {
1632a533b70aSweichenchen 	unsigned long sched_next = jiffies +
1633a533b70aSweichenchen 			prandom_u32_max(NEIGH_VAR(p, PROXY_DELAY));
16341da177e4SLinus Torvalds 
16351f9248e5SJiri Pirko 	if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) {
16361da177e4SLinus Torvalds 		kfree_skb(skb);
16371da177e4SLinus Torvalds 		return;
16381da177e4SLinus Torvalds 	}
1639a61bbcf2SPatrick McHardy 
1640a61bbcf2SPatrick McHardy 	NEIGH_CB(skb)->sched_next = sched_next;
1641a61bbcf2SPatrick McHardy 	NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
16421da177e4SLinus Torvalds 
16431da177e4SLinus Torvalds 	spin_lock(&tbl->proxy_queue.lock);
16441da177e4SLinus Torvalds 	if (del_timer(&tbl->proxy_timer)) {
16451da177e4SLinus Torvalds 		if (time_before(tbl->proxy_timer.expires, sched_next))
16461da177e4SLinus Torvalds 			sched_next = tbl->proxy_timer.expires;
16471da177e4SLinus Torvalds 	}
1648adf30907SEric Dumazet 	skb_dst_drop(skb);
16491da177e4SLinus Torvalds 	dev_hold(skb->dev);
16501da177e4SLinus Torvalds 	__skb_queue_tail(&tbl->proxy_queue, skb);
16511da177e4SLinus Torvalds 	mod_timer(&tbl->proxy_timer, sched_next);
16521da177e4SLinus Torvalds 	spin_unlock(&tbl->proxy_queue.lock);
16531da177e4SLinus Torvalds }
16540a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(pneigh_enqueue);
16551da177e4SLinus Torvalds 
165697fd5bc7STobias Klauser static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
1657426b5303SEric W. Biederman 						      struct net *net, int ifindex)
1658426b5303SEric W. Biederman {
1659426b5303SEric W. Biederman 	struct neigh_parms *p;
1660426b5303SEric W. Biederman 
166175fbfd33SNicolas Dichtel 	list_for_each_entry(p, &tbl->parms_list, list) {
1662878628fbSYOSHIFUJI Hideaki 		if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
1663170d6f99SGao feng 		    (!p->dev && !ifindex && net_eq(net, &init_net)))
1664426b5303SEric W. Biederman 			return p;
1665426b5303SEric W. Biederman 	}
1666426b5303SEric W. Biederman 
1667426b5303SEric W. Biederman 	return NULL;
1668426b5303SEric W. Biederman }
16691da177e4SLinus Torvalds 
16701da177e4SLinus Torvalds struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
16711da177e4SLinus Torvalds 				      struct neigh_table *tbl)
16721da177e4SLinus Torvalds {
1673cf89d6b2SGao feng 	struct neigh_parms *p;
167400829823SStephen Hemminger 	struct net *net = dev_net(dev);
167500829823SStephen Hemminger 	const struct net_device_ops *ops = dev->netdev_ops;
16761da177e4SLinus Torvalds 
1677cf89d6b2SGao feng 	p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL);
16781da177e4SLinus Torvalds 	if (p) {
16791da177e4SLinus Torvalds 		p->tbl		  = tbl;
16806343944bSReshetova, Elena 		refcount_set(&p->refcnt, 1);
16811da177e4SLinus Torvalds 		p->reachable_time =
16821f9248e5SJiri Pirko 				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
1683d62607c3SJakub Kicinski 		netdev_hold(dev, &p->dev_tracker, GFP_KERNEL);
1684c7fb64dbSThomas Graf 		p->dev = dev;
1685efd7ef1cSEric W. Biederman 		write_pnet(&p->net, net);
16861da177e4SLinus Torvalds 		p->sysctl_table = NULL;
168763134803SVeaceslav Falico 
168863134803SVeaceslav Falico 		if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
1689d62607c3SJakub Kicinski 			netdev_put(dev, &p->dev_tracker);
169063134803SVeaceslav Falico 			kfree(p);
169163134803SVeaceslav Falico 			return NULL;
169263134803SVeaceslav Falico 		}
169363134803SVeaceslav Falico 
16941da177e4SLinus Torvalds 		write_lock_bh(&tbl->lock);
169575fbfd33SNicolas Dichtel 		list_add(&p->list, &tbl->parms.list);
16961da177e4SLinus Torvalds 		write_unlock_bh(&tbl->lock);
16971d4c8c29SJiri Pirko 
16981d4c8c29SJiri Pirko 		neigh_parms_data_state_cleanall(p);
16991da177e4SLinus Torvalds 	}
17001da177e4SLinus Torvalds 	return p;
17011da177e4SLinus Torvalds }
17020a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_parms_alloc);
17031da177e4SLinus Torvalds 
17041da177e4SLinus Torvalds static void neigh_rcu_free_parms(struct rcu_head *head)
17051da177e4SLinus Torvalds {
17061da177e4SLinus Torvalds 	struct neigh_parms *parms =
17071da177e4SLinus Torvalds 		container_of(head, struct neigh_parms, rcu_head);
17081da177e4SLinus Torvalds 
17091da177e4SLinus Torvalds 	neigh_parms_put(parms);
17101da177e4SLinus Torvalds }
17111da177e4SLinus Torvalds 
17121da177e4SLinus Torvalds void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
17131da177e4SLinus Torvalds {
17141da177e4SLinus Torvalds 	if (!parms || parms == &tbl->parms)
17151da177e4SLinus Torvalds 		return;
17161da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
171775fbfd33SNicolas Dichtel 	list_del(&parms->list);
17181da177e4SLinus Torvalds 	parms->dead = 1;
17191da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
1720d62607c3SJakub Kicinski 	netdev_put(parms->dev, &parms->dev_tracker);
17211da177e4SLinus Torvalds 	call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
17221da177e4SLinus Torvalds }
17230a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_parms_release);
17241da177e4SLinus Torvalds 
172506f0511dSDenis V. Lunev static void neigh_parms_destroy(struct neigh_parms *parms)
17261da177e4SLinus Torvalds {
17271da177e4SLinus Torvalds 	kfree(parms);
17281da177e4SLinus Torvalds }
17291da177e4SLinus Torvalds 
1730c2ecba71SPavel Emelianov static struct lock_class_key neigh_table_proxy_queue_class;
1731c2ecba71SPavel Emelianov 
1732d7480fd3SWANG Cong static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly;
1733d7480fd3SWANG Cong 
1734d7480fd3SWANG Cong void neigh_table_init(int index, struct neigh_table *tbl)
17351da177e4SLinus Torvalds {
17361da177e4SLinus Torvalds 	unsigned long now = jiffies;
17371da177e4SLinus Torvalds 	unsigned long phsize;
17381da177e4SLinus Torvalds 
173975fbfd33SNicolas Dichtel 	INIT_LIST_HEAD(&tbl->parms_list);
174058956317SDavid Ahern 	INIT_LIST_HEAD(&tbl->gc_list);
17417482e384SDaniel Borkmann 	INIT_LIST_HEAD(&tbl->managed_list);
17427482e384SDaniel Borkmann 
174375fbfd33SNicolas Dichtel 	list_add(&tbl->parms.list, &tbl->parms_list);
1744e42ea986SEric Dumazet 	write_pnet(&tbl->parms.net, &init_net);
17456343944bSReshetova, Elena 	refcount_set(&tbl->parms.refcnt, 1);
17461da177e4SLinus Torvalds 	tbl->parms.reachable_time =
17471f9248e5SJiri Pirko 			  neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME));
17481da177e4SLinus Torvalds 
17491da177e4SLinus Torvalds 	tbl->stats = alloc_percpu(struct neigh_statistics);
17501da177e4SLinus Torvalds 	if (!tbl->stats)
17511da177e4SLinus Torvalds 		panic("cannot create neighbour cache statistics");
17521da177e4SLinus Torvalds 
17531da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
175471a5053aSChristoph Hellwig 	if (!proc_create_seq_data(tbl->id, 0, init_net.proc_net_stat,
175571a5053aSChristoph Hellwig 			      &neigh_stat_seq_ops, tbl))
17561da177e4SLinus Torvalds 		panic("cannot create neighbour proc dir entry");
17571da177e4SLinus Torvalds #endif
17581da177e4SLinus Torvalds 
1759cd089336SDavid S. Miller 	RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
17601da177e4SLinus Torvalds 
17611da177e4SLinus Torvalds 	phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
176277d04bd9SAndrew Morton 	tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
17631da177e4SLinus Torvalds 
1764d6bf7817SEric Dumazet 	if (!tbl->nht || !tbl->phash_buckets)
17651da177e4SLinus Torvalds 		panic("cannot allocate neighbour cache hashes");
17661da177e4SLinus Torvalds 
176708433effSYOSHIFUJI Hideaki / 吉藤英明 	if (!tbl->entry_size)
176808433effSYOSHIFUJI Hideaki / 吉藤英明 		tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
176908433effSYOSHIFUJI Hideaki / 吉藤英明 					tbl->key_len, NEIGH_PRIV_ALIGN);
177008433effSYOSHIFUJI Hideaki / 吉藤英明 	else
177108433effSYOSHIFUJI Hideaki / 吉藤英明 		WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
177208433effSYOSHIFUJI Hideaki / 吉藤英明 
17731da177e4SLinus Torvalds 	rwlock_init(&tbl->lock);
17747482e384SDaniel Borkmann 
1775203b42f7STejun Heo 	INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
1776f618002bSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
1777f618002bSviresh kumar 			tbl->parms.reachable_time);
17787482e384SDaniel Borkmann 	INIT_DEFERRABLE_WORK(&tbl->managed_work, neigh_managed_work);
17797482e384SDaniel Borkmann 	queue_delayed_work(system_power_efficient_wq, &tbl->managed_work, 0);
17807482e384SDaniel Borkmann 
1781e99e88a9SKees Cook 	timer_setup(&tbl->proxy_timer, neigh_proxy_process, 0);
1782c2ecba71SPavel Emelianov 	skb_queue_head_init_class(&tbl->proxy_queue,
1783c2ecba71SPavel Emelianov 			&neigh_table_proxy_queue_class);
17841da177e4SLinus Torvalds 
17851da177e4SLinus Torvalds 	tbl->last_flush = now;
17861da177e4SLinus Torvalds 	tbl->last_rand	= now + tbl->parms.reachable_time * 20;
1787bd89efc5SSimon Kelley 
1788d7480fd3SWANG Cong 	neigh_tables[index] = tbl;
17891da177e4SLinus Torvalds }
17900a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_table_init);
17911da177e4SLinus Torvalds 
1792d7480fd3SWANG Cong int neigh_table_clear(int index, struct neigh_table *tbl)
17931da177e4SLinus Torvalds {
1794d7480fd3SWANG Cong 	neigh_tables[index] = NULL;
17951da177e4SLinus Torvalds 	/* It is not clean... Fix it to unload IPv6 module safely */
17964177d5b0SDaniel Borkmann 	cancel_delayed_work_sync(&tbl->managed_work);
1797a5c30b34STejun Heo 	cancel_delayed_work_sync(&tbl->gc_work);
17981da177e4SLinus Torvalds 	del_timer_sync(&tbl->proxy_timer);
1799*66ba215cSDenis V. Lunev 	pneigh_queue_purge(&tbl->proxy_queue, NULL);
18001da177e4SLinus Torvalds 	neigh_ifdown(tbl, NULL);
18011da177e4SLinus Torvalds 	if (atomic_read(&tbl->entries))
1802e005d193SJoe Perches 		pr_crit("neighbour leakage\n");
18031da177e4SLinus Torvalds 
18046193d2beSEric Dumazet 	call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
18056193d2beSEric Dumazet 		 neigh_hash_free_rcu);
1806d6bf7817SEric Dumazet 	tbl->nht = NULL;
18071da177e4SLinus Torvalds 
18081da177e4SLinus Torvalds 	kfree(tbl->phash_buckets);
18091da177e4SLinus Torvalds 	tbl->phash_buckets = NULL;
18101da177e4SLinus Torvalds 
18113f192b5cSAlexey Dobriyan 	remove_proc_entry(tbl->id, init_net.proc_net_stat);
18123f192b5cSAlexey Dobriyan 
18133fcde74bSKirill Korotaev 	free_percpu(tbl->stats);
18143fcde74bSKirill Korotaev 	tbl->stats = NULL;
18153fcde74bSKirill Korotaev 
18161da177e4SLinus Torvalds 	return 0;
18171da177e4SLinus Torvalds }
18180a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_table_clear);
18191da177e4SLinus Torvalds 
1820d7480fd3SWANG Cong static struct neigh_table *neigh_find_table(int family)
1821d7480fd3SWANG Cong {
1822d7480fd3SWANG Cong 	struct neigh_table *tbl = NULL;
1823d7480fd3SWANG Cong 
1824d7480fd3SWANG Cong 	switch (family) {
1825d7480fd3SWANG Cong 	case AF_INET:
1826d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_ARP_TABLE];
1827d7480fd3SWANG Cong 		break;
1828d7480fd3SWANG Cong 	case AF_INET6:
1829d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_ND_TABLE];
1830d7480fd3SWANG Cong 		break;
1831d7480fd3SWANG Cong 	case AF_DECnet:
1832d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_DN_TABLE];
1833d7480fd3SWANG Cong 		break;
1834d7480fd3SWANG Cong 	}
1835d7480fd3SWANG Cong 
1836d7480fd3SWANG Cong 	return tbl;
1837d7480fd3SWANG Cong }
1838d7480fd3SWANG Cong 
183982cbb5c6SRoopa Prabhu const struct nla_policy nda_policy[NDA_MAX+1] = {
18401274e1ccSRoopa Prabhu 	[NDA_UNSPEC]		= { .strict_start_type = NDA_NH_ID },
184182cbb5c6SRoopa Prabhu 	[NDA_DST]		= { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
184282cbb5c6SRoopa Prabhu 	[NDA_LLADDR]		= { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
184382cbb5c6SRoopa Prabhu 	[NDA_CACHEINFO]		= { .len = sizeof(struct nda_cacheinfo) },
184482cbb5c6SRoopa Prabhu 	[NDA_PROBES]		= { .type = NLA_U32 },
184582cbb5c6SRoopa Prabhu 	[NDA_VLAN]		= { .type = NLA_U16 },
184682cbb5c6SRoopa Prabhu 	[NDA_PORT]		= { .type = NLA_U16 },
184782cbb5c6SRoopa Prabhu 	[NDA_VNI]		= { .type = NLA_U32 },
184882cbb5c6SRoopa Prabhu 	[NDA_IFINDEX]		= { .type = NLA_U32 },
184982cbb5c6SRoopa Prabhu 	[NDA_MASTER]		= { .type = NLA_U32 },
1850a9cd3439SDavid Ahern 	[NDA_PROTOCOL]		= { .type = NLA_U8 },
18511274e1ccSRoopa Prabhu 	[NDA_NH_ID]		= { .type = NLA_U32 },
1852c8e80c11SDaniel Borkmann 	[NDA_FLAGS_EXT]		= NLA_POLICY_MASK(NLA_U32, NTF_EXT_MASK),
1853899426b3SNikolay Aleksandrov 	[NDA_FDB_EXT_ATTRS]	= { .type = NLA_NESTED },
185482cbb5c6SRoopa Prabhu };
185582cbb5c6SRoopa Prabhu 
1856c21ef3e3SDavid Ahern static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
1857c21ef3e3SDavid Ahern 			struct netlink_ext_ack *extack)
18581da177e4SLinus Torvalds {
18593b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
1860a14a49d2SThomas Graf 	struct ndmsg *ndm;
1861a14a49d2SThomas Graf 	struct nlattr *dst_attr;
18621da177e4SLinus Torvalds 	struct neigh_table *tbl;
1863d7480fd3SWANG Cong 	struct neighbour *neigh;
18641da177e4SLinus Torvalds 	struct net_device *dev = NULL;
1865a14a49d2SThomas Graf 	int err = -EINVAL;
18661da177e4SLinus Torvalds 
1867110b2499SEric Dumazet 	ASSERT_RTNL();
1868a14a49d2SThomas Graf 	if (nlmsg_len(nlh) < sizeof(*ndm))
18691da177e4SLinus Torvalds 		goto out;
18701da177e4SLinus Torvalds 
1871a14a49d2SThomas Graf 	dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
18727a35a50dSDavid Ahern 	if (!dst_attr) {
18737a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Network address not specified");
1874a14a49d2SThomas Graf 		goto out;
18757a35a50dSDavid Ahern 	}
1876a14a49d2SThomas Graf 
1877a14a49d2SThomas Graf 	ndm = nlmsg_data(nlh);
1878a14a49d2SThomas Graf 	if (ndm->ndm_ifindex) {
1879110b2499SEric Dumazet 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
1880a14a49d2SThomas Graf 		if (dev == NULL) {
1881a14a49d2SThomas Graf 			err = -ENODEV;
1882a14a49d2SThomas Graf 			goto out;
1883a14a49d2SThomas Graf 		}
1884a14a49d2SThomas Graf 	}
1885a14a49d2SThomas Graf 
1886d7480fd3SWANG Cong 	tbl = neigh_find_table(ndm->ndm_family);
1887d7480fd3SWANG Cong 	if (tbl == NULL)
1888d7480fd3SWANG Cong 		return -EAFNOSUPPORT;
18891da177e4SLinus Torvalds 
18907a35a50dSDavid Ahern 	if (nla_len(dst_attr) < (int)tbl->key_len) {
18917a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid network address");
1892110b2499SEric Dumazet 		goto out;
18937a35a50dSDavid Ahern 	}
18941da177e4SLinus Torvalds 
18951da177e4SLinus Torvalds 	if (ndm->ndm_flags & NTF_PROXY) {
1896426b5303SEric W. Biederman 		err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
1897110b2499SEric Dumazet 		goto out;
18981da177e4SLinus Torvalds 	}
18991da177e4SLinus Torvalds 
1900a14a49d2SThomas Graf 	if (dev == NULL)
1901110b2499SEric Dumazet 		goto out;
19021da177e4SLinus Torvalds 
1903a14a49d2SThomas Graf 	neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1904a14a49d2SThomas Graf 	if (neigh == NULL) {
1905a14a49d2SThomas Graf 		err = -ENOENT;
1906110b2499SEric Dumazet 		goto out;
1907a14a49d2SThomas Graf 	}
1908a14a49d2SThomas Graf 
19097a35a50dSDavid Ahern 	err = __neigh_update(neigh, NULL, NUD_FAILED,
19107a35a50dSDavid Ahern 			     NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN,
19117a35a50dSDavid Ahern 			     NETLINK_CB(skb).portid, extack);
19125071034eSSowmini Varadhan 	write_lock_bh(&tbl->lock);
1913a14a49d2SThomas Graf 	neigh_release(neigh);
19145071034eSSowmini Varadhan 	neigh_remove_one(neigh, tbl);
19155071034eSSowmini Varadhan 	write_unlock_bh(&tbl->lock);
1916a14a49d2SThomas Graf 
19171da177e4SLinus Torvalds out:
19181da177e4SLinus Torvalds 	return err;
19191da177e4SLinus Torvalds }
19201da177e4SLinus Torvalds 
1921c21ef3e3SDavid Ahern static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
1922c21ef3e3SDavid Ahern 		     struct netlink_ext_ack *extack)
19231da177e4SLinus Torvalds {
1924f7aa74e4SRoopa Prabhu 	int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE |
1925f7aa74e4SRoopa Prabhu 		    NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
19263b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
19275208debdSThomas Graf 	struct ndmsg *ndm;
19285208debdSThomas Graf 	struct nlattr *tb[NDA_MAX+1];
19291da177e4SLinus Torvalds 	struct neigh_table *tbl;
19301da177e4SLinus Torvalds 	struct net_device *dev = NULL;
1931d7480fd3SWANG Cong 	struct neighbour *neigh;
1932d7480fd3SWANG Cong 	void *dst, *lladdr;
1933df9b0e30SDavid Ahern 	u8 protocol = 0;
19342c611ad9SRoopa Prabhu 	u32 ndm_flags;
19355208debdSThomas Graf 	int err;
19361da177e4SLinus Torvalds 
1937110b2499SEric Dumazet 	ASSERT_RTNL();
19388cb08174SJohannes Berg 	err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX,
19398cb08174SJohannes Berg 				     nda_policy, extack);
19405208debdSThomas Graf 	if (err < 0)
19411da177e4SLinus Torvalds 		goto out;
19421da177e4SLinus Torvalds 
19435208debdSThomas Graf 	err = -EINVAL;
19447a35a50dSDavid Ahern 	if (!tb[NDA_DST]) {
19457a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Network address not specified");
19465208debdSThomas Graf 		goto out;
19477a35a50dSDavid Ahern 	}
19485208debdSThomas Graf 
19495208debdSThomas Graf 	ndm = nlmsg_data(nlh);
19502c611ad9SRoopa Prabhu 	ndm_flags = ndm->ndm_flags;
19512c611ad9SRoopa Prabhu 	if (tb[NDA_FLAGS_EXT]) {
19522c611ad9SRoopa Prabhu 		u32 ext = nla_get_u32(tb[NDA_FLAGS_EXT]);
19532c611ad9SRoopa Prabhu 
1954507c2f1dSDaniel Borkmann 		BUILD_BUG_ON(sizeof(neigh->flags) * BITS_PER_BYTE <
1955507c2f1dSDaniel Borkmann 			     (sizeof(ndm->ndm_flags) * BITS_PER_BYTE +
1956507c2f1dSDaniel Borkmann 			      hweight32(NTF_EXT_MASK)));
19572c611ad9SRoopa Prabhu 		ndm_flags |= (ext << NTF_EXT_SHIFT);
19582c611ad9SRoopa Prabhu 	}
19595208debdSThomas Graf 	if (ndm->ndm_ifindex) {
1960110b2499SEric Dumazet 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
19615208debdSThomas Graf 		if (dev == NULL) {
19625208debdSThomas Graf 			err = -ENODEV;
19635208debdSThomas Graf 			goto out;
19645208debdSThomas Graf 		}
19655208debdSThomas Graf 
19667a35a50dSDavid Ahern 		if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) {
19677a35a50dSDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid link address");
1968110b2499SEric Dumazet 			goto out;
19695208debdSThomas Graf 		}
19707a35a50dSDavid Ahern 	}
19715208debdSThomas Graf 
1972d7480fd3SWANG Cong 	tbl = neigh_find_table(ndm->ndm_family);
1973d7480fd3SWANG Cong 	if (tbl == NULL)
1974d7480fd3SWANG Cong 		return -EAFNOSUPPORT;
19751da177e4SLinus Torvalds 
19767a35a50dSDavid Ahern 	if (nla_len(tb[NDA_DST]) < (int)tbl->key_len) {
19777a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid network address");
1978110b2499SEric Dumazet 		goto out;
19797a35a50dSDavid Ahern 	}
19807a35a50dSDavid Ahern 
19815208debdSThomas Graf 	dst = nla_data(tb[NDA_DST]);
19825208debdSThomas Graf 	lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
19831da177e4SLinus Torvalds 
1984a9cd3439SDavid Ahern 	if (tb[NDA_PROTOCOL])
1985df9b0e30SDavid Ahern 		protocol = nla_get_u8(tb[NDA_PROTOCOL]);
19862c611ad9SRoopa Prabhu 	if (ndm_flags & NTF_PROXY) {
198762dd9318SVille Nuorvala 		struct pneigh_entry *pn;
198862dd9318SVille Nuorvala 
19897482e384SDaniel Borkmann 		if (ndm_flags & NTF_MANAGED) {
19907482e384SDaniel Borkmann 			NL_SET_ERR_MSG(extack, "Invalid NTF_* flag combination");
19917482e384SDaniel Borkmann 			goto out;
19927482e384SDaniel Borkmann 		}
19937482e384SDaniel Borkmann 
19945208debdSThomas Graf 		err = -ENOBUFS;
1995426b5303SEric W. Biederman 		pn = pneigh_lookup(tbl, net, dst, dev, 1);
199662dd9318SVille Nuorvala 		if (pn) {
19972c611ad9SRoopa Prabhu 			pn->flags = ndm_flags;
1998df9b0e30SDavid Ahern 			if (protocol)
1999df9b0e30SDavid Ahern 				pn->protocol = protocol;
200062dd9318SVille Nuorvala 			err = 0;
200162dd9318SVille Nuorvala 		}
2002110b2499SEric Dumazet 		goto out;
20031da177e4SLinus Torvalds 	}
20041da177e4SLinus Torvalds 
20057a35a50dSDavid Ahern 	if (!dev) {
20067a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Device not specified");
2007110b2499SEric Dumazet 		goto out;
20087a35a50dSDavid Ahern 	}
20091da177e4SLinus Torvalds 
2010b8fb1ab4SDavid Ahern 	if (tbl->allow_add && !tbl->allow_add(dev, extack)) {
2011b8fb1ab4SDavid Ahern 		err = -EINVAL;
2012b8fb1ab4SDavid Ahern 		goto out;
2013b8fb1ab4SDavid Ahern 	}
2014b8fb1ab4SDavid Ahern 
20155208debdSThomas Graf 	neigh = neigh_lookup(tbl, dst, dev);
20165208debdSThomas Graf 	if (neigh == NULL) {
201730fc7efaSDaniel Borkmann 		bool ndm_permanent  = ndm->ndm_state & NUD_PERMANENT;
201830fc7efaSDaniel Borkmann 		bool exempt_from_gc = ndm_permanent ||
201930fc7efaSDaniel Borkmann 				      ndm_flags & NTF_EXT_LEARNED;
2020e997f8a2SDavid Ahern 
20215208debdSThomas Graf 		if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
20221da177e4SLinus Torvalds 			err = -ENOENT;
2023110b2499SEric Dumazet 			goto out;
20245208debdSThomas Graf 		}
202530fc7efaSDaniel Borkmann 		if (ndm_permanent && (ndm_flags & NTF_MANAGED)) {
202630fc7efaSDaniel Borkmann 			NL_SET_ERR_MSG(extack, "Invalid NTF_* flag for permanent entry");
202730fc7efaSDaniel Borkmann 			err = -EINVAL;
202830fc7efaSDaniel Borkmann 			goto out;
202930fc7efaSDaniel Borkmann 		}
20305208debdSThomas Graf 
2031e4400bbfSDaniel Borkmann 		neigh = ___neigh_create(tbl, dst, dev,
20327482e384SDaniel Borkmann 					ndm_flags &
20337482e384SDaniel Borkmann 					(NTF_EXT_LEARNED | NTF_MANAGED),
2034e4400bbfSDaniel Borkmann 					exempt_from_gc, true);
20355208debdSThomas Graf 		if (IS_ERR(neigh)) {
20365208debdSThomas Graf 			err = PTR_ERR(neigh);
2037110b2499SEric Dumazet 			goto out;
20381da177e4SLinus Torvalds 		}
20395208debdSThomas Graf 	} else {
20405208debdSThomas Graf 		if (nlh->nlmsg_flags & NLM_F_EXCL) {
20415208debdSThomas Graf 			err = -EEXIST;
20425208debdSThomas Graf 			neigh_release(neigh);
2043110b2499SEric Dumazet 			goto out;
20441da177e4SLinus Torvalds 		}
20451da177e4SLinus Torvalds 
20465208debdSThomas Graf 		if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
2047f7aa74e4SRoopa Prabhu 			flags &= ~(NEIGH_UPDATE_F_OVERRIDE |
2048f7aa74e4SRoopa Prabhu 				   NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
20495208debdSThomas Graf 	}
20501da177e4SLinus Torvalds 
205138212bb3SRoman Mashak 	if (protocol)
205238212bb3SRoman Mashak 		neigh->protocol = protocol;
20532c611ad9SRoopa Prabhu 	if (ndm_flags & NTF_EXT_LEARNED)
20549ce33e46SRoopa Prabhu 		flags |= NEIGH_UPDATE_F_EXT_LEARNED;
20552c611ad9SRoopa Prabhu 	if (ndm_flags & NTF_ROUTER)
2056f7aa74e4SRoopa Prabhu 		flags |= NEIGH_UPDATE_F_ISROUTER;
20577482e384SDaniel Borkmann 	if (ndm_flags & NTF_MANAGED)
20587482e384SDaniel Borkmann 		flags |= NEIGH_UPDATE_F_MANAGED;
20592c611ad9SRoopa Prabhu 	if (ndm_flags & NTF_USE)
20603dc20f47SDaniel Borkmann 		flags |= NEIGH_UPDATE_F_USE;
2061f7aa74e4SRoopa Prabhu 
20627a35a50dSDavid Ahern 	err = __neigh_update(neigh, lladdr, ndm->ndm_state, flags,
20637a35a50dSDavid Ahern 			     NETLINK_CB(skb).portid, extack);
20647482e384SDaniel Borkmann 	if (!err && ndm_flags & (NTF_USE | NTF_MANAGED)) {
20653dc20f47SDaniel Borkmann 		neigh_event_send(neigh, NULL);
20663dc20f47SDaniel Borkmann 		err = 0;
20673dc20f47SDaniel Borkmann 	}
20685208debdSThomas Graf 	neigh_release(neigh);
20691da177e4SLinus Torvalds out:
20701da177e4SLinus Torvalds 	return err;
20711da177e4SLinus Torvalds }
20721da177e4SLinus Torvalds 
2073c7fb64dbSThomas Graf static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
2074c7fb64dbSThomas Graf {
2075ca860fb3SThomas Graf 	struct nlattr *nest;
2076e386c6ebSThomas Graf 
2077ae0be8deSMichal Kubecek 	nest = nla_nest_start_noflag(skb, NDTA_PARMS);
2078ca860fb3SThomas Graf 	if (nest == NULL)
2079ca860fb3SThomas Graf 		return -ENOBUFS;
2080c7fb64dbSThomas Graf 
20819a6308d7SDavid S. Miller 	if ((parms->dev &&
20829a6308d7SDavid S. Miller 	     nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
20836343944bSReshetova, Elena 	    nla_put_u32(skb, NDTPA_REFCNT, refcount_read(&parms->refcnt)) ||
20841f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_QUEUE_LENBYTES,
20851f9248e5SJiri Pirko 			NEIGH_VAR(parms, QUEUE_LEN_BYTES)) ||
20868b5c171bSEric Dumazet 	    /* approximative value for deprecated QUEUE_LEN (in packets) */
20879a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTPA_QUEUE_LEN,
20881f9248e5SJiri Pirko 			NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) ||
20891f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) ||
20901f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) ||
20911f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_UCAST_PROBES,
20921f9248e5SJiri Pirko 			NEIGH_VAR(parms, UCAST_PROBES)) ||
20931f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_MCAST_PROBES,
20941f9248e5SJiri Pirko 			NEIGH_VAR(parms, MCAST_PROBES)) ||
20958da86466SYOSHIFUJI Hideaki/吉藤英明 	    nla_put_u32(skb, NDTPA_MCAST_REPROBES,
20968da86466SYOSHIFUJI Hideaki/吉藤英明 			NEIGH_VAR(parms, MCAST_REPROBES)) ||
20972175d87cSNicolas Dichtel 	    nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time,
20982175d87cSNicolas Dichtel 			  NDTPA_PAD) ||
20999a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
21002175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, BASE_REACHABLE_TIME), NDTPA_PAD) ||
21011f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_GC_STALETIME,
21022175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, GC_STALETIME), NDTPA_PAD) ||
21039a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
21042175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, DELAY_PROBE_TIME), NDTPA_PAD) ||
21051f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_RETRANS_TIME,
21062175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, RETRANS_TIME), NDTPA_PAD) ||
21071f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_ANYCAST_DELAY,
21082175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, ANYCAST_DELAY), NDTPA_PAD) ||
21091f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_PROXY_DELAY,
21102175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, PROXY_DELAY), NDTPA_PAD) ||
21111f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_LOCKTIME,
2112211da42eSYuwei Wang 			  NEIGH_VAR(parms, LOCKTIME), NDTPA_PAD) ||
2113211da42eSYuwei Wang 	    nla_put_msecs(skb, NDTPA_INTERVAL_PROBE_TIME_MS,
2114211da42eSYuwei Wang 			  NEIGH_VAR(parms, INTERVAL_PROBE_TIME_MS), NDTPA_PAD))
21159a6308d7SDavid S. Miller 		goto nla_put_failure;
2116ca860fb3SThomas Graf 	return nla_nest_end(skb, nest);
2117c7fb64dbSThomas Graf 
2118ca860fb3SThomas Graf nla_put_failure:
2119bc3ed28cSThomas Graf 	nla_nest_cancel(skb, nest);
2120bc3ed28cSThomas Graf 	return -EMSGSIZE;
2121c7fb64dbSThomas Graf }
2122c7fb64dbSThomas Graf 
2123ca860fb3SThomas Graf static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
2124ca860fb3SThomas Graf 			      u32 pid, u32 seq, int type, int flags)
2125c7fb64dbSThomas Graf {
2126c7fb64dbSThomas Graf 	struct nlmsghdr *nlh;
2127c7fb64dbSThomas Graf 	struct ndtmsg *ndtmsg;
2128c7fb64dbSThomas Graf 
2129ca860fb3SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2130ca860fb3SThomas Graf 	if (nlh == NULL)
213126932566SPatrick McHardy 		return -EMSGSIZE;
2132c7fb64dbSThomas Graf 
2133ca860fb3SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2134c7fb64dbSThomas Graf 
2135c7fb64dbSThomas Graf 	read_lock_bh(&tbl->lock);
2136c7fb64dbSThomas Graf 	ndtmsg->ndtm_family = tbl->family;
21379ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad1   = 0;
21389ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad2   = 0;
2139c7fb64dbSThomas Graf 
21409a6308d7SDavid S. Miller 	if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
21412175d87cSNicolas Dichtel 	    nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval, NDTA_PAD) ||
21429a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
21439a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
21449a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
21459a6308d7SDavid S. Miller 		goto nla_put_failure;
2146c7fb64dbSThomas Graf 	{
2147c7fb64dbSThomas Graf 		unsigned long now = jiffies;
21489d027e3aSEric Dumazet 		long flush_delta = now - tbl->last_flush;
21499d027e3aSEric Dumazet 		long rand_delta = now - tbl->last_rand;
2150d6bf7817SEric Dumazet 		struct neigh_hash_table *nht;
2151c7fb64dbSThomas Graf 		struct ndt_config ndc = {
2152c7fb64dbSThomas Graf 			.ndtc_key_len		= tbl->key_len,
2153c7fb64dbSThomas Graf 			.ndtc_entry_size	= tbl->entry_size,
2154c7fb64dbSThomas Graf 			.ndtc_entries		= atomic_read(&tbl->entries),
2155c7fb64dbSThomas Graf 			.ndtc_last_flush	= jiffies_to_msecs(flush_delta),
2156c7fb64dbSThomas Graf 			.ndtc_last_rand		= jiffies_to_msecs(rand_delta),
2157c7fb64dbSThomas Graf 			.ndtc_proxy_qlen	= tbl->proxy_queue.qlen,
2158c7fb64dbSThomas Graf 		};
2159c7fb64dbSThomas Graf 
2160d6bf7817SEric Dumazet 		rcu_read_lock_bh();
2161d6bf7817SEric Dumazet 		nht = rcu_dereference_bh(tbl->nht);
21622c2aba6cSDavid S. Miller 		ndc.ndtc_hash_rnd = nht->hash_rnd[0];
2163cd089336SDavid S. Miller 		ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
2164d6bf7817SEric Dumazet 		rcu_read_unlock_bh();
2165d6bf7817SEric Dumazet 
21669a6308d7SDavid S. Miller 		if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
21679a6308d7SDavid S. Miller 			goto nla_put_failure;
2168c7fb64dbSThomas Graf 	}
2169c7fb64dbSThomas Graf 
2170c7fb64dbSThomas Graf 	{
2171c7fb64dbSThomas Graf 		int cpu;
2172c7fb64dbSThomas Graf 		struct ndt_stats ndst;
2173c7fb64dbSThomas Graf 
2174c7fb64dbSThomas Graf 		memset(&ndst, 0, sizeof(ndst));
2175c7fb64dbSThomas Graf 
21766f912042SKAMEZAWA Hiroyuki 		for_each_possible_cpu(cpu) {
2177c7fb64dbSThomas Graf 			struct neigh_statistics	*st;
2178c7fb64dbSThomas Graf 
2179c7fb64dbSThomas Graf 			st = per_cpu_ptr(tbl->stats, cpu);
2180c7fb64dbSThomas Graf 			ndst.ndts_allocs		+= st->allocs;
2181c7fb64dbSThomas Graf 			ndst.ndts_destroys		+= st->destroys;
2182c7fb64dbSThomas Graf 			ndst.ndts_hash_grows		+= st->hash_grows;
2183c7fb64dbSThomas Graf 			ndst.ndts_res_failed		+= st->res_failed;
2184c7fb64dbSThomas Graf 			ndst.ndts_lookups		+= st->lookups;
2185c7fb64dbSThomas Graf 			ndst.ndts_hits			+= st->hits;
2186c7fb64dbSThomas Graf 			ndst.ndts_rcv_probes_mcast	+= st->rcv_probes_mcast;
2187c7fb64dbSThomas Graf 			ndst.ndts_rcv_probes_ucast	+= st->rcv_probes_ucast;
2188c7fb64dbSThomas Graf 			ndst.ndts_periodic_gc_runs	+= st->periodic_gc_runs;
2189c7fb64dbSThomas Graf 			ndst.ndts_forced_gc_runs	+= st->forced_gc_runs;
2190fb811395SRick Jones 			ndst.ndts_table_fulls		+= st->table_fulls;
2191c7fb64dbSThomas Graf 		}
2192c7fb64dbSThomas Graf 
2193b676338fSNicolas Dichtel 		if (nla_put_64bit(skb, NDTA_STATS, sizeof(ndst), &ndst,
2194b676338fSNicolas Dichtel 				  NDTA_PAD))
21959a6308d7SDavid S. Miller 			goto nla_put_failure;
2196c7fb64dbSThomas Graf 	}
2197c7fb64dbSThomas Graf 
2198c7fb64dbSThomas Graf 	BUG_ON(tbl->parms.dev);
2199c7fb64dbSThomas Graf 	if (neightbl_fill_parms(skb, &tbl->parms) < 0)
2200ca860fb3SThomas Graf 		goto nla_put_failure;
2201c7fb64dbSThomas Graf 
2202c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
2203053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2204053c095aSJohannes Berg 	return 0;
2205c7fb64dbSThomas Graf 
2206ca860fb3SThomas Graf nla_put_failure:
2207c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
220826932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
220926932566SPatrick McHardy 	return -EMSGSIZE;
2210c7fb64dbSThomas Graf }
2211c7fb64dbSThomas Graf 
2212ca860fb3SThomas Graf static int neightbl_fill_param_info(struct sk_buff *skb,
2213ca860fb3SThomas Graf 				    struct neigh_table *tbl,
2214c7fb64dbSThomas Graf 				    struct neigh_parms *parms,
2215ca860fb3SThomas Graf 				    u32 pid, u32 seq, int type,
2216ca860fb3SThomas Graf 				    unsigned int flags)
2217c7fb64dbSThomas Graf {
2218c7fb64dbSThomas Graf 	struct ndtmsg *ndtmsg;
2219c7fb64dbSThomas Graf 	struct nlmsghdr *nlh;
2220c7fb64dbSThomas Graf 
2221ca860fb3SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2222ca860fb3SThomas Graf 	if (nlh == NULL)
222326932566SPatrick McHardy 		return -EMSGSIZE;
2224c7fb64dbSThomas Graf 
2225ca860fb3SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2226c7fb64dbSThomas Graf 
2227c7fb64dbSThomas Graf 	read_lock_bh(&tbl->lock);
2228c7fb64dbSThomas Graf 	ndtmsg->ndtm_family = tbl->family;
22299ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad1   = 0;
22309ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad2   = 0;
2231c7fb64dbSThomas Graf 
2232ca860fb3SThomas Graf 	if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
2233ca860fb3SThomas Graf 	    neightbl_fill_parms(skb, parms) < 0)
2234ca860fb3SThomas Graf 		goto errout;
2235c7fb64dbSThomas Graf 
2236c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
2237053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2238053c095aSJohannes Berg 	return 0;
2239ca860fb3SThomas Graf errout:
2240c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
224126932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
224226932566SPatrick McHardy 	return -EMSGSIZE;
2243c7fb64dbSThomas Graf }
2244c7fb64dbSThomas Graf 
2245ef7c79edSPatrick McHardy static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
22466b3f8674SThomas Graf 	[NDTA_NAME]		= { .type = NLA_STRING },
22476b3f8674SThomas Graf 	[NDTA_THRESH1]		= { .type = NLA_U32 },
22486b3f8674SThomas Graf 	[NDTA_THRESH2]		= { .type = NLA_U32 },
22496b3f8674SThomas Graf 	[NDTA_THRESH3]		= { .type = NLA_U32 },
22506b3f8674SThomas Graf 	[NDTA_GC_INTERVAL]	= { .type = NLA_U64 },
22516b3f8674SThomas Graf 	[NDTA_PARMS]		= { .type = NLA_NESTED },
22526b3f8674SThomas Graf };
22536b3f8674SThomas Graf 
2254ef7c79edSPatrick McHardy static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
22556b3f8674SThomas Graf 	[NDTPA_IFINDEX]			= { .type = NLA_U32 },
22566b3f8674SThomas Graf 	[NDTPA_QUEUE_LEN]		= { .type = NLA_U32 },
22576b3f8674SThomas Graf 	[NDTPA_PROXY_QLEN]		= { .type = NLA_U32 },
22586b3f8674SThomas Graf 	[NDTPA_APP_PROBES]		= { .type = NLA_U32 },
22596b3f8674SThomas Graf 	[NDTPA_UCAST_PROBES]		= { .type = NLA_U32 },
22606b3f8674SThomas Graf 	[NDTPA_MCAST_PROBES]		= { .type = NLA_U32 },
22618da86466SYOSHIFUJI Hideaki/吉藤英明 	[NDTPA_MCAST_REPROBES]		= { .type = NLA_U32 },
22626b3f8674SThomas Graf 	[NDTPA_BASE_REACHABLE_TIME]	= { .type = NLA_U64 },
22636b3f8674SThomas Graf 	[NDTPA_GC_STALETIME]		= { .type = NLA_U64 },
22646b3f8674SThomas Graf 	[NDTPA_DELAY_PROBE_TIME]	= { .type = NLA_U64 },
22656b3f8674SThomas Graf 	[NDTPA_RETRANS_TIME]		= { .type = NLA_U64 },
22666b3f8674SThomas Graf 	[NDTPA_ANYCAST_DELAY]		= { .type = NLA_U64 },
22676b3f8674SThomas Graf 	[NDTPA_PROXY_DELAY]		= { .type = NLA_U64 },
22686b3f8674SThomas Graf 	[NDTPA_LOCKTIME]		= { .type = NLA_U64 },
2269211da42eSYuwei Wang 	[NDTPA_INTERVAL_PROBE_TIME_MS]	= { .type = NLA_U64, .min = 1 },
22706b3f8674SThomas Graf };
22716b3f8674SThomas Graf 
2272c21ef3e3SDavid Ahern static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
2273c21ef3e3SDavid Ahern 			struct netlink_ext_ack *extack)
2274c7fb64dbSThomas Graf {
22753b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
2276c7fb64dbSThomas Graf 	struct neigh_table *tbl;
22776b3f8674SThomas Graf 	struct ndtmsg *ndtmsg;
22786b3f8674SThomas Graf 	struct nlattr *tb[NDTA_MAX+1];
2279d7480fd3SWANG Cong 	bool found = false;
2280d7480fd3SWANG Cong 	int err, tidx;
2281c7fb64dbSThomas Graf 
22828cb08174SJohannes Berg 	err = nlmsg_parse_deprecated(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
2283c21ef3e3SDavid Ahern 				     nl_neightbl_policy, extack);
22846b3f8674SThomas Graf 	if (err < 0)
22856b3f8674SThomas Graf 		goto errout;
2286c7fb64dbSThomas Graf 
22876b3f8674SThomas Graf 	if (tb[NDTA_NAME] == NULL) {
22886b3f8674SThomas Graf 		err = -EINVAL;
22896b3f8674SThomas Graf 		goto errout;
22906b3f8674SThomas Graf 	}
22916b3f8674SThomas Graf 
22926b3f8674SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2293d7480fd3SWANG Cong 
2294d7480fd3SWANG Cong 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2295d7480fd3SWANG Cong 		tbl = neigh_tables[tidx];
2296d7480fd3SWANG Cong 		if (!tbl)
2297d7480fd3SWANG Cong 			continue;
2298c7fb64dbSThomas Graf 		if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
2299c7fb64dbSThomas Graf 			continue;
2300d7480fd3SWANG Cong 		if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) {
2301d7480fd3SWANG Cong 			found = true;
2302c7fb64dbSThomas Graf 			break;
2303c7fb64dbSThomas Graf 		}
2304c7fb64dbSThomas Graf 	}
2305c7fb64dbSThomas Graf 
2306d7480fd3SWANG Cong 	if (!found)
2307d7480fd3SWANG Cong 		return -ENOENT;
2308d7480fd3SWANG Cong 
2309c7fb64dbSThomas Graf 	/*
2310c7fb64dbSThomas Graf 	 * We acquire tbl->lock to be nice to the periodic timers and
2311c7fb64dbSThomas Graf 	 * make sure they always see a consistent set of values.
2312c7fb64dbSThomas Graf 	 */
2313c7fb64dbSThomas Graf 	write_lock_bh(&tbl->lock);
2314c7fb64dbSThomas Graf 
23156b3f8674SThomas Graf 	if (tb[NDTA_PARMS]) {
23166b3f8674SThomas Graf 		struct nlattr *tbp[NDTPA_MAX+1];
2317c7fb64dbSThomas Graf 		struct neigh_parms *p;
23186b3f8674SThomas Graf 		int i, ifindex = 0;
2319c7fb64dbSThomas Graf 
23208cb08174SJohannes Berg 		err = nla_parse_nested_deprecated(tbp, NDTPA_MAX,
23218cb08174SJohannes Berg 						  tb[NDTA_PARMS],
2322c21ef3e3SDavid Ahern 						  nl_ntbl_parm_policy, extack);
23236b3f8674SThomas Graf 		if (err < 0)
23246b3f8674SThomas Graf 			goto errout_tbl_lock;
2325c7fb64dbSThomas Graf 
23266b3f8674SThomas Graf 		if (tbp[NDTPA_IFINDEX])
23276b3f8674SThomas Graf 			ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
2328c7fb64dbSThomas Graf 
232997fd5bc7STobias Klauser 		p = lookup_neigh_parms(tbl, net, ifindex);
2330c7fb64dbSThomas Graf 		if (p == NULL) {
2331c7fb64dbSThomas Graf 			err = -ENOENT;
23326b3f8674SThomas Graf 			goto errout_tbl_lock;
2333c7fb64dbSThomas Graf 		}
2334c7fb64dbSThomas Graf 
23356b3f8674SThomas Graf 		for (i = 1; i <= NDTPA_MAX; i++) {
23366b3f8674SThomas Graf 			if (tbp[i] == NULL)
23376b3f8674SThomas Graf 				continue;
2338c7fb64dbSThomas Graf 
23396b3f8674SThomas Graf 			switch (i) {
23406b3f8674SThomas Graf 			case NDTPA_QUEUE_LEN:
23411f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
23421f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]) *
23431f9248e5SJiri Pirko 					      SKB_TRUESIZE(ETH_FRAME_LEN));
23448b5c171bSEric Dumazet 				break;
23458b5c171bSEric Dumazet 			case NDTPA_QUEUE_LENBYTES:
23461f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
23471f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23486b3f8674SThomas Graf 				break;
23496b3f8674SThomas Graf 			case NDTPA_PROXY_QLEN:
23501f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, PROXY_QLEN,
23511f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23526b3f8674SThomas Graf 				break;
23536b3f8674SThomas Graf 			case NDTPA_APP_PROBES:
23541f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, APP_PROBES,
23551f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23566b3f8674SThomas Graf 				break;
23576b3f8674SThomas Graf 			case NDTPA_UCAST_PROBES:
23581f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, UCAST_PROBES,
23591f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23606b3f8674SThomas Graf 				break;
23616b3f8674SThomas Graf 			case NDTPA_MCAST_PROBES:
23621f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, MCAST_PROBES,
23631f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23646b3f8674SThomas Graf 				break;
23658da86466SYOSHIFUJI Hideaki/吉藤英明 			case NDTPA_MCAST_REPROBES:
23668da86466SYOSHIFUJI Hideaki/吉藤英明 				NEIGH_VAR_SET(p, MCAST_REPROBES,
23678da86466SYOSHIFUJI Hideaki/吉藤英明 					      nla_get_u32(tbp[i]));
23688da86466SYOSHIFUJI Hideaki/吉藤英明 				break;
23696b3f8674SThomas Graf 			case NDTPA_BASE_REACHABLE_TIME:
23701f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,
23711f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
23724bf6980dSJean-Francois Remy 				/* update reachable_time as well, otherwise, the change will
23734bf6980dSJean-Francois Remy 				 * only be effective after the next time neigh_periodic_work
23744bf6980dSJean-Francois Remy 				 * decides to recompute it (can be multiple minutes)
23754bf6980dSJean-Francois Remy 				 */
23764bf6980dSJean-Francois Remy 				p->reachable_time =
23774bf6980dSJean-Francois Remy 					neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
23786b3f8674SThomas Graf 				break;
23796b3f8674SThomas Graf 			case NDTPA_GC_STALETIME:
23801f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, GC_STALETIME,
23811f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
23826b3f8674SThomas Graf 				break;
23836b3f8674SThomas Graf 			case NDTPA_DELAY_PROBE_TIME:
23841f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, DELAY_PROBE_TIME,
23851f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
23862a4501aeSIdo Schimmel 				call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
23876b3f8674SThomas Graf 				break;
2388211da42eSYuwei Wang 			case NDTPA_INTERVAL_PROBE_TIME_MS:
2389211da42eSYuwei Wang 				NEIGH_VAR_SET(p, INTERVAL_PROBE_TIME_MS,
2390211da42eSYuwei Wang 					      nla_get_msecs(tbp[i]));
2391211da42eSYuwei Wang 				break;
23926b3f8674SThomas Graf 			case NDTPA_RETRANS_TIME:
23931f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, RETRANS_TIME,
23941f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
23956b3f8674SThomas Graf 				break;
23966b3f8674SThomas Graf 			case NDTPA_ANYCAST_DELAY:
23973977458cSJiri Pirko 				NEIGH_VAR_SET(p, ANYCAST_DELAY,
23983977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
23996b3f8674SThomas Graf 				break;
24006b3f8674SThomas Graf 			case NDTPA_PROXY_DELAY:
24013977458cSJiri Pirko 				NEIGH_VAR_SET(p, PROXY_DELAY,
24023977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
24036b3f8674SThomas Graf 				break;
24046b3f8674SThomas Graf 			case NDTPA_LOCKTIME:
24053977458cSJiri Pirko 				NEIGH_VAR_SET(p, LOCKTIME,
24063977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
24076b3f8674SThomas Graf 				break;
2408c7fb64dbSThomas Graf 			}
24096b3f8674SThomas Graf 		}
24106b3f8674SThomas Graf 	}
24116b3f8674SThomas Graf 
2412dc25c676SGao feng 	err = -ENOENT;
2413dc25c676SGao feng 	if ((tb[NDTA_THRESH1] || tb[NDTA_THRESH2] ||
2414dc25c676SGao feng 	     tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]) &&
2415dc25c676SGao feng 	    !net_eq(net, &init_net))
2416dc25c676SGao feng 		goto errout_tbl_lock;
2417dc25c676SGao feng 
24186b3f8674SThomas Graf 	if (tb[NDTA_THRESH1])
24196b3f8674SThomas Graf 		tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
24206b3f8674SThomas Graf 
24216b3f8674SThomas Graf 	if (tb[NDTA_THRESH2])
24226b3f8674SThomas Graf 		tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
24236b3f8674SThomas Graf 
24246b3f8674SThomas Graf 	if (tb[NDTA_THRESH3])
24256b3f8674SThomas Graf 		tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
24266b3f8674SThomas Graf 
24276b3f8674SThomas Graf 	if (tb[NDTA_GC_INTERVAL])
24286b3f8674SThomas Graf 		tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2429c7fb64dbSThomas Graf 
2430c7fb64dbSThomas Graf 	err = 0;
2431c7fb64dbSThomas Graf 
24326b3f8674SThomas Graf errout_tbl_lock:
2433c7fb64dbSThomas Graf 	write_unlock_bh(&tbl->lock);
24346b3f8674SThomas Graf errout:
2435c7fb64dbSThomas Graf 	return err;
2436c7fb64dbSThomas Graf }
2437c7fb64dbSThomas Graf 
24389632d47fSDavid Ahern static int neightbl_valid_dump_info(const struct nlmsghdr *nlh,
24399632d47fSDavid Ahern 				    struct netlink_ext_ack *extack)
24409632d47fSDavid Ahern {
24419632d47fSDavid Ahern 	struct ndtmsg *ndtm;
24429632d47fSDavid Ahern 
24439632d47fSDavid Ahern 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndtm))) {
24449632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid header for neighbor table dump request");
24459632d47fSDavid Ahern 		return -EINVAL;
24469632d47fSDavid Ahern 	}
24479632d47fSDavid Ahern 
24489632d47fSDavid Ahern 	ndtm = nlmsg_data(nlh);
24499632d47fSDavid Ahern 	if (ndtm->ndtm_pad1  || ndtm->ndtm_pad2) {
24509632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor table dump request");
24519632d47fSDavid Ahern 		return -EINVAL;
24529632d47fSDavid Ahern 	}
24539632d47fSDavid Ahern 
24549632d47fSDavid Ahern 	if (nlmsg_attrlen(nlh, sizeof(*ndtm))) {
24559632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid data after header in neighbor table dump request");
24569632d47fSDavid Ahern 		return -EINVAL;
24579632d47fSDavid Ahern 	}
24589632d47fSDavid Ahern 
24599632d47fSDavid Ahern 	return 0;
24609632d47fSDavid Ahern }
24619632d47fSDavid Ahern 
2462c8822a4eSThomas Graf static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
2463c7fb64dbSThomas Graf {
24649632d47fSDavid Ahern 	const struct nlmsghdr *nlh = cb->nlh;
24653b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
2466ca860fb3SThomas Graf 	int family, tidx, nidx = 0;
2467ca860fb3SThomas Graf 	int tbl_skip = cb->args[0];
2468ca860fb3SThomas Graf 	int neigh_skip = cb->args[1];
2469c7fb64dbSThomas Graf 	struct neigh_table *tbl;
2470c7fb64dbSThomas Graf 
24719632d47fSDavid Ahern 	if (cb->strict_check) {
24729632d47fSDavid Ahern 		int err = neightbl_valid_dump_info(nlh, cb->extack);
24739632d47fSDavid Ahern 
24749632d47fSDavid Ahern 		if (err < 0)
24759632d47fSDavid Ahern 			return err;
24769632d47fSDavid Ahern 	}
24779632d47fSDavid Ahern 
24789632d47fSDavid Ahern 	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
2479c7fb64dbSThomas Graf 
2480d7480fd3SWANG Cong 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2481c7fb64dbSThomas Graf 		struct neigh_parms *p;
2482c7fb64dbSThomas Graf 
2483d7480fd3SWANG Cong 		tbl = neigh_tables[tidx];
2484d7480fd3SWANG Cong 		if (!tbl)
2485d7480fd3SWANG Cong 			continue;
2486d7480fd3SWANG Cong 
2487ca860fb3SThomas Graf 		if (tidx < tbl_skip || (family && tbl->family != family))
2488c7fb64dbSThomas Graf 			continue;
2489c7fb64dbSThomas Graf 
249015e47304SEric W. Biederman 		if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
24919632d47fSDavid Ahern 				       nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
24927b46a644SDavid S. Miller 				       NLM_F_MULTI) < 0)
2493c7fb64dbSThomas Graf 			break;
2494c7fb64dbSThomas Graf 
249575fbfd33SNicolas Dichtel 		nidx = 0;
249675fbfd33SNicolas Dichtel 		p = list_next_entry(&tbl->parms, list);
249775fbfd33SNicolas Dichtel 		list_for_each_entry_from(p, &tbl->parms_list, list) {
2498878628fbSYOSHIFUJI Hideaki 			if (!net_eq(neigh_parms_net(p), net))
2499426b5303SEric W. Biederman 				continue;
2500426b5303SEric W. Biederman 
2501efc683fcSGautam Kachroo 			if (nidx < neigh_skip)
2502efc683fcSGautam Kachroo 				goto next;
2503c7fb64dbSThomas Graf 
2504ca860fb3SThomas Graf 			if (neightbl_fill_param_info(skb, tbl, p,
250515e47304SEric W. Biederman 						     NETLINK_CB(cb->skb).portid,
25069632d47fSDavid Ahern 						     nlh->nlmsg_seq,
2507ca860fb3SThomas Graf 						     RTM_NEWNEIGHTBL,
25087b46a644SDavid S. Miller 						     NLM_F_MULTI) < 0)
2509c7fb64dbSThomas Graf 				goto out;
2510efc683fcSGautam Kachroo 		next:
2511efc683fcSGautam Kachroo 			nidx++;
2512c7fb64dbSThomas Graf 		}
2513c7fb64dbSThomas Graf 
2514ca860fb3SThomas Graf 		neigh_skip = 0;
2515c7fb64dbSThomas Graf 	}
2516c7fb64dbSThomas Graf out:
2517ca860fb3SThomas Graf 	cb->args[0] = tidx;
2518ca860fb3SThomas Graf 	cb->args[1] = nidx;
2519c7fb64dbSThomas Graf 
2520c7fb64dbSThomas Graf 	return skb->len;
2521c7fb64dbSThomas Graf }
25221da177e4SLinus Torvalds 
25238b8aec50SThomas Graf static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
25248b8aec50SThomas Graf 			   u32 pid, u32 seq, int type, unsigned int flags)
25251da177e4SLinus Torvalds {
25262c611ad9SRoopa Prabhu 	u32 neigh_flags, neigh_flags_ext;
25271da177e4SLinus Torvalds 	unsigned long now = jiffies;
25281da177e4SLinus Torvalds 	struct nda_cacheinfo ci;
25298b8aec50SThomas Graf 	struct nlmsghdr *nlh;
25308b8aec50SThomas Graf 	struct ndmsg *ndm;
25311da177e4SLinus Torvalds 
25328b8aec50SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
25338b8aec50SThomas Graf 	if (nlh == NULL)
253426932566SPatrick McHardy 		return -EMSGSIZE;
25358b8aec50SThomas Graf 
25362c611ad9SRoopa Prabhu 	neigh_flags_ext = neigh->flags >> NTF_EXT_SHIFT;
25372c611ad9SRoopa Prabhu 	neigh_flags     = neigh->flags & NTF_OLD_MASK;
25382c611ad9SRoopa Prabhu 
25398b8aec50SThomas Graf 	ndm = nlmsg_data(nlh);
25408b8aec50SThomas Graf 	ndm->ndm_family	 = neigh->ops->family;
25419ef1d4c7SPatrick McHardy 	ndm->ndm_pad1    = 0;
25429ef1d4c7SPatrick McHardy 	ndm->ndm_pad2    = 0;
25432c611ad9SRoopa Prabhu 	ndm->ndm_flags	 = neigh_flags;
25448b8aec50SThomas Graf 	ndm->ndm_type	 = neigh->type;
25458b8aec50SThomas Graf 	ndm->ndm_ifindex = neigh->dev->ifindex;
25461da177e4SLinus Torvalds 
25479a6308d7SDavid S. Miller 	if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
25489a6308d7SDavid S. Miller 		goto nla_put_failure;
25498b8aec50SThomas Graf 
25508b8aec50SThomas Graf 	read_lock_bh(&neigh->lock);
25518b8aec50SThomas Graf 	ndm->ndm_state	 = neigh->nud_state;
25520ed8ddf4SEric Dumazet 	if (neigh->nud_state & NUD_VALID) {
25530ed8ddf4SEric Dumazet 		char haddr[MAX_ADDR_LEN];
25540ed8ddf4SEric Dumazet 
25550ed8ddf4SEric Dumazet 		neigh_ha_snapshot(haddr, neigh, neigh->dev);
25560ed8ddf4SEric Dumazet 		if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
25578b8aec50SThomas Graf 			read_unlock_bh(&neigh->lock);
25588b8aec50SThomas Graf 			goto nla_put_failure;
25598b8aec50SThomas Graf 		}
25600ed8ddf4SEric Dumazet 	}
25618b8aec50SThomas Graf 
2562b9f5f52cSStephen Hemminger 	ci.ndm_used	 = jiffies_to_clock_t(now - neigh->used);
2563b9f5f52cSStephen Hemminger 	ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2564b9f5f52cSStephen Hemminger 	ci.ndm_updated	 = jiffies_to_clock_t(now - neigh->updated);
25659f237430SReshetova, Elena 	ci.ndm_refcnt	 = refcount_read(&neigh->refcnt) - 1;
25668b8aec50SThomas Graf 	read_unlock_bh(&neigh->lock);
25678b8aec50SThomas Graf 
25689a6308d7SDavid S. Miller 	if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
25699a6308d7SDavid S. Miller 	    nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
25709a6308d7SDavid S. Miller 		goto nla_put_failure;
25718b8aec50SThomas Graf 
2572df9b0e30SDavid Ahern 	if (neigh->protocol && nla_put_u8(skb, NDA_PROTOCOL, neigh->protocol))
2573df9b0e30SDavid Ahern 		goto nla_put_failure;
25742c611ad9SRoopa Prabhu 	if (neigh_flags_ext && nla_put_u32(skb, NDA_FLAGS_EXT, neigh_flags_ext))
25752c611ad9SRoopa Prabhu 		goto nla_put_failure;
2576df9b0e30SDavid Ahern 
2577053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2578053c095aSJohannes Berg 	return 0;
25798b8aec50SThomas Graf 
25808b8aec50SThomas Graf nla_put_failure:
258126932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
258226932566SPatrick McHardy 	return -EMSGSIZE;
25831da177e4SLinus Torvalds }
25841da177e4SLinus Torvalds 
258584920c14STony Zelenoff static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
258684920c14STony Zelenoff 			    u32 pid, u32 seq, int type, unsigned int flags,
258784920c14STony Zelenoff 			    struct neigh_table *tbl)
258884920c14STony Zelenoff {
25892c611ad9SRoopa Prabhu 	u32 neigh_flags, neigh_flags_ext;
259084920c14STony Zelenoff 	struct nlmsghdr *nlh;
259184920c14STony Zelenoff 	struct ndmsg *ndm;
259284920c14STony Zelenoff 
259384920c14STony Zelenoff 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
259484920c14STony Zelenoff 	if (nlh == NULL)
259584920c14STony Zelenoff 		return -EMSGSIZE;
259684920c14STony Zelenoff 
25972c611ad9SRoopa Prabhu 	neigh_flags_ext = pn->flags >> NTF_EXT_SHIFT;
25982c611ad9SRoopa Prabhu 	neigh_flags     = pn->flags & NTF_OLD_MASK;
25992c611ad9SRoopa Prabhu 
260084920c14STony Zelenoff 	ndm = nlmsg_data(nlh);
260184920c14STony Zelenoff 	ndm->ndm_family	 = tbl->family;
260284920c14STony Zelenoff 	ndm->ndm_pad1    = 0;
260384920c14STony Zelenoff 	ndm->ndm_pad2    = 0;
26042c611ad9SRoopa Prabhu 	ndm->ndm_flags	 = neigh_flags | NTF_PROXY;
2605545469f7SJun Zhao 	ndm->ndm_type	 = RTN_UNICAST;
26066adc5fd6SKonstantin Khlebnikov 	ndm->ndm_ifindex = pn->dev ? pn->dev->ifindex : 0;
260784920c14STony Zelenoff 	ndm->ndm_state	 = NUD_NONE;
260884920c14STony Zelenoff 
26099a6308d7SDavid S. Miller 	if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
26109a6308d7SDavid S. Miller 		goto nla_put_failure;
261184920c14STony Zelenoff 
2612df9b0e30SDavid Ahern 	if (pn->protocol && nla_put_u8(skb, NDA_PROTOCOL, pn->protocol))
2613df9b0e30SDavid Ahern 		goto nla_put_failure;
26142c611ad9SRoopa Prabhu 	if (neigh_flags_ext && nla_put_u32(skb, NDA_FLAGS_EXT, neigh_flags_ext))
26152c611ad9SRoopa Prabhu 		goto nla_put_failure;
2616df9b0e30SDavid Ahern 
2617053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2618053c095aSJohannes Berg 	return 0;
261984920c14STony Zelenoff 
262084920c14STony Zelenoff nla_put_failure:
262184920c14STony Zelenoff 	nlmsg_cancel(skb, nlh);
262284920c14STony Zelenoff 	return -EMSGSIZE;
262384920c14STony Zelenoff }
262484920c14STony Zelenoff 
26257b8f7a40SRoopa Prabhu static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid)
2626d961db35SThomas Graf {
2627d961db35SThomas Graf 	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
26287b8f7a40SRoopa Prabhu 	__neigh_notify(neigh, RTM_NEWNEIGH, 0, nlmsg_pid);
2629d961db35SThomas Graf }
26301da177e4SLinus Torvalds 
263121fdd092SDavid Ahern static bool neigh_master_filtered(struct net_device *dev, int master_idx)
263221fdd092SDavid Ahern {
263321fdd092SDavid Ahern 	struct net_device *master;
263421fdd092SDavid Ahern 
263521fdd092SDavid Ahern 	if (!master_idx)
263621fdd092SDavid Ahern 		return false;
263721fdd092SDavid Ahern 
2638aab456dfSEric Dumazet 	master = dev ? netdev_master_upper_dev_get(dev) : NULL;
2639d3432bf1SLahav Schlesinger 
2640d3432bf1SLahav Schlesinger 	/* 0 is already used to denote NDA_MASTER wasn't passed, therefore need another
2641d3432bf1SLahav Schlesinger 	 * invalid value for ifindex to denote "no master".
2642d3432bf1SLahav Schlesinger 	 */
2643d3432bf1SLahav Schlesinger 	if (master_idx == -1)
2644d3432bf1SLahav Schlesinger 		return !!master;
2645d3432bf1SLahav Schlesinger 
264621fdd092SDavid Ahern 	if (!master || master->ifindex != master_idx)
264721fdd092SDavid Ahern 		return true;
264821fdd092SDavid Ahern 
264921fdd092SDavid Ahern 	return false;
265021fdd092SDavid Ahern }
265121fdd092SDavid Ahern 
265216660f0bSDavid Ahern static bool neigh_ifindex_filtered(struct net_device *dev, int filter_idx)
265316660f0bSDavid Ahern {
2654aab456dfSEric Dumazet 	if (filter_idx && (!dev || dev->ifindex != filter_idx))
265516660f0bSDavid Ahern 		return true;
265616660f0bSDavid Ahern 
265716660f0bSDavid Ahern 	return false;
265816660f0bSDavid Ahern }
265916660f0bSDavid Ahern 
26606f52f80eSDavid Ahern struct neigh_dump_filter {
26616f52f80eSDavid Ahern 	int master_idx;
26626f52f80eSDavid Ahern 	int dev_idx;
26636f52f80eSDavid Ahern };
26646f52f80eSDavid Ahern 
26651da177e4SLinus Torvalds static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
26666f52f80eSDavid Ahern 			    struct netlink_callback *cb,
26676f52f80eSDavid Ahern 			    struct neigh_dump_filter *filter)
26681da177e4SLinus Torvalds {
26693b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
26701da177e4SLinus Torvalds 	struct neighbour *n;
26711da177e4SLinus Torvalds 	int rc, h, s_h = cb->args[1];
26721da177e4SLinus Torvalds 	int idx, s_idx = idx = cb->args[2];
2673d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
267421fdd092SDavid Ahern 	unsigned int flags = NLM_F_MULTI;
267521fdd092SDavid Ahern 
26766f52f80eSDavid Ahern 	if (filter->dev_idx || filter->master_idx)
267721fdd092SDavid Ahern 		flags |= NLM_F_DUMP_FILTERED;
26781da177e4SLinus Torvalds 
2679d6bf7817SEric Dumazet 	rcu_read_lock_bh();
2680d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
2681d6bf7817SEric Dumazet 
26824bd6683bSEric Dumazet 	for (h = s_h; h < (1 << nht->hash_shift); h++) {
26831da177e4SLinus Torvalds 		if (h > s_h)
26841da177e4SLinus Torvalds 			s_idx = 0;
2685767e97e1SEric Dumazet 		for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2686767e97e1SEric Dumazet 		     n != NULL;
2687767e97e1SEric Dumazet 		     n = rcu_dereference_bh(n->next)) {
268818502acdSZhang Shengju 			if (idx < s_idx || !net_eq(dev_net(n->dev), net))
268918502acdSZhang Shengju 				goto next;
26906f52f80eSDavid Ahern 			if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
26916f52f80eSDavid Ahern 			    neigh_master_filtered(n->dev, filter->master_idx))
2692efc683fcSGautam Kachroo 				goto next;
269315e47304SEric W. Biederman 			if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
26941da177e4SLinus Torvalds 					    cb->nlh->nlmsg_seq,
2695b6544c0bSJamal Hadi Salim 					    RTM_NEWNEIGH,
269621fdd092SDavid Ahern 					    flags) < 0) {
26971da177e4SLinus Torvalds 				rc = -1;
26981da177e4SLinus Torvalds 				goto out;
26991da177e4SLinus Torvalds 			}
2700efc683fcSGautam Kachroo next:
2701efc683fcSGautam Kachroo 			idx++;
27021da177e4SLinus Torvalds 		}
27031da177e4SLinus Torvalds 	}
27041da177e4SLinus Torvalds 	rc = skb->len;
27051da177e4SLinus Torvalds out:
2706d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
27071da177e4SLinus Torvalds 	cb->args[1] = h;
27081da177e4SLinus Torvalds 	cb->args[2] = idx;
27091da177e4SLinus Torvalds 	return rc;
27101da177e4SLinus Torvalds }
27111da177e4SLinus Torvalds 
271284920c14STony Zelenoff static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
27136f52f80eSDavid Ahern 			     struct netlink_callback *cb,
27146f52f80eSDavid Ahern 			     struct neigh_dump_filter *filter)
271584920c14STony Zelenoff {
271684920c14STony Zelenoff 	struct pneigh_entry *n;
271784920c14STony Zelenoff 	struct net *net = sock_net(skb->sk);
271884920c14STony Zelenoff 	int rc, h, s_h = cb->args[3];
271984920c14STony Zelenoff 	int idx, s_idx = idx = cb->args[4];
27206f52f80eSDavid Ahern 	unsigned int flags = NLM_F_MULTI;
27216f52f80eSDavid Ahern 
27226f52f80eSDavid Ahern 	if (filter->dev_idx || filter->master_idx)
27236f52f80eSDavid Ahern 		flags |= NLM_F_DUMP_FILTERED;
272484920c14STony Zelenoff 
272584920c14STony Zelenoff 	read_lock_bh(&tbl->lock);
272684920c14STony Zelenoff 
27274bd6683bSEric Dumazet 	for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
272884920c14STony Zelenoff 		if (h > s_h)
272984920c14STony Zelenoff 			s_idx = 0;
273084920c14STony Zelenoff 		for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
273118502acdSZhang Shengju 			if (idx < s_idx || pneigh_net(n) != net)
273284920c14STony Zelenoff 				goto next;
27336f52f80eSDavid Ahern 			if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
27346f52f80eSDavid Ahern 			    neigh_master_filtered(n->dev, filter->master_idx))
27356f52f80eSDavid Ahern 				goto next;
273615e47304SEric W. Biederman 			if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
273784920c14STony Zelenoff 					    cb->nlh->nlmsg_seq,
27386f52f80eSDavid Ahern 					    RTM_NEWNEIGH, flags, tbl) < 0) {
273984920c14STony Zelenoff 				read_unlock_bh(&tbl->lock);
274084920c14STony Zelenoff 				rc = -1;
274184920c14STony Zelenoff 				goto out;
274284920c14STony Zelenoff 			}
274384920c14STony Zelenoff 		next:
274484920c14STony Zelenoff 			idx++;
274584920c14STony Zelenoff 		}
274684920c14STony Zelenoff 	}
274784920c14STony Zelenoff 
274884920c14STony Zelenoff 	read_unlock_bh(&tbl->lock);
274984920c14STony Zelenoff 	rc = skb->len;
275084920c14STony Zelenoff out:
275184920c14STony Zelenoff 	cb->args[3] = h;
275284920c14STony Zelenoff 	cb->args[4] = idx;
275384920c14STony Zelenoff 	return rc;
275484920c14STony Zelenoff 
275584920c14STony Zelenoff }
275684920c14STony Zelenoff 
275751183d23SDavid Ahern static int neigh_valid_dump_req(const struct nlmsghdr *nlh,
275851183d23SDavid Ahern 				bool strict_check,
275951183d23SDavid Ahern 				struct neigh_dump_filter *filter,
276051183d23SDavid Ahern 				struct netlink_ext_ack *extack)
276151183d23SDavid Ahern {
276251183d23SDavid Ahern 	struct nlattr *tb[NDA_MAX + 1];
276351183d23SDavid Ahern 	int err, i;
276451183d23SDavid Ahern 
276551183d23SDavid Ahern 	if (strict_check) {
276651183d23SDavid Ahern 		struct ndmsg *ndm;
276751183d23SDavid Ahern 
276851183d23SDavid Ahern 		if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
276951183d23SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid header for neighbor dump request");
277051183d23SDavid Ahern 			return -EINVAL;
277151183d23SDavid Ahern 		}
277251183d23SDavid Ahern 
277351183d23SDavid Ahern 		ndm = nlmsg_data(nlh);
277451183d23SDavid Ahern 		if (ndm->ndm_pad1  || ndm->ndm_pad2  || ndm->ndm_ifindex ||
2775c0fde870SDavid Ahern 		    ndm->ndm_state || ndm->ndm_type) {
277651183d23SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor dump request");
277751183d23SDavid Ahern 			return -EINVAL;
277851183d23SDavid Ahern 		}
277951183d23SDavid Ahern 
2780c0fde870SDavid Ahern 		if (ndm->ndm_flags & ~NTF_PROXY) {
2781c0fde870SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor dump request");
2782c0fde870SDavid Ahern 			return -EINVAL;
2783c0fde870SDavid Ahern 		}
2784c0fde870SDavid Ahern 
27858cb08174SJohannes Berg 		err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg),
27868cb08174SJohannes Berg 						    tb, NDA_MAX, nda_policy,
27878cb08174SJohannes Berg 						    extack);
278851183d23SDavid Ahern 	} else {
27898cb08174SJohannes Berg 		err = nlmsg_parse_deprecated(nlh, sizeof(struct ndmsg), tb,
27908cb08174SJohannes Berg 					     NDA_MAX, nda_policy, extack);
279151183d23SDavid Ahern 	}
279251183d23SDavid Ahern 	if (err < 0)
279351183d23SDavid Ahern 		return err;
279451183d23SDavid Ahern 
279551183d23SDavid Ahern 	for (i = 0; i <= NDA_MAX; ++i) {
279651183d23SDavid Ahern 		if (!tb[i])
279751183d23SDavid Ahern 			continue;
279851183d23SDavid Ahern 
279951183d23SDavid Ahern 		/* all new attributes should require strict_check */
280051183d23SDavid Ahern 		switch (i) {
280151183d23SDavid Ahern 		case NDA_IFINDEX:
280251183d23SDavid Ahern 			filter->dev_idx = nla_get_u32(tb[i]);
280351183d23SDavid Ahern 			break;
280451183d23SDavid Ahern 		case NDA_MASTER:
280551183d23SDavid Ahern 			filter->master_idx = nla_get_u32(tb[i]);
280651183d23SDavid Ahern 			break;
280751183d23SDavid Ahern 		default:
280851183d23SDavid Ahern 			if (strict_check) {
280951183d23SDavid Ahern 				NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor dump request");
281051183d23SDavid Ahern 				return -EINVAL;
281151183d23SDavid Ahern 			}
281251183d23SDavid Ahern 		}
281351183d23SDavid Ahern 	}
281451183d23SDavid Ahern 
281551183d23SDavid Ahern 	return 0;
281651183d23SDavid Ahern }
281751183d23SDavid Ahern 
2818c8822a4eSThomas Graf static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
28191da177e4SLinus Torvalds {
28206f52f80eSDavid Ahern 	const struct nlmsghdr *nlh = cb->nlh;
28216f52f80eSDavid Ahern 	struct neigh_dump_filter filter = {};
28221da177e4SLinus Torvalds 	struct neigh_table *tbl;
28231da177e4SLinus Torvalds 	int t, family, s_t;
282484920c14STony Zelenoff 	int proxy = 0;
28254bd6683bSEric Dumazet 	int err;
28261da177e4SLinus Torvalds 
28276f52f80eSDavid Ahern 	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
282884920c14STony Zelenoff 
282984920c14STony Zelenoff 	/* check for full ndmsg structure presence, family member is
283084920c14STony Zelenoff 	 * the same for both structures
283184920c14STony Zelenoff 	 */
28326f52f80eSDavid Ahern 	if (nlmsg_len(nlh) >= sizeof(struct ndmsg) &&
28336f52f80eSDavid Ahern 	    ((struct ndmsg *)nlmsg_data(nlh))->ndm_flags == NTF_PROXY)
283484920c14STony Zelenoff 		proxy = 1;
283584920c14STony Zelenoff 
283651183d23SDavid Ahern 	err = neigh_valid_dump_req(nlh, cb->strict_check, &filter, cb->extack);
283751183d23SDavid Ahern 	if (err < 0 && cb->strict_check)
283851183d23SDavid Ahern 		return err;
283951183d23SDavid Ahern 
28401da177e4SLinus Torvalds 	s_t = cb->args[0];
28411da177e4SLinus Torvalds 
2842d7480fd3SWANG Cong 	for (t = 0; t < NEIGH_NR_TABLES; t++) {
2843d7480fd3SWANG Cong 		tbl = neigh_tables[t];
2844d7480fd3SWANG Cong 
2845d7480fd3SWANG Cong 		if (!tbl)
2846d7480fd3SWANG Cong 			continue;
28471da177e4SLinus Torvalds 		if (t < s_t || (family && tbl->family != family))
28481da177e4SLinus Torvalds 			continue;
28491da177e4SLinus Torvalds 		if (t > s_t)
28501da177e4SLinus Torvalds 			memset(&cb->args[1], 0, sizeof(cb->args) -
28511da177e4SLinus Torvalds 						sizeof(cb->args[0]));
285284920c14STony Zelenoff 		if (proxy)
28536f52f80eSDavid Ahern 			err = pneigh_dump_table(tbl, skb, cb, &filter);
285484920c14STony Zelenoff 		else
28556f52f80eSDavid Ahern 			err = neigh_dump_table(tbl, skb, cb, &filter);
28564bd6683bSEric Dumazet 		if (err < 0)
28574bd6683bSEric Dumazet 			break;
28581da177e4SLinus Torvalds 	}
28591da177e4SLinus Torvalds 
28601da177e4SLinus Torvalds 	cb->args[0] = t;
28611da177e4SLinus Torvalds 	return skb->len;
28621da177e4SLinus Torvalds }
28631da177e4SLinus Torvalds 
286482cbb5c6SRoopa Prabhu static int neigh_valid_get_req(const struct nlmsghdr *nlh,
286582cbb5c6SRoopa Prabhu 			       struct neigh_table **tbl,
286682cbb5c6SRoopa Prabhu 			       void **dst, int *dev_idx, u8 *ndm_flags,
286782cbb5c6SRoopa Prabhu 			       struct netlink_ext_ack *extack)
286882cbb5c6SRoopa Prabhu {
286982cbb5c6SRoopa Prabhu 	struct nlattr *tb[NDA_MAX + 1];
287082cbb5c6SRoopa Prabhu 	struct ndmsg *ndm;
287182cbb5c6SRoopa Prabhu 	int err, i;
287282cbb5c6SRoopa Prabhu 
287382cbb5c6SRoopa Prabhu 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
287482cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid header for neighbor get request");
287582cbb5c6SRoopa Prabhu 		return -EINVAL;
287682cbb5c6SRoopa Prabhu 	}
287782cbb5c6SRoopa Prabhu 
287882cbb5c6SRoopa Prabhu 	ndm = nlmsg_data(nlh);
287982cbb5c6SRoopa Prabhu 	if (ndm->ndm_pad1  || ndm->ndm_pad2  || ndm->ndm_state ||
288082cbb5c6SRoopa Prabhu 	    ndm->ndm_type) {
288182cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor get request");
288282cbb5c6SRoopa Prabhu 		return -EINVAL;
288382cbb5c6SRoopa Prabhu 	}
288482cbb5c6SRoopa Prabhu 
288582cbb5c6SRoopa Prabhu 	if (ndm->ndm_flags & ~NTF_PROXY) {
288682cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor get request");
288782cbb5c6SRoopa Prabhu 		return -EINVAL;
288882cbb5c6SRoopa Prabhu 	}
288982cbb5c6SRoopa Prabhu 
28908cb08174SJohannes Berg 	err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb,
28918cb08174SJohannes Berg 					    NDA_MAX, nda_policy, extack);
289282cbb5c6SRoopa Prabhu 	if (err < 0)
289382cbb5c6SRoopa Prabhu 		return err;
289482cbb5c6SRoopa Prabhu 
289582cbb5c6SRoopa Prabhu 	*ndm_flags = ndm->ndm_flags;
289682cbb5c6SRoopa Prabhu 	*dev_idx = ndm->ndm_ifindex;
289782cbb5c6SRoopa Prabhu 	*tbl = neigh_find_table(ndm->ndm_family);
289882cbb5c6SRoopa Prabhu 	if (*tbl == NULL) {
289982cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
290082cbb5c6SRoopa Prabhu 		return -EAFNOSUPPORT;
290182cbb5c6SRoopa Prabhu 	}
290282cbb5c6SRoopa Prabhu 
290382cbb5c6SRoopa Prabhu 	for (i = 0; i <= NDA_MAX; ++i) {
290482cbb5c6SRoopa Prabhu 		if (!tb[i])
290582cbb5c6SRoopa Prabhu 			continue;
290682cbb5c6SRoopa Prabhu 
290782cbb5c6SRoopa Prabhu 		switch (i) {
290882cbb5c6SRoopa Prabhu 		case NDA_DST:
290982cbb5c6SRoopa Prabhu 			if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
291082cbb5c6SRoopa Prabhu 				NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
291182cbb5c6SRoopa Prabhu 				return -EINVAL;
291282cbb5c6SRoopa Prabhu 			}
291382cbb5c6SRoopa Prabhu 			*dst = nla_data(tb[i]);
291482cbb5c6SRoopa Prabhu 			break;
291582cbb5c6SRoopa Prabhu 		default:
291682cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request");
291782cbb5c6SRoopa Prabhu 			return -EINVAL;
291882cbb5c6SRoopa Prabhu 		}
291982cbb5c6SRoopa Prabhu 	}
292082cbb5c6SRoopa Prabhu 
292182cbb5c6SRoopa Prabhu 	return 0;
292282cbb5c6SRoopa Prabhu }
292382cbb5c6SRoopa Prabhu 
292482cbb5c6SRoopa Prabhu static inline size_t neigh_nlmsg_size(void)
292582cbb5c6SRoopa Prabhu {
292682cbb5c6SRoopa Prabhu 	return NLMSG_ALIGN(sizeof(struct ndmsg))
292782cbb5c6SRoopa Prabhu 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
292882cbb5c6SRoopa Prabhu 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
292982cbb5c6SRoopa Prabhu 	       + nla_total_size(sizeof(struct nda_cacheinfo))
293082cbb5c6SRoopa Prabhu 	       + nla_total_size(4)  /* NDA_PROBES */
29312c611ad9SRoopa Prabhu 	       + nla_total_size(4)  /* NDA_FLAGS_EXT */
293282cbb5c6SRoopa Prabhu 	       + nla_total_size(1); /* NDA_PROTOCOL */
293382cbb5c6SRoopa Prabhu }
293482cbb5c6SRoopa Prabhu 
293582cbb5c6SRoopa Prabhu static int neigh_get_reply(struct net *net, struct neighbour *neigh,
293682cbb5c6SRoopa Prabhu 			   u32 pid, u32 seq)
293782cbb5c6SRoopa Prabhu {
293882cbb5c6SRoopa Prabhu 	struct sk_buff *skb;
293982cbb5c6SRoopa Prabhu 	int err = 0;
294082cbb5c6SRoopa Prabhu 
294182cbb5c6SRoopa Prabhu 	skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL);
294282cbb5c6SRoopa Prabhu 	if (!skb)
294382cbb5c6SRoopa Prabhu 		return -ENOBUFS;
294482cbb5c6SRoopa Prabhu 
294582cbb5c6SRoopa Prabhu 	err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0);
294682cbb5c6SRoopa Prabhu 	if (err) {
294782cbb5c6SRoopa Prabhu 		kfree_skb(skb);
294882cbb5c6SRoopa Prabhu 		goto errout;
294982cbb5c6SRoopa Prabhu 	}
295082cbb5c6SRoopa Prabhu 
295182cbb5c6SRoopa Prabhu 	err = rtnl_unicast(skb, net, pid);
295282cbb5c6SRoopa Prabhu errout:
295382cbb5c6SRoopa Prabhu 	return err;
295482cbb5c6SRoopa Prabhu }
295582cbb5c6SRoopa Prabhu 
295682cbb5c6SRoopa Prabhu static inline size_t pneigh_nlmsg_size(void)
295782cbb5c6SRoopa Prabhu {
295882cbb5c6SRoopa Prabhu 	return NLMSG_ALIGN(sizeof(struct ndmsg))
2959463561e6SColin Ian King 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
29602c611ad9SRoopa Prabhu 	       + nla_total_size(4)  /* NDA_FLAGS_EXT */
296182cbb5c6SRoopa Prabhu 	       + nla_total_size(1); /* NDA_PROTOCOL */
296282cbb5c6SRoopa Prabhu }
296382cbb5c6SRoopa Prabhu 
296482cbb5c6SRoopa Prabhu static int pneigh_get_reply(struct net *net, struct pneigh_entry *neigh,
296582cbb5c6SRoopa Prabhu 			    u32 pid, u32 seq, struct neigh_table *tbl)
296682cbb5c6SRoopa Prabhu {
296782cbb5c6SRoopa Prabhu 	struct sk_buff *skb;
296882cbb5c6SRoopa Prabhu 	int err = 0;
296982cbb5c6SRoopa Prabhu 
297082cbb5c6SRoopa Prabhu 	skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL);
297182cbb5c6SRoopa Prabhu 	if (!skb)
297282cbb5c6SRoopa Prabhu 		return -ENOBUFS;
297382cbb5c6SRoopa Prabhu 
297482cbb5c6SRoopa Prabhu 	err = pneigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0, tbl);
297582cbb5c6SRoopa Prabhu 	if (err) {
297682cbb5c6SRoopa Prabhu 		kfree_skb(skb);
297782cbb5c6SRoopa Prabhu 		goto errout;
297882cbb5c6SRoopa Prabhu 	}
297982cbb5c6SRoopa Prabhu 
298082cbb5c6SRoopa Prabhu 	err = rtnl_unicast(skb, net, pid);
298182cbb5c6SRoopa Prabhu errout:
298282cbb5c6SRoopa Prabhu 	return err;
298382cbb5c6SRoopa Prabhu }
298482cbb5c6SRoopa Prabhu 
298582cbb5c6SRoopa Prabhu static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
298682cbb5c6SRoopa Prabhu 		     struct netlink_ext_ack *extack)
298782cbb5c6SRoopa Prabhu {
298882cbb5c6SRoopa Prabhu 	struct net *net = sock_net(in_skb->sk);
298982cbb5c6SRoopa Prabhu 	struct net_device *dev = NULL;
299082cbb5c6SRoopa Prabhu 	struct neigh_table *tbl = NULL;
299182cbb5c6SRoopa Prabhu 	struct neighbour *neigh;
299282cbb5c6SRoopa Prabhu 	void *dst = NULL;
299382cbb5c6SRoopa Prabhu 	u8 ndm_flags = 0;
299482cbb5c6SRoopa Prabhu 	int dev_idx = 0;
299582cbb5c6SRoopa Prabhu 	int err;
299682cbb5c6SRoopa Prabhu 
299782cbb5c6SRoopa Prabhu 	err = neigh_valid_get_req(nlh, &tbl, &dst, &dev_idx, &ndm_flags,
299882cbb5c6SRoopa Prabhu 				  extack);
299982cbb5c6SRoopa Prabhu 	if (err < 0)
300082cbb5c6SRoopa Prabhu 		return err;
300182cbb5c6SRoopa Prabhu 
300282cbb5c6SRoopa Prabhu 	if (dev_idx) {
300382cbb5c6SRoopa Prabhu 		dev = __dev_get_by_index(net, dev_idx);
300482cbb5c6SRoopa Prabhu 		if (!dev) {
300582cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Unknown device ifindex");
300682cbb5c6SRoopa Prabhu 			return -ENODEV;
300782cbb5c6SRoopa Prabhu 		}
300882cbb5c6SRoopa Prabhu 	}
300982cbb5c6SRoopa Prabhu 
301082cbb5c6SRoopa Prabhu 	if (!dst) {
301182cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Network address not specified");
301282cbb5c6SRoopa Prabhu 		return -EINVAL;
301382cbb5c6SRoopa Prabhu 	}
301482cbb5c6SRoopa Prabhu 
301582cbb5c6SRoopa Prabhu 	if (ndm_flags & NTF_PROXY) {
301682cbb5c6SRoopa Prabhu 		struct pneigh_entry *pn;
301782cbb5c6SRoopa Prabhu 
301882cbb5c6SRoopa Prabhu 		pn = pneigh_lookup(tbl, net, dst, dev, 0);
301982cbb5c6SRoopa Prabhu 		if (!pn) {
302082cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Proxy neighbour entry not found");
302182cbb5c6SRoopa Prabhu 			return -ENOENT;
302282cbb5c6SRoopa Prabhu 		}
302382cbb5c6SRoopa Prabhu 		return pneigh_get_reply(net, pn, NETLINK_CB(in_skb).portid,
302482cbb5c6SRoopa Prabhu 					nlh->nlmsg_seq, tbl);
302582cbb5c6SRoopa Prabhu 	}
302682cbb5c6SRoopa Prabhu 
302782cbb5c6SRoopa Prabhu 	if (!dev) {
302882cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "No device specified");
302982cbb5c6SRoopa Prabhu 		return -EINVAL;
303082cbb5c6SRoopa Prabhu 	}
303182cbb5c6SRoopa Prabhu 
303282cbb5c6SRoopa Prabhu 	neigh = neigh_lookup(tbl, dst, dev);
303382cbb5c6SRoopa Prabhu 	if (!neigh) {
303482cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Neighbour entry not found");
303582cbb5c6SRoopa Prabhu 		return -ENOENT;
303682cbb5c6SRoopa Prabhu 	}
303782cbb5c6SRoopa Prabhu 
303882cbb5c6SRoopa Prabhu 	err = neigh_get_reply(net, neigh, NETLINK_CB(in_skb).portid,
303982cbb5c6SRoopa Prabhu 			      nlh->nlmsg_seq);
304082cbb5c6SRoopa Prabhu 
304182cbb5c6SRoopa Prabhu 	neigh_release(neigh);
304282cbb5c6SRoopa Prabhu 
304382cbb5c6SRoopa Prabhu 	return err;
304482cbb5c6SRoopa Prabhu }
304582cbb5c6SRoopa Prabhu 
30461da177e4SLinus Torvalds void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
30471da177e4SLinus Torvalds {
30481da177e4SLinus Torvalds 	int chain;
3049d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
30501da177e4SLinus Torvalds 
3051d6bf7817SEric Dumazet 	rcu_read_lock_bh();
3052d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
3053d6bf7817SEric Dumazet 
3054767e97e1SEric Dumazet 	read_lock(&tbl->lock); /* avoid resizes */
3055cd089336SDavid S. Miller 	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
30561da177e4SLinus Torvalds 		struct neighbour *n;
30571da177e4SLinus Torvalds 
3058767e97e1SEric Dumazet 		for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
3059767e97e1SEric Dumazet 		     n != NULL;
3060767e97e1SEric Dumazet 		     n = rcu_dereference_bh(n->next))
30611da177e4SLinus Torvalds 			cb(n, cookie);
30621da177e4SLinus Torvalds 	}
3063d6bf7817SEric Dumazet 	read_unlock(&tbl->lock);
3064d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
30651da177e4SLinus Torvalds }
30661da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_for_each);
30671da177e4SLinus Torvalds 
30681da177e4SLinus Torvalds /* The tbl->lock must be held as a writer and BH disabled. */
30691da177e4SLinus Torvalds void __neigh_for_each_release(struct neigh_table *tbl,
30701da177e4SLinus Torvalds 			      int (*cb)(struct neighbour *))
30711da177e4SLinus Torvalds {
30721da177e4SLinus Torvalds 	int chain;
3073d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
30741da177e4SLinus Torvalds 
3075d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
3076d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
3077cd089336SDavid S. Miller 	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
3078767e97e1SEric Dumazet 		struct neighbour *n;
3079767e97e1SEric Dumazet 		struct neighbour __rcu **np;
30801da177e4SLinus Torvalds 
3081d6bf7817SEric Dumazet 		np = &nht->hash_buckets[chain];
3082767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
3083767e97e1SEric Dumazet 					lockdep_is_held(&tbl->lock))) != NULL) {
30841da177e4SLinus Torvalds 			int release;
30851da177e4SLinus Torvalds 
30861da177e4SLinus Torvalds 			write_lock(&n->lock);
30871da177e4SLinus Torvalds 			release = cb(n);
30881da177e4SLinus Torvalds 			if (release) {
3089767e97e1SEric Dumazet 				rcu_assign_pointer(*np,
3090767e97e1SEric Dumazet 					rcu_dereference_protected(n->next,
3091767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
309258956317SDavid Ahern 				neigh_mark_dead(n);
30931da177e4SLinus Torvalds 			} else
30941da177e4SLinus Torvalds 				np = &n->next;
30951da177e4SLinus Torvalds 			write_unlock(&n->lock);
30964f494554SThomas Graf 			if (release)
30974f494554SThomas Graf 				neigh_cleanup_and_release(n);
30981da177e4SLinus Torvalds 		}
30991da177e4SLinus Torvalds 	}
3100ecbb4169SAlexey Kuznetsov }
31011da177e4SLinus Torvalds EXPORT_SYMBOL(__neigh_for_each_release);
31021da177e4SLinus Torvalds 
3103b79bda3dSEric W. Biederman int neigh_xmit(int index, struct net_device *dev,
31044fd3d7d9SEric W. Biederman 	       const void *addr, struct sk_buff *skb)
31054fd3d7d9SEric W. Biederman {
3106b79bda3dSEric W. Biederman 	int err = -EAFNOSUPPORT;
3107b79bda3dSEric W. Biederman 	if (likely(index < NEIGH_NR_TABLES)) {
31084fd3d7d9SEric W. Biederman 		struct neigh_table *tbl;
31094fd3d7d9SEric W. Biederman 		struct neighbour *neigh;
31104fd3d7d9SEric W. Biederman 
3111b79bda3dSEric W. Biederman 		tbl = neigh_tables[index];
31124fd3d7d9SEric W. Biederman 		if (!tbl)
31134fd3d7d9SEric W. Biederman 			goto out;
3114b560f03dSDavid Barroso 		rcu_read_lock_bh();
31154b2a2bfeSDavid Ahern 		if (index == NEIGH_ARP_TABLE) {
31164b2a2bfeSDavid Ahern 			u32 key = *((u32 *)addr);
31174b2a2bfeSDavid Ahern 
31184b2a2bfeSDavid Ahern 			neigh = __ipv4_neigh_lookup_noref(dev, key);
31194b2a2bfeSDavid Ahern 		} else {
31204fd3d7d9SEric W. Biederman 			neigh = __neigh_lookup_noref(tbl, addr, dev);
31214b2a2bfeSDavid Ahern 		}
31224fd3d7d9SEric W. Biederman 		if (!neigh)
31234fd3d7d9SEric W. Biederman 			neigh = __neigh_create(tbl, addr, dev, false);
31244fd3d7d9SEric W. Biederman 		err = PTR_ERR(neigh);
3125b560f03dSDavid Barroso 		if (IS_ERR(neigh)) {
3126b560f03dSDavid Barroso 			rcu_read_unlock_bh();
31274fd3d7d9SEric W. Biederman 			goto out_kfree_skb;
3128b560f03dSDavid Barroso 		}
31294fd3d7d9SEric W. Biederman 		err = neigh->output(neigh, skb);
3130b560f03dSDavid Barroso 		rcu_read_unlock_bh();
31314fd3d7d9SEric W. Biederman 	}
3132b79bda3dSEric W. Biederman 	else if (index == NEIGH_LINK_TABLE) {
3133b79bda3dSEric W. Biederman 		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
3134b79bda3dSEric W. Biederman 				      addr, NULL, skb->len);
3135b79bda3dSEric W. Biederman 		if (err < 0)
3136b79bda3dSEric W. Biederman 			goto out_kfree_skb;
3137b79bda3dSEric W. Biederman 		err = dev_queue_xmit(skb);
3138b79bda3dSEric W. Biederman 	}
31394fd3d7d9SEric W. Biederman out:
31404fd3d7d9SEric W. Biederman 	return err;
31414fd3d7d9SEric W. Biederman out_kfree_skb:
31424fd3d7d9SEric W. Biederman 	kfree_skb(skb);
31434fd3d7d9SEric W. Biederman 	goto out;
31444fd3d7d9SEric W. Biederman }
31454fd3d7d9SEric W. Biederman EXPORT_SYMBOL(neigh_xmit);
31464fd3d7d9SEric W. Biederman 
31471da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
31481da177e4SLinus Torvalds 
31491da177e4SLinus Torvalds static struct neighbour *neigh_get_first(struct seq_file *seq)
31501da177e4SLinus Torvalds {
31511da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
31521218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
3153d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = state->nht;
31541da177e4SLinus Torvalds 	struct neighbour *n = NULL;
3155f530eed6SColin Ian King 	int bucket;
31561da177e4SLinus Torvalds 
31571da177e4SLinus Torvalds 	state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
3158cd089336SDavid S. Miller 	for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
3159767e97e1SEric Dumazet 		n = rcu_dereference_bh(nht->hash_buckets[bucket]);
31601da177e4SLinus Torvalds 
31611da177e4SLinus Torvalds 		while (n) {
3162878628fbSYOSHIFUJI Hideaki 			if (!net_eq(dev_net(n->dev), net))
3163426b5303SEric W. Biederman 				goto next;
31641da177e4SLinus Torvalds 			if (state->neigh_sub_iter) {
31651da177e4SLinus Torvalds 				loff_t fakep = 0;
31661da177e4SLinus Torvalds 				void *v;
31671da177e4SLinus Torvalds 
31681da177e4SLinus Torvalds 				v = state->neigh_sub_iter(state, n, &fakep);
31691da177e4SLinus Torvalds 				if (!v)
31701da177e4SLinus Torvalds 					goto next;
31711da177e4SLinus Torvalds 			}
31721da177e4SLinus Torvalds 			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
31731da177e4SLinus Torvalds 				break;
31741da177e4SLinus Torvalds 			if (n->nud_state & ~NUD_NOARP)
31751da177e4SLinus Torvalds 				break;
31761da177e4SLinus Torvalds next:
3177767e97e1SEric Dumazet 			n = rcu_dereference_bh(n->next);
31781da177e4SLinus Torvalds 		}
31791da177e4SLinus Torvalds 
31801da177e4SLinus Torvalds 		if (n)
31811da177e4SLinus Torvalds 			break;
31821da177e4SLinus Torvalds 	}
31831da177e4SLinus Torvalds 	state->bucket = bucket;
31841da177e4SLinus Torvalds 
31851da177e4SLinus Torvalds 	return n;
31861da177e4SLinus Torvalds }
31871da177e4SLinus Torvalds 
31881da177e4SLinus Torvalds static struct neighbour *neigh_get_next(struct seq_file *seq,
31891da177e4SLinus Torvalds 					struct neighbour *n,
31901da177e4SLinus Torvalds 					loff_t *pos)
31911da177e4SLinus Torvalds {
31921da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
31931218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
3194d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = state->nht;
31951da177e4SLinus Torvalds 
31961da177e4SLinus Torvalds 	if (state->neigh_sub_iter) {
31971da177e4SLinus Torvalds 		void *v = state->neigh_sub_iter(state, n, pos);
31981da177e4SLinus Torvalds 		if (v)
31991da177e4SLinus Torvalds 			return n;
32001da177e4SLinus Torvalds 	}
3201767e97e1SEric Dumazet 	n = rcu_dereference_bh(n->next);
32021da177e4SLinus Torvalds 
32031da177e4SLinus Torvalds 	while (1) {
32041da177e4SLinus Torvalds 		while (n) {
3205878628fbSYOSHIFUJI Hideaki 			if (!net_eq(dev_net(n->dev), net))
3206426b5303SEric W. Biederman 				goto next;
32071da177e4SLinus Torvalds 			if (state->neigh_sub_iter) {
32081da177e4SLinus Torvalds 				void *v = state->neigh_sub_iter(state, n, pos);
32091da177e4SLinus Torvalds 				if (v)
32101da177e4SLinus Torvalds 					return n;
32111da177e4SLinus Torvalds 				goto next;
32121da177e4SLinus Torvalds 			}
32131da177e4SLinus Torvalds 			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
32141da177e4SLinus Torvalds 				break;
32151da177e4SLinus Torvalds 
32161da177e4SLinus Torvalds 			if (n->nud_state & ~NUD_NOARP)
32171da177e4SLinus Torvalds 				break;
32181da177e4SLinus Torvalds next:
3219767e97e1SEric Dumazet 			n = rcu_dereference_bh(n->next);
32201da177e4SLinus Torvalds 		}
32211da177e4SLinus Torvalds 
32221da177e4SLinus Torvalds 		if (n)
32231da177e4SLinus Torvalds 			break;
32241da177e4SLinus Torvalds 
3225cd089336SDavid S. Miller 		if (++state->bucket >= (1 << nht->hash_shift))
32261da177e4SLinus Torvalds 			break;
32271da177e4SLinus Torvalds 
3228767e97e1SEric Dumazet 		n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
32291da177e4SLinus Torvalds 	}
32301da177e4SLinus Torvalds 
32311da177e4SLinus Torvalds 	if (n && pos)
32321da177e4SLinus Torvalds 		--(*pos);
32331da177e4SLinus Torvalds 	return n;
32341da177e4SLinus Torvalds }
32351da177e4SLinus Torvalds 
32361da177e4SLinus Torvalds static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
32371da177e4SLinus Torvalds {
32381da177e4SLinus Torvalds 	struct neighbour *n = neigh_get_first(seq);
32391da177e4SLinus Torvalds 
32401da177e4SLinus Torvalds 	if (n) {
3241745e2031SChris Larson 		--(*pos);
32421da177e4SLinus Torvalds 		while (*pos) {
32431da177e4SLinus Torvalds 			n = neigh_get_next(seq, n, pos);
32441da177e4SLinus Torvalds 			if (!n)
32451da177e4SLinus Torvalds 				break;
32461da177e4SLinus Torvalds 		}
32471da177e4SLinus Torvalds 	}
32481da177e4SLinus Torvalds 	return *pos ? NULL : n;
32491da177e4SLinus Torvalds }
32501da177e4SLinus Torvalds 
32511da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
32521da177e4SLinus Torvalds {
32531da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
32541218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
32551da177e4SLinus Torvalds 	struct neigh_table *tbl = state->tbl;
32561da177e4SLinus Torvalds 	struct pneigh_entry *pn = NULL;
325748de7c0cSYang Li 	int bucket;
32581da177e4SLinus Torvalds 
32591da177e4SLinus Torvalds 	state->flags |= NEIGH_SEQ_IS_PNEIGH;
32601da177e4SLinus Torvalds 	for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
32611da177e4SLinus Torvalds 		pn = tbl->phash_buckets[bucket];
3262878628fbSYOSHIFUJI Hideaki 		while (pn && !net_eq(pneigh_net(pn), net))
3263426b5303SEric W. Biederman 			pn = pn->next;
32641da177e4SLinus Torvalds 		if (pn)
32651da177e4SLinus Torvalds 			break;
32661da177e4SLinus Torvalds 	}
32671da177e4SLinus Torvalds 	state->bucket = bucket;
32681da177e4SLinus Torvalds 
32691da177e4SLinus Torvalds 	return pn;
32701da177e4SLinus Torvalds }
32711da177e4SLinus Torvalds 
32721da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
32731da177e4SLinus Torvalds 					    struct pneigh_entry *pn,
32741da177e4SLinus Torvalds 					    loff_t *pos)
32751da177e4SLinus Torvalds {
32761da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
32771218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
32781da177e4SLinus Torvalds 	struct neigh_table *tbl = state->tbl;
32791da177e4SLinus Torvalds 
3280df07a94cSJorge Boncompte [DTI2] 	do {
32811da177e4SLinus Torvalds 		pn = pn->next;
3282df07a94cSJorge Boncompte [DTI2] 	} while (pn && !net_eq(pneigh_net(pn), net));
3283df07a94cSJorge Boncompte [DTI2] 
32841da177e4SLinus Torvalds 	while (!pn) {
32851da177e4SLinus Torvalds 		if (++state->bucket > PNEIGH_HASHMASK)
32861da177e4SLinus Torvalds 			break;
32871da177e4SLinus Torvalds 		pn = tbl->phash_buckets[state->bucket];
3288878628fbSYOSHIFUJI Hideaki 		while (pn && !net_eq(pneigh_net(pn), net))
3289426b5303SEric W. Biederman 			pn = pn->next;
32901da177e4SLinus Torvalds 		if (pn)
32911da177e4SLinus Torvalds 			break;
32921da177e4SLinus Torvalds 	}
32931da177e4SLinus Torvalds 
32941da177e4SLinus Torvalds 	if (pn && pos)
32951da177e4SLinus Torvalds 		--(*pos);
32961da177e4SLinus Torvalds 
32971da177e4SLinus Torvalds 	return pn;
32981da177e4SLinus Torvalds }
32991da177e4SLinus Torvalds 
33001da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
33011da177e4SLinus Torvalds {
33021da177e4SLinus Torvalds 	struct pneigh_entry *pn = pneigh_get_first(seq);
33031da177e4SLinus Torvalds 
33041da177e4SLinus Torvalds 	if (pn) {
3305745e2031SChris Larson 		--(*pos);
33061da177e4SLinus Torvalds 		while (*pos) {
33071da177e4SLinus Torvalds 			pn = pneigh_get_next(seq, pn, pos);
33081da177e4SLinus Torvalds 			if (!pn)
33091da177e4SLinus Torvalds 				break;
33101da177e4SLinus Torvalds 		}
33111da177e4SLinus Torvalds 	}
33121da177e4SLinus Torvalds 	return *pos ? NULL : pn;
33131da177e4SLinus Torvalds }
33141da177e4SLinus Torvalds 
33151da177e4SLinus Torvalds static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
33161da177e4SLinus Torvalds {
33171da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
33181da177e4SLinus Torvalds 	void *rc;
3319745e2031SChris Larson 	loff_t idxpos = *pos;
33201da177e4SLinus Torvalds 
3321745e2031SChris Larson 	rc = neigh_get_idx(seq, &idxpos);
33221da177e4SLinus Torvalds 	if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
3323745e2031SChris Larson 		rc = pneigh_get_idx(seq, &idxpos);
33241da177e4SLinus Torvalds 
33251da177e4SLinus Torvalds 	return rc;
33261da177e4SLinus Torvalds }
33271da177e4SLinus Torvalds 
33281da177e4SLinus Torvalds void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags)
3329f3e92cb8SEric Dumazet 	__acquires(tbl->lock)
3330d6bf7817SEric Dumazet 	__acquires(rcu_bh)
33311da177e4SLinus Torvalds {
33321da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
33331da177e4SLinus Torvalds 
33341da177e4SLinus Torvalds 	state->tbl = tbl;
33351da177e4SLinus Torvalds 	state->bucket = 0;
33361da177e4SLinus Torvalds 	state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
33371da177e4SLinus Torvalds 
3338d6bf7817SEric Dumazet 	rcu_read_lock_bh();
3339d6bf7817SEric Dumazet 	state->nht = rcu_dereference_bh(tbl->nht);
3340f3e92cb8SEric Dumazet 	read_lock(&tbl->lock);
3341767e97e1SEric Dumazet 
3342745e2031SChris Larson 	return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
33431da177e4SLinus Torvalds }
33441da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_start);
33451da177e4SLinus Torvalds 
33461da177e4SLinus Torvalds void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
33471da177e4SLinus Torvalds {
33481da177e4SLinus Torvalds 	struct neigh_seq_state *state;
33491da177e4SLinus Torvalds 	void *rc;
33501da177e4SLinus Torvalds 
33511da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN) {
3352bff69732SChris Larson 		rc = neigh_get_first(seq);
33531da177e4SLinus Torvalds 		goto out;
33541da177e4SLinus Torvalds 	}
33551da177e4SLinus Torvalds 
33561da177e4SLinus Torvalds 	state = seq->private;
33571da177e4SLinus Torvalds 	if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
33581da177e4SLinus Torvalds 		rc = neigh_get_next(seq, v, NULL);
33591da177e4SLinus Torvalds 		if (rc)
33601da177e4SLinus Torvalds 			goto out;
33611da177e4SLinus Torvalds 		if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
33621da177e4SLinus Torvalds 			rc = pneigh_get_first(seq);
33631da177e4SLinus Torvalds 	} else {
33641da177e4SLinus Torvalds 		BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
33651da177e4SLinus Torvalds 		rc = pneigh_get_next(seq, v, NULL);
33661da177e4SLinus Torvalds 	}
33671da177e4SLinus Torvalds out:
33681da177e4SLinus Torvalds 	++(*pos);
33691da177e4SLinus Torvalds 	return rc;
33701da177e4SLinus Torvalds }
33711da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_next);
33721da177e4SLinus Torvalds 
33731da177e4SLinus Torvalds void neigh_seq_stop(struct seq_file *seq, void *v)
3374f3e92cb8SEric Dumazet 	__releases(tbl->lock)
3375d6bf7817SEric Dumazet 	__releases(rcu_bh)
33761da177e4SLinus Torvalds {
3377f3e92cb8SEric Dumazet 	struct neigh_seq_state *state = seq->private;
3378f3e92cb8SEric Dumazet 	struct neigh_table *tbl = state->tbl;
3379f3e92cb8SEric Dumazet 
3380f3e92cb8SEric Dumazet 	read_unlock(&tbl->lock);
3381d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
33821da177e4SLinus Torvalds }
33831da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_stop);
33841da177e4SLinus Torvalds 
33851da177e4SLinus Torvalds /* statistics via seq_file */
33861da177e4SLinus Torvalds 
33871da177e4SLinus Torvalds static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
33881da177e4SLinus Torvalds {
3389359745d7SMuchun Song 	struct neigh_table *tbl = pde_data(file_inode(seq->file));
33901da177e4SLinus Torvalds 	int cpu;
33911da177e4SLinus Torvalds 
33921da177e4SLinus Torvalds 	if (*pos == 0)
33931da177e4SLinus Torvalds 		return SEQ_START_TOKEN;
33941da177e4SLinus Torvalds 
33950f23174aSRusty Russell 	for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
33961da177e4SLinus Torvalds 		if (!cpu_possible(cpu))
33971da177e4SLinus Torvalds 			continue;
33981da177e4SLinus Torvalds 		*pos = cpu+1;
33991da177e4SLinus Torvalds 		return per_cpu_ptr(tbl->stats, cpu);
34001da177e4SLinus Torvalds 	}
34011da177e4SLinus Torvalds 	return NULL;
34021da177e4SLinus Torvalds }
34031da177e4SLinus Torvalds 
34041da177e4SLinus Torvalds static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
34051da177e4SLinus Torvalds {
3406359745d7SMuchun Song 	struct neigh_table *tbl = pde_data(file_inode(seq->file));
34071da177e4SLinus Torvalds 	int cpu;
34081da177e4SLinus Torvalds 
34090f23174aSRusty Russell 	for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
34101da177e4SLinus Torvalds 		if (!cpu_possible(cpu))
34111da177e4SLinus Torvalds 			continue;
34121da177e4SLinus Torvalds 		*pos = cpu+1;
34131da177e4SLinus Torvalds 		return per_cpu_ptr(tbl->stats, cpu);
34141da177e4SLinus Torvalds 	}
34151e3f9f07SVasily Averin 	(*pos)++;
34161da177e4SLinus Torvalds 	return NULL;
34171da177e4SLinus Torvalds }
34181da177e4SLinus Torvalds 
34191da177e4SLinus Torvalds static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
34201da177e4SLinus Torvalds {
34211da177e4SLinus Torvalds 
34221da177e4SLinus Torvalds }
34231da177e4SLinus Torvalds 
34241da177e4SLinus Torvalds static int neigh_stat_seq_show(struct seq_file *seq, void *v)
34251da177e4SLinus Torvalds {
3426359745d7SMuchun Song 	struct neigh_table *tbl = pde_data(file_inode(seq->file));
34271da177e4SLinus Torvalds 	struct neigh_statistics *st = v;
34281da177e4SLinus Torvalds 
34291da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN) {
34300547ffe6SYajun 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");
34311da177e4SLinus Torvalds 		return 0;
34321da177e4SLinus Torvalds 	}
34331da177e4SLinus Torvalds 
34341da177e4SLinus Torvalds 	seq_printf(seq, "%08x %08lx %08lx %08lx   %08lx %08lx %08lx   "
34350547ffe6SYajun Deng 			"%08lx         %08lx         %08lx         "
34360547ffe6SYajun Deng 			"%08lx       %08lx            %08lx\n",
34371da177e4SLinus Torvalds 		   atomic_read(&tbl->entries),
34381da177e4SLinus Torvalds 
34391da177e4SLinus Torvalds 		   st->allocs,
34401da177e4SLinus Torvalds 		   st->destroys,
34411da177e4SLinus Torvalds 		   st->hash_grows,
34421da177e4SLinus Torvalds 
34431da177e4SLinus Torvalds 		   st->lookups,
34441da177e4SLinus Torvalds 		   st->hits,
34451da177e4SLinus Torvalds 
34461da177e4SLinus Torvalds 		   st->res_failed,
34471da177e4SLinus Torvalds 
34481da177e4SLinus Torvalds 		   st->rcv_probes_mcast,
34491da177e4SLinus Torvalds 		   st->rcv_probes_ucast,
34501da177e4SLinus Torvalds 
34511da177e4SLinus Torvalds 		   st->periodic_gc_runs,
34529a6d276eSNeil Horman 		   st->forced_gc_runs,
3453fb811395SRick Jones 		   st->unres_discards,
3454fb811395SRick Jones 		   st->table_fulls
34551da177e4SLinus Torvalds 		   );
34561da177e4SLinus Torvalds 
34571da177e4SLinus Torvalds 	return 0;
34581da177e4SLinus Torvalds }
34591da177e4SLinus Torvalds 
3460f690808eSStephen Hemminger static const struct seq_operations neigh_stat_seq_ops = {
34611da177e4SLinus Torvalds 	.start	= neigh_stat_seq_start,
34621da177e4SLinus Torvalds 	.next	= neigh_stat_seq_next,
34631da177e4SLinus Torvalds 	.stop	= neigh_stat_seq_stop,
34641da177e4SLinus Torvalds 	.show	= neigh_stat_seq_show,
34651da177e4SLinus Torvalds };
34661da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */
34671da177e4SLinus Torvalds 
34687b8f7a40SRoopa Prabhu static void __neigh_notify(struct neighbour *n, int type, int flags,
34697b8f7a40SRoopa Prabhu 			   u32 pid)
34701da177e4SLinus Torvalds {
3471c346dca1SYOSHIFUJI Hideaki 	struct net *net = dev_net(n->dev);
34728b8aec50SThomas Graf 	struct sk_buff *skb;
3473b8673311SThomas Graf 	int err = -ENOBUFS;
34741da177e4SLinus Torvalds 
3475339bf98fSThomas Graf 	skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
34768b8aec50SThomas Graf 	if (skb == NULL)
3477b8673311SThomas Graf 		goto errout;
34781da177e4SLinus Torvalds 
34797b8f7a40SRoopa Prabhu 	err = neigh_fill_info(skb, n, pid, 0, type, flags);
348026932566SPatrick McHardy 	if (err < 0) {
348126932566SPatrick McHardy 		/* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
348226932566SPatrick McHardy 		WARN_ON(err == -EMSGSIZE);
348326932566SPatrick McHardy 		kfree_skb(skb);
348426932566SPatrick McHardy 		goto errout;
348526932566SPatrick McHardy 	}
34861ce85fe4SPablo Neira Ayuso 	rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
34871ce85fe4SPablo Neira Ayuso 	return;
3488b8673311SThomas Graf errout:
3489b8673311SThomas Graf 	if (err < 0)
3490426b5303SEric W. Biederman 		rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
3491b8673311SThomas Graf }
3492b8673311SThomas Graf 
3493b8673311SThomas Graf void neigh_app_ns(struct neighbour *n)
3494b8673311SThomas Graf {
34957b8f7a40SRoopa Prabhu 	__neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST, 0);
34968b8aec50SThomas Graf }
34970a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_app_ns);
34981da177e4SLinus Torvalds 
34991da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL
3500b93196dcSCong Wang static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
35011da177e4SLinus Torvalds 
3502fe2c6338SJoe Perches static int proc_unres_qlen(struct ctl_table *ctl, int write,
350332927393SChristoph Hellwig 			   void *buffer, size_t *lenp, loff_t *ppos)
35048b5c171bSEric Dumazet {
35058b5c171bSEric Dumazet 	int size, ret;
3506fe2c6338SJoe Perches 	struct ctl_table tmp = *ctl;
35078b5c171bSEric Dumazet 
3508eec4844fSMatteo Croce 	tmp.extra1 = SYSCTL_ZERO;
3509ce46cc64SShan Wei 	tmp.extra2 = &unres_qlen_max;
35108b5c171bSEric Dumazet 	tmp.data = &size;
3511ce46cc64SShan Wei 
3512ce46cc64SShan Wei 	size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN);
3513ce46cc64SShan Wei 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
3514ce46cc64SShan Wei 
35158b5c171bSEric Dumazet 	if (write && !ret)
35168b5c171bSEric Dumazet 		*(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
35178b5c171bSEric Dumazet 	return ret;
35188b5c171bSEric Dumazet }
35198b5c171bSEric Dumazet 
35201d4c8c29SJiri Pirko static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
35211d4c8c29SJiri Pirko 						   int family)
35221d4c8c29SJiri Pirko {
3523bba24896SJiri Pirko 	switch (family) {
3524bba24896SJiri Pirko 	case AF_INET:
35251d4c8c29SJiri Pirko 		return __in_dev_arp_parms_get_rcu(dev);
3526bba24896SJiri Pirko 	case AF_INET6:
3527bba24896SJiri Pirko 		return __in6_dev_nd_parms_get_rcu(dev);
3528bba24896SJiri Pirko 	}
35291d4c8c29SJiri Pirko 	return NULL;
35301d4c8c29SJiri Pirko }
35311d4c8c29SJiri Pirko 
35321d4c8c29SJiri Pirko static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
35331d4c8c29SJiri Pirko 				  int index)
35341d4c8c29SJiri Pirko {
35351d4c8c29SJiri Pirko 	struct net_device *dev;
35361d4c8c29SJiri Pirko 	int family = neigh_parms_family(p);
35371d4c8c29SJiri Pirko 
35381d4c8c29SJiri Pirko 	rcu_read_lock();
35391d4c8c29SJiri Pirko 	for_each_netdev_rcu(net, dev) {
35401d4c8c29SJiri Pirko 		struct neigh_parms *dst_p =
35411d4c8c29SJiri Pirko 				neigh_get_dev_parms_rcu(dev, family);
35421d4c8c29SJiri Pirko 
35431d4c8c29SJiri Pirko 		if (dst_p && !test_bit(index, dst_p->data_state))
35441d4c8c29SJiri Pirko 			dst_p->data[index] = p->data[index];
35451d4c8c29SJiri Pirko 	}
35461d4c8c29SJiri Pirko 	rcu_read_unlock();
35471d4c8c29SJiri Pirko }
35481d4c8c29SJiri Pirko 
35491d4c8c29SJiri Pirko static void neigh_proc_update(struct ctl_table *ctl, int write)
35501d4c8c29SJiri Pirko {
35511d4c8c29SJiri Pirko 	struct net_device *dev = ctl->extra1;
35521d4c8c29SJiri Pirko 	struct neigh_parms *p = ctl->extra2;
355377d47afbSJiri Pirko 	struct net *net = neigh_parms_net(p);
35541d4c8c29SJiri Pirko 	int index = (int *) ctl->data - p->data;
35551d4c8c29SJiri Pirko 
35561d4c8c29SJiri Pirko 	if (!write)
35571d4c8c29SJiri Pirko 		return;
35581d4c8c29SJiri Pirko 
35591d4c8c29SJiri Pirko 	set_bit(index, p->data_state);
35607627ae60SMarcus Huewe 	if (index == NEIGH_VAR_DELAY_PROBE_TIME)
35612a4501aeSIdo Schimmel 		call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
35621d4c8c29SJiri Pirko 	if (!dev) /* NULL dev means this is default value */
35631d4c8c29SJiri Pirko 		neigh_copy_dflt_parms(net, p, index);
35641d4c8c29SJiri Pirko }
35651d4c8c29SJiri Pirko 
35661f9248e5SJiri Pirko static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
356732927393SChristoph Hellwig 					   void *buffer, size_t *lenp,
356832927393SChristoph Hellwig 					   loff_t *ppos)
35691f9248e5SJiri Pirko {
35701f9248e5SJiri Pirko 	struct ctl_table tmp = *ctl;
35711d4c8c29SJiri Pirko 	int ret;
35721f9248e5SJiri Pirko 
3573eec4844fSMatteo Croce 	tmp.extra1 = SYSCTL_ZERO;
3574eec4844fSMatteo Croce 	tmp.extra2 = SYSCTL_INT_MAX;
35751f9248e5SJiri Pirko 
35761d4c8c29SJiri Pirko 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
35771d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
35781d4c8c29SJiri Pirko 	return ret;
35791f9248e5SJiri Pirko }
35801f9248e5SJiri Pirko 
3581211da42eSYuwei Wang static int neigh_proc_dointvec_ms_jiffies_positive(struct ctl_table *ctl, int write,
3582211da42eSYuwei Wang 						   void *buffer, size_t *lenp, loff_t *ppos)
3583211da42eSYuwei Wang {
3584211da42eSYuwei Wang 	struct ctl_table tmp = *ctl;
3585211da42eSYuwei Wang 	int ret;
3586211da42eSYuwei Wang 
3587211da42eSYuwei Wang 	int min = msecs_to_jiffies(1);
3588211da42eSYuwei Wang 
3589211da42eSYuwei Wang 	tmp.extra1 = &min;
3590211da42eSYuwei Wang 	tmp.extra2 = NULL;
3591211da42eSYuwei Wang 
3592211da42eSYuwei Wang 	ret = proc_dointvec_ms_jiffies_minmax(&tmp, write, buffer, lenp, ppos);
3593211da42eSYuwei Wang 	neigh_proc_update(ctl, write);
3594211da42eSYuwei Wang 	return ret;
3595211da42eSYuwei Wang }
3596211da42eSYuwei Wang 
359732927393SChristoph Hellwig int neigh_proc_dointvec(struct ctl_table *ctl, int write, void *buffer,
359832927393SChristoph Hellwig 			size_t *lenp, loff_t *ppos)
3599cb5b09c1SJiri Pirko {
36001d4c8c29SJiri Pirko 	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
36011d4c8c29SJiri Pirko 
36021d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36031d4c8c29SJiri Pirko 	return ret;
3604cb5b09c1SJiri Pirko }
3605cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec);
3606cb5b09c1SJiri Pirko 
360732927393SChristoph Hellwig int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, void *buffer,
3608cb5b09c1SJiri Pirko 				size_t *lenp, loff_t *ppos)
3609cb5b09c1SJiri Pirko {
36101d4c8c29SJiri Pirko 	int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
36111d4c8c29SJiri Pirko 
36121d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36131d4c8c29SJiri Pirko 	return ret;
3614cb5b09c1SJiri Pirko }
3615cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
3616cb5b09c1SJiri Pirko 
3617cb5b09c1SJiri Pirko static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write,
361832927393SChristoph Hellwig 					      void *buffer, size_t *lenp,
361932927393SChristoph Hellwig 					      loff_t *ppos)
3620cb5b09c1SJiri Pirko {
36211d4c8c29SJiri Pirko 	int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
36221d4c8c29SJiri Pirko 
36231d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36241d4c8c29SJiri Pirko 	return ret;
3625cb5b09c1SJiri Pirko }
3626cb5b09c1SJiri Pirko 
3627cb5b09c1SJiri Pirko int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
362832927393SChristoph Hellwig 				   void *buffer, size_t *lenp, loff_t *ppos)
3629cb5b09c1SJiri Pirko {
36301d4c8c29SJiri Pirko 	int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
36311d4c8c29SJiri Pirko 
36321d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36331d4c8c29SJiri Pirko 	return ret;
3634cb5b09c1SJiri Pirko }
3635cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
3636cb5b09c1SJiri Pirko 
3637cb5b09c1SJiri Pirko static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
363832927393SChristoph Hellwig 					  void *buffer, size_t *lenp,
363932927393SChristoph Hellwig 					  loff_t *ppos)
3640cb5b09c1SJiri Pirko {
36411d4c8c29SJiri Pirko 	int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
36421d4c8c29SJiri Pirko 
36431d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36441d4c8c29SJiri Pirko 	return ret;
3645cb5b09c1SJiri Pirko }
3646cb5b09c1SJiri Pirko 
36474bf6980dSJean-Francois Remy static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write,
364832927393SChristoph Hellwig 					  void *buffer, size_t *lenp,
364932927393SChristoph Hellwig 					  loff_t *ppos)
36504bf6980dSJean-Francois Remy {
36514bf6980dSJean-Francois Remy 	struct neigh_parms *p = ctl->extra2;
36524bf6980dSJean-Francois Remy 	int ret;
36534bf6980dSJean-Francois Remy 
36544bf6980dSJean-Francois Remy 	if (strcmp(ctl->procname, "base_reachable_time") == 0)
36554bf6980dSJean-Francois Remy 		ret = neigh_proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
36564bf6980dSJean-Francois Remy 	else if (strcmp(ctl->procname, "base_reachable_time_ms") == 0)
36574bf6980dSJean-Francois Remy 		ret = neigh_proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
36584bf6980dSJean-Francois Remy 	else
36594bf6980dSJean-Francois Remy 		ret = -1;
36604bf6980dSJean-Francois Remy 
36614bf6980dSJean-Francois Remy 	if (write && ret == 0) {
36624bf6980dSJean-Francois Remy 		/* update reachable_time as well, otherwise, the change will
36634bf6980dSJean-Francois Remy 		 * only be effective after the next time neigh_periodic_work
36644bf6980dSJean-Francois Remy 		 * decides to recompute it
36654bf6980dSJean-Francois Remy 		 */
36664bf6980dSJean-Francois Remy 		p->reachable_time =
36674bf6980dSJean-Francois Remy 			neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
36684bf6980dSJean-Francois Remy 	}
36694bf6980dSJean-Francois Remy 	return ret;
36704bf6980dSJean-Francois Remy }
36714bf6980dSJean-Francois Remy 
36721f9248e5SJiri Pirko #define NEIGH_PARMS_DATA_OFFSET(index)	\
36731f9248e5SJiri Pirko 	(&((struct neigh_parms *) 0)->data[index])
36741f9248e5SJiri Pirko 
36751f9248e5SJiri Pirko #define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \
36761f9248e5SJiri Pirko 	[NEIGH_VAR_ ## attr] = { \
36771f9248e5SJiri Pirko 		.procname	= name, \
36781f9248e5SJiri Pirko 		.data		= NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \
36791f9248e5SJiri Pirko 		.maxlen		= sizeof(int), \
36801f9248e5SJiri Pirko 		.mode		= mval, \
36811f9248e5SJiri Pirko 		.proc_handler	= proc, \
36821f9248e5SJiri Pirko 	}
36831f9248e5SJiri Pirko 
36841f9248e5SJiri Pirko #define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \
36851f9248e5SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax)
36861f9248e5SJiri Pirko 
36871f9248e5SJiri Pirko #define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \
3688cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies)
36891f9248e5SJiri Pirko 
36901f9248e5SJiri Pirko #define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
3691cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)
36921f9248e5SJiri Pirko 
3693211da42eSYuwei Wang #define NEIGH_SYSCTL_MS_JIFFIES_POSITIVE_ENTRY(attr, name) \
3694211da42eSYuwei Wang 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_ms_jiffies_positive)
3695211da42eSYuwei Wang 
36961f9248e5SJiri Pirko #define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \
3697cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
36981f9248e5SJiri Pirko 
36991f9248e5SJiri Pirko #define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \
3700cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_unres_qlen)
370154716e3bSEric W. Biederman 
37021da177e4SLinus Torvalds static struct neigh_sysctl_table {
37031da177e4SLinus Torvalds 	struct ctl_table_header *sysctl_header;
37048b5c171bSEric Dumazet 	struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
3705ab32ea5dSBrian Haley } neigh_sysctl_template __read_mostly = {
37061da177e4SLinus Torvalds 	.neigh_vars = {
37071f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"),
37081f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"),
37091f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"),
37108da86466SYOSHIFUJI Hideaki/吉藤英明 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_REPROBES, "mcast_resolicit"),
37111f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),
37121f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),
37131f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"),
3714211da42eSYuwei Wang 		NEIGH_SYSCTL_MS_JIFFIES_POSITIVE_ENTRY(INTERVAL_PROBE_TIME_MS,
3715211da42eSYuwei Wang 						       "interval_probe_time_ms"),
37161f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"),
37171f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"),
37181f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"),
37191f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"),
37201f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"),
37211f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"),
37221f9248e5SJiri Pirko 		NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"),
37231f9248e5SJiri Pirko 		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"),
37241f9248e5SJiri Pirko 		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"),
37258b5c171bSEric Dumazet 		[NEIGH_VAR_GC_INTERVAL] = {
37261da177e4SLinus Torvalds 			.procname	= "gc_interval",
37271da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
37281da177e4SLinus Torvalds 			.mode		= 0644,
37296d9f239aSAlexey Dobriyan 			.proc_handler	= proc_dointvec_jiffies,
37301da177e4SLinus Torvalds 		},
37318b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH1] = {
37321da177e4SLinus Torvalds 			.procname	= "gc_thresh1",
37331da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
37341da177e4SLinus Torvalds 			.mode		= 0644,
3735eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3736eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3737555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
37381da177e4SLinus Torvalds 		},
37398b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH2] = {
37401da177e4SLinus Torvalds 			.procname	= "gc_thresh2",
37411da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
37421da177e4SLinus Torvalds 			.mode		= 0644,
3743eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3744eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3745555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
37461da177e4SLinus Torvalds 		},
37478b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH3] = {
37481da177e4SLinus Torvalds 			.procname	= "gc_thresh3",
37491da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
37501da177e4SLinus Torvalds 			.mode		= 0644,
3751eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3752eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3753555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
37541da177e4SLinus Torvalds 		},
3755c3bac5a7SPavel Emelyanov 		{},
37561da177e4SLinus Torvalds 	},
37571da177e4SLinus Torvalds };
37581da177e4SLinus Torvalds 
37591da177e4SLinus Torvalds int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
376073af614aSJiri Pirko 			  proc_handler *handler)
37611da177e4SLinus Torvalds {
37621f9248e5SJiri Pirko 	int i;
37633c607bbbSPavel Emelyanov 	struct neigh_sysctl_table *t;
37641f9248e5SJiri Pirko 	const char *dev_name_source;
37658f40a1f9SEric W. Biederman 	char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
376673af614aSJiri Pirko 	char *p_name;
37671da177e4SLinus Torvalds 
3768425b9c7fSVasily Averin 	t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL_ACCOUNT);
37691da177e4SLinus Torvalds 	if (!t)
37703c607bbbSPavel Emelyanov 		goto err;
37713c607bbbSPavel Emelyanov 
3772b194c1f1SJiri Pirko 	for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
37731f9248e5SJiri Pirko 		t->neigh_vars[i].data += (long) p;
3774cb5b09c1SJiri Pirko 		t->neigh_vars[i].extra1 = dev;
37751d4c8c29SJiri Pirko 		t->neigh_vars[i].extra2 = p;
3776cb5b09c1SJiri Pirko 	}
37771da177e4SLinus Torvalds 
37781da177e4SLinus Torvalds 	if (dev) {
37791da177e4SLinus Torvalds 		dev_name_source = dev->name;
3780d12af679SEric W. Biederman 		/* Terminate the table early */
37818b5c171bSEric Dumazet 		memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
37828b5c171bSEric Dumazet 		       sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
37831da177e4SLinus Torvalds 	} else {
37849ecf07a1SMathias Krause 		struct neigh_table *tbl = p->tbl;
37858f40a1f9SEric W. Biederman 		dev_name_source = "default";
37869ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = &tbl->gc_interval;
37879ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = &tbl->gc_thresh1;
37889ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = &tbl->gc_thresh2;
37899ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = &tbl->gc_thresh3;
37901da177e4SLinus Torvalds 	}
37911da177e4SLinus Torvalds 
3792f8572d8fSEric W. Biederman 	if (handler) {
37931da177e4SLinus Torvalds 		/* RetransTime */
37948b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
37951da177e4SLinus Torvalds 		/* ReachableTime */
37968b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
37971da177e4SLinus Torvalds 		/* RetransTime (in milliseconds)*/
37988b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
37991da177e4SLinus Torvalds 		/* ReachableTime (in milliseconds) */
38008b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
38014bf6980dSJean-Francois Remy 	} else {
38024bf6980dSJean-Francois Remy 		/* Those handlers will update p->reachable_time after
38034bf6980dSJean-Francois Remy 		 * base_reachable_time(_ms) is set to ensure the new timer starts being
38044bf6980dSJean-Francois Remy 		 * applied after the next neighbour update instead of waiting for
38054bf6980dSJean-Francois Remy 		 * neigh_periodic_work to update its value (can be multiple minutes)
38064bf6980dSJean-Francois Remy 		 * So any handler that replaces them should do this as well
38074bf6980dSJean-Francois Remy 		 */
38084bf6980dSJean-Francois Remy 		/* ReachableTime */
38094bf6980dSJean-Francois Remy 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler =
38104bf6980dSJean-Francois Remy 			neigh_proc_base_reachable_time;
38114bf6980dSJean-Francois Remy 		/* ReachableTime (in milliseconds) */
38124bf6980dSJean-Francois Remy 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler =
38134bf6980dSJean-Francois Remy 			neigh_proc_base_reachable_time;
38141da177e4SLinus Torvalds 	}
38151da177e4SLinus Torvalds 
381673af614aSJiri Pirko 	switch (neigh_parms_family(p)) {
381773af614aSJiri Pirko 	case AF_INET:
381873af614aSJiri Pirko 	      p_name = "ipv4";
381973af614aSJiri Pirko 	      break;
382073af614aSJiri Pirko 	case AF_INET6:
382173af614aSJiri Pirko 	      p_name = "ipv6";
382273af614aSJiri Pirko 	      break;
382373af614aSJiri Pirko 	default:
382473af614aSJiri Pirko 	      BUG();
382573af614aSJiri Pirko 	}
382673af614aSJiri Pirko 
38278f40a1f9SEric W. Biederman 	snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
38288f40a1f9SEric W. Biederman 		p_name, dev_name_source);
38294ab438fcSDenis V. Lunev 	t->sysctl_header =
38308f40a1f9SEric W. Biederman 		register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
38313c607bbbSPavel Emelyanov 	if (!t->sysctl_header)
38328f40a1f9SEric W. Biederman 		goto free;
38333c607bbbSPavel Emelyanov 
38341da177e4SLinus Torvalds 	p->sysctl_table = t;
38351da177e4SLinus Torvalds 	return 0;
38361da177e4SLinus Torvalds 
38371da177e4SLinus Torvalds free:
38381da177e4SLinus Torvalds 	kfree(t);
38393c607bbbSPavel Emelyanov err:
38403c607bbbSPavel Emelyanov 	return -ENOBUFS;
38411da177e4SLinus Torvalds }
38420a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_sysctl_register);
38431da177e4SLinus Torvalds 
38441da177e4SLinus Torvalds void neigh_sysctl_unregister(struct neigh_parms *p)
38451da177e4SLinus Torvalds {
38461da177e4SLinus Torvalds 	if (p->sysctl_table) {
38471da177e4SLinus Torvalds 		struct neigh_sysctl_table *t = p->sysctl_table;
38481da177e4SLinus Torvalds 		p->sysctl_table = NULL;
38495dd3df10SEric W. Biederman 		unregister_net_sysctl_table(t->sysctl_header);
38501da177e4SLinus Torvalds 		kfree(t);
38511da177e4SLinus Torvalds 	}
38521da177e4SLinus Torvalds }
38530a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_sysctl_unregister);
38541da177e4SLinus Torvalds 
38551da177e4SLinus Torvalds #endif	/* CONFIG_SYSCTL */
38561da177e4SLinus Torvalds 
3857c8822a4eSThomas Graf static int __init neigh_init(void)
3858c8822a4eSThomas Graf {
3859b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0);
3860b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0);
386182cbb5c6SRoopa Prabhu 	rtnl_register(PF_UNSPEC, RTM_GETNEIGH, neigh_get, neigh_dump_info, 0);
3862c8822a4eSThomas Graf 
3863c7ac8679SGreg Rose 	rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
3864b97bac64SFlorian Westphal 		      0);
3865b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, 0);
3866c8822a4eSThomas Graf 
3867c8822a4eSThomas Graf 	return 0;
3868c8822a4eSThomas Graf }
3869c8822a4eSThomas Graf 
3870c8822a4eSThomas Graf subsys_initcall(neigh_init);
3871