xref: /openbmc/linux/net/core/neighbour.c (revision d62607c3)
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 
3101da177e4SLinus Torvalds static void pneigh_queue_purge(struct sk_buff_head *list)
3111da177e4SLinus Torvalds {
3121da177e4SLinus Torvalds 	struct sk_buff *skb;
3131da177e4SLinus Torvalds 
3141da177e4SLinus Torvalds 	while ((skb = skb_dequeue(list)) != NULL) {
3151da177e4SLinus Torvalds 		dev_put(skb->dev);
3161da177e4SLinus Torvalds 		kfree_skb(skb);
3171da177e4SLinus Torvalds 	}
3181da177e4SLinus Torvalds }
3191da177e4SLinus Torvalds 
320859bd2efSDavid Ahern static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev,
321859bd2efSDavid Ahern 			    bool skip_perm)
3221da177e4SLinus Torvalds {
3231da177e4SLinus Torvalds 	int i;
324d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
3251da177e4SLinus Torvalds 
326d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
327d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
328d6bf7817SEric Dumazet 
329cd089336SDavid S. Miller 	for (i = 0; i < (1 << nht->hash_shift); i++) {
330767e97e1SEric Dumazet 		struct neighbour *n;
331767e97e1SEric Dumazet 		struct neighbour __rcu **np = &nht->hash_buckets[i];
3321da177e4SLinus Torvalds 
333767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
334767e97e1SEric Dumazet 					lockdep_is_held(&tbl->lock))) != NULL) {
3351da177e4SLinus Torvalds 			if (dev && n->dev != dev) {
3361da177e4SLinus Torvalds 				np = &n->next;
3371da177e4SLinus Torvalds 				continue;
3381da177e4SLinus Torvalds 			}
339859bd2efSDavid Ahern 			if (skip_perm && n->nud_state & NUD_PERMANENT) {
340859bd2efSDavid Ahern 				np = &n->next;
341859bd2efSDavid Ahern 				continue;
342859bd2efSDavid Ahern 			}
343767e97e1SEric Dumazet 			rcu_assign_pointer(*np,
344767e97e1SEric Dumazet 				   rcu_dereference_protected(n->next,
345767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
3461da177e4SLinus Torvalds 			write_lock(&n->lock);
3471da177e4SLinus Torvalds 			neigh_del_timer(n);
34858956317SDavid Ahern 			neigh_mark_dead(n);
3499f237430SReshetova, Elena 			if (refcount_read(&n->refcnt) != 1) {
3501da177e4SLinus Torvalds 				/* The most unpleasant situation.
3511da177e4SLinus Torvalds 				   We must destroy neighbour entry,
3521da177e4SLinus Torvalds 				   but someone still uses it.
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds 				   The destroy will be delayed until
3551da177e4SLinus Torvalds 				   the last user releases us, but
3561da177e4SLinus Torvalds 				   we must kill timers etc. and move
3571da177e4SLinus Torvalds 				   it to safe state.
3581da177e4SLinus Torvalds 				 */
359c9ab4d85SEric Dumazet 				__skb_queue_purge(&n->arp_queue);
3608b5c171bSEric Dumazet 				n->arp_queue_len_bytes = 0;
3611da177e4SLinus Torvalds 				n->output = neigh_blackhole;
3621da177e4SLinus Torvalds 				if (n->nud_state & NUD_VALID)
3631da177e4SLinus Torvalds 					n->nud_state = NUD_NOARP;
3641da177e4SLinus Torvalds 				else
3651da177e4SLinus Torvalds 					n->nud_state = NUD_NONE;
366d5d427cdSJoe Perches 				neigh_dbg(2, "neigh %p is stray\n", n);
3671da177e4SLinus Torvalds 			}
3681da177e4SLinus Torvalds 			write_unlock(&n->lock);
3694f494554SThomas Graf 			neigh_cleanup_and_release(n);
3701da177e4SLinus Torvalds 		}
3711da177e4SLinus Torvalds 	}
37249636bb1SHerbert Xu }
3731da177e4SLinus Torvalds 
37449636bb1SHerbert Xu void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
37549636bb1SHerbert Xu {
37649636bb1SHerbert Xu 	write_lock_bh(&tbl->lock);
377859bd2efSDavid Ahern 	neigh_flush_dev(tbl, dev, false);
37849636bb1SHerbert Xu 	write_unlock_bh(&tbl->lock);
37949636bb1SHerbert Xu }
3800a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_changeaddr);
38149636bb1SHerbert Xu 
382859bd2efSDavid Ahern static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
383859bd2efSDavid Ahern 			  bool skip_perm)
38449636bb1SHerbert Xu {
38549636bb1SHerbert Xu 	write_lock_bh(&tbl->lock);
386859bd2efSDavid Ahern 	neigh_flush_dev(tbl, dev, skip_perm);
38753b76cdfSWolfgang Bumiller 	pneigh_ifdown_and_unlock(tbl, dev);
3881da177e4SLinus Torvalds 
3891da177e4SLinus Torvalds 	del_timer_sync(&tbl->proxy_timer);
3901da177e4SLinus Torvalds 	pneigh_queue_purge(&tbl->proxy_queue);
3911da177e4SLinus Torvalds 	return 0;
3921da177e4SLinus Torvalds }
393859bd2efSDavid Ahern 
394859bd2efSDavid Ahern int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev)
395859bd2efSDavid Ahern {
396859bd2efSDavid Ahern 	__neigh_ifdown(tbl, dev, true);
397859bd2efSDavid Ahern 	return 0;
398859bd2efSDavid Ahern }
399859bd2efSDavid Ahern EXPORT_SYMBOL(neigh_carrier_down);
400859bd2efSDavid Ahern 
401859bd2efSDavid Ahern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
402859bd2efSDavid Ahern {
403859bd2efSDavid Ahern 	__neigh_ifdown(tbl, dev, false);
404859bd2efSDavid Ahern 	return 0;
405859bd2efSDavid Ahern }
4060a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_ifdown);
4071da177e4SLinus Torvalds 
40858956317SDavid Ahern static struct neighbour *neigh_alloc(struct neigh_table *tbl,
40958956317SDavid Ahern 				     struct net_device *dev,
4102c611ad9SRoopa Prabhu 				     u32 flags, bool exempt_from_gc)
4111da177e4SLinus Torvalds {
4121da177e4SLinus Torvalds 	struct neighbour *n = NULL;
4131da177e4SLinus Torvalds 	unsigned long now = jiffies;
4141da177e4SLinus Torvalds 	int entries;
4151da177e4SLinus Torvalds 
416e997f8a2SDavid Ahern 	if (exempt_from_gc)
41758956317SDavid Ahern 		goto do_alloc;
41858956317SDavid Ahern 
41958956317SDavid Ahern 	entries = atomic_inc_return(&tbl->gc_entries) - 1;
4201da177e4SLinus Torvalds 	if (entries >= tbl->gc_thresh3 ||
4211da177e4SLinus Torvalds 	    (entries >= tbl->gc_thresh2 &&
4221da177e4SLinus Torvalds 	     time_after(now, tbl->last_flush + 5 * HZ))) {
4231da177e4SLinus Torvalds 		if (!neigh_forced_gc(tbl) &&
424fb811395SRick Jones 		    entries >= tbl->gc_thresh3) {
425fb811395SRick Jones 			net_info_ratelimited("%s: neighbor table overflow!\n",
426fb811395SRick Jones 					     tbl->id);
427fb811395SRick Jones 			NEIGH_CACHE_STAT_INC(tbl, table_fulls);
4281da177e4SLinus Torvalds 			goto out_entries;
4291da177e4SLinus Torvalds 		}
430fb811395SRick Jones 	}
4311da177e4SLinus Torvalds 
43258956317SDavid Ahern do_alloc:
43308433effSYOSHIFUJI Hideaki / 吉藤英明 	n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
4341da177e4SLinus Torvalds 	if (!n)
4351da177e4SLinus Torvalds 		goto out_entries;
4361da177e4SLinus Torvalds 
437c9ab4d85SEric Dumazet 	__skb_queue_head_init(&n->arp_queue);
4381da177e4SLinus Torvalds 	rwlock_init(&n->lock);
4390ed8ddf4SEric Dumazet 	seqlock_init(&n->ha_lock);
4401da177e4SLinus Torvalds 	n->updated	  = n->used = now;
4411da177e4SLinus Torvalds 	n->nud_state	  = NUD_NONE;
4421da177e4SLinus Torvalds 	n->output	  = neigh_blackhole;
443e4400bbfSDaniel Borkmann 	n->flags	  = flags;
444f6b72b62SDavid S. Miller 	seqlock_init(&n->hh.hh_lock);
4451da177e4SLinus Torvalds 	n->parms	  = neigh_parms_clone(&tbl->parms);
446e99e88a9SKees Cook 	timer_setup(&n->timer, neigh_timer_handler, 0);
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, allocs);
4491da177e4SLinus Torvalds 	n->tbl		  = tbl;
4509f237430SReshetova, Elena 	refcount_set(&n->refcnt, 1);
4511da177e4SLinus Torvalds 	n->dead		  = 1;
45258956317SDavid Ahern 	INIT_LIST_HEAD(&n->gc_list);
4537482e384SDaniel Borkmann 	INIT_LIST_HEAD(&n->managed_list);
45458956317SDavid Ahern 
45558956317SDavid Ahern 	atomic_inc(&tbl->entries);
4561da177e4SLinus Torvalds out:
4571da177e4SLinus Torvalds 	return n;
4581da177e4SLinus Torvalds 
4591da177e4SLinus Torvalds out_entries:
460e997f8a2SDavid Ahern 	if (!exempt_from_gc)
46158956317SDavid Ahern 		atomic_dec(&tbl->gc_entries);
4621da177e4SLinus Torvalds 	goto out;
4631da177e4SLinus Torvalds }
4641da177e4SLinus Torvalds 
4652c2aba6cSDavid S. Miller static void neigh_get_hash_rnd(u32 *x)
4662c2aba6cSDavid S. Miller {
467b3d0f789SJason A. Donenfeld 	*x = get_random_u32() | 1;
4682c2aba6cSDavid S. Miller }
4692c2aba6cSDavid S. Miller 
470cd089336SDavid S. Miller static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
4711da177e4SLinus Torvalds {
472cd089336SDavid S. Miller 	size_t size = (1 << shift) * sizeof(struct neighbour *);
473d6bf7817SEric Dumazet 	struct neigh_hash_table *ret;
4746193d2beSEric Dumazet 	struct neighbour __rcu **buckets;
4752c2aba6cSDavid S. Miller 	int i;
4761da177e4SLinus Torvalds 
477d6bf7817SEric Dumazet 	ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
478d6bf7817SEric Dumazet 	if (!ret)
479d6bf7817SEric Dumazet 		return NULL;
48085704cb8SKonstantin Khlebnikov 	if (size <= PAGE_SIZE) {
481d6bf7817SEric Dumazet 		buckets = kzalloc(size, GFP_ATOMIC);
48285704cb8SKonstantin Khlebnikov 	} else {
4836193d2beSEric Dumazet 		buckets = (struct neighbour __rcu **)
484d6bf7817SEric Dumazet 			  __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
485d6bf7817SEric Dumazet 					   get_order(size));
48601b833abSKonstantin Khlebnikov 		kmemleak_alloc(buckets, size, 1, GFP_ATOMIC);
48785704cb8SKonstantin Khlebnikov 	}
488d6bf7817SEric Dumazet 	if (!buckets) {
489d6bf7817SEric Dumazet 		kfree(ret);
490d6bf7817SEric Dumazet 		return NULL;
4911da177e4SLinus Torvalds 	}
4926193d2beSEric Dumazet 	ret->hash_buckets = buckets;
493cd089336SDavid S. Miller 	ret->hash_shift = shift;
4942c2aba6cSDavid S. Miller 	for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
4952c2aba6cSDavid S. Miller 		neigh_get_hash_rnd(&ret->hash_rnd[i]);
4961da177e4SLinus Torvalds 	return ret;
4971da177e4SLinus Torvalds }
4981da177e4SLinus Torvalds 
499d6bf7817SEric Dumazet static void neigh_hash_free_rcu(struct rcu_head *head)
5001da177e4SLinus Torvalds {
501d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = container_of(head,
502d6bf7817SEric Dumazet 						    struct neigh_hash_table,
503d6bf7817SEric Dumazet 						    rcu);
504cd089336SDavid S. Miller 	size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
5056193d2beSEric Dumazet 	struct neighbour __rcu **buckets = nht->hash_buckets;
5061da177e4SLinus Torvalds 
50785704cb8SKonstantin Khlebnikov 	if (size <= PAGE_SIZE) {
508d6bf7817SEric Dumazet 		kfree(buckets);
50985704cb8SKonstantin Khlebnikov 	} else {
51085704cb8SKonstantin Khlebnikov 		kmemleak_free(buckets);
511d6bf7817SEric Dumazet 		free_pages((unsigned long)buckets, get_order(size));
51285704cb8SKonstantin Khlebnikov 	}
513d6bf7817SEric Dumazet 	kfree(nht);
5141da177e4SLinus Torvalds }
5151da177e4SLinus Torvalds 
516d6bf7817SEric Dumazet static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
517cd089336SDavid S. Miller 						unsigned long new_shift)
5181da177e4SLinus Torvalds {
519d6bf7817SEric Dumazet 	unsigned int i, hash;
520d6bf7817SEric Dumazet 	struct neigh_hash_table *new_nht, *old_nht;
5211da177e4SLinus Torvalds 
5221da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, hash_grows);
5231da177e4SLinus Torvalds 
524d6bf7817SEric Dumazet 	old_nht = rcu_dereference_protected(tbl->nht,
525d6bf7817SEric Dumazet 					    lockdep_is_held(&tbl->lock));
526cd089336SDavid S. Miller 	new_nht = neigh_hash_alloc(new_shift);
527d6bf7817SEric Dumazet 	if (!new_nht)
528d6bf7817SEric Dumazet 		return old_nht;
5291da177e4SLinus Torvalds 
530cd089336SDavid S. Miller 	for (i = 0; i < (1 << old_nht->hash_shift); i++) {
5311da177e4SLinus Torvalds 		struct neighbour *n, *next;
5321da177e4SLinus Torvalds 
533767e97e1SEric Dumazet 		for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
534767e97e1SEric Dumazet 						   lockdep_is_held(&tbl->lock));
535d6bf7817SEric Dumazet 		     n != NULL;
536d6bf7817SEric Dumazet 		     n = next) {
537d6bf7817SEric Dumazet 			hash = tbl->hash(n->primary_key, n->dev,
538d6bf7817SEric Dumazet 					 new_nht->hash_rnd);
5391da177e4SLinus Torvalds 
540cd089336SDavid S. Miller 			hash >>= (32 - new_nht->hash_shift);
541767e97e1SEric Dumazet 			next = rcu_dereference_protected(n->next,
542767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock));
5431da177e4SLinus Torvalds 
544767e97e1SEric Dumazet 			rcu_assign_pointer(n->next,
545767e97e1SEric Dumazet 					   rcu_dereference_protected(
546767e97e1SEric Dumazet 						new_nht->hash_buckets[hash],
547767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
548767e97e1SEric Dumazet 			rcu_assign_pointer(new_nht->hash_buckets[hash], n);
5491da177e4SLinus Torvalds 		}
5501da177e4SLinus Torvalds 	}
5511da177e4SLinus Torvalds 
552d6bf7817SEric Dumazet 	rcu_assign_pointer(tbl->nht, new_nht);
553d6bf7817SEric Dumazet 	call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
554d6bf7817SEric Dumazet 	return new_nht;
5551da177e4SLinus Torvalds }
5561da177e4SLinus Torvalds 
5571da177e4SLinus Torvalds struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
5581da177e4SLinus Torvalds 			       struct net_device *dev)
5591da177e4SLinus Torvalds {
5601da177e4SLinus Torvalds 	struct neighbour *n;
5611da177e4SLinus Torvalds 
5621da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, lookups);
5631da177e4SLinus Torvalds 
564d6bf7817SEric Dumazet 	rcu_read_lock_bh();
56560395a20SEric W. Biederman 	n = __neigh_lookup_noref(tbl, pkey, dev);
56660395a20SEric W. Biederman 	if (n) {
5679f237430SReshetova, Elena 		if (!refcount_inc_not_zero(&n->refcnt))
568767e97e1SEric Dumazet 			n = NULL;
5691da177e4SLinus Torvalds 		NEIGH_CACHE_STAT_INC(tbl, hits);
5701da177e4SLinus Torvalds 	}
571767e97e1SEric Dumazet 
572d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
5731da177e4SLinus Torvalds 	return n;
5741da177e4SLinus Torvalds }
5750a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_lookup);
5761da177e4SLinus Torvalds 
577426b5303SEric W. Biederman struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
578426b5303SEric W. Biederman 				     const void *pkey)
5791da177e4SLinus Torvalds {
5801da177e4SLinus Torvalds 	struct neighbour *n;
58101ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
582bc4bf5f3SPavel Emelyanov 	u32 hash_val;
583d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
5841da177e4SLinus Torvalds 
5851da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, lookups);
5861da177e4SLinus Torvalds 
587d6bf7817SEric Dumazet 	rcu_read_lock_bh();
588d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
589cd089336SDavid S. Miller 	hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
590767e97e1SEric Dumazet 
591767e97e1SEric Dumazet 	for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
592767e97e1SEric Dumazet 	     n != NULL;
593767e97e1SEric Dumazet 	     n = rcu_dereference_bh(n->next)) {
594426b5303SEric W. Biederman 		if (!memcmp(n->primary_key, pkey, key_len) &&
595878628fbSYOSHIFUJI Hideaki 		    net_eq(dev_net(n->dev), net)) {
5969f237430SReshetova, Elena 			if (!refcount_inc_not_zero(&n->refcnt))
597767e97e1SEric Dumazet 				n = NULL;
5981da177e4SLinus Torvalds 			NEIGH_CACHE_STAT_INC(tbl, hits);
5991da177e4SLinus Torvalds 			break;
6001da177e4SLinus Torvalds 		}
6011da177e4SLinus Torvalds 	}
602767e97e1SEric Dumazet 
603d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
6041da177e4SLinus Torvalds 	return n;
6051da177e4SLinus Torvalds }
6060a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_lookup_nodev);
6071da177e4SLinus Torvalds 
608e4400bbfSDaniel Borkmann static struct neighbour *
609e4400bbfSDaniel Borkmann ___neigh_create(struct neigh_table *tbl, const void *pkey,
6102c611ad9SRoopa Prabhu 		struct net_device *dev, u32 flags,
611e997f8a2SDavid Ahern 		bool exempt_from_gc, bool want_ref)
6121da177e4SLinus Torvalds {
613e4400bbfSDaniel Borkmann 	u32 hash_val, key_len = tbl->key_len;
614e4400bbfSDaniel Borkmann 	struct neighbour *n1, *rc, *n;
615d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
616e4400bbfSDaniel Borkmann 	int error;
6171da177e4SLinus Torvalds 
618e4400bbfSDaniel Borkmann 	n = neigh_alloc(tbl, dev, flags, exempt_from_gc);
619fc651001SDavid Ahern 	trace_neigh_create(tbl, dev, pkey, n, exempt_from_gc);
6201da177e4SLinus Torvalds 	if (!n) {
6211da177e4SLinus Torvalds 		rc = ERR_PTR(-ENOBUFS);
6221da177e4SLinus Torvalds 		goto out;
6231da177e4SLinus Torvalds 	}
6241da177e4SLinus Torvalds 
6251da177e4SLinus Torvalds 	memcpy(n->primary_key, pkey, key_len);
6261da177e4SLinus Torvalds 	n->dev = dev;
627*d62607c3SJakub Kicinski 	netdev_hold(dev, &n->dev_tracker, GFP_ATOMIC);
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds 	/* Protocol specific setup. */
6301da177e4SLinus Torvalds 	if (tbl->constructor &&	(error = tbl->constructor(n)) < 0) {
6311da177e4SLinus Torvalds 		rc = ERR_PTR(error);
6321da177e4SLinus Torvalds 		goto out_neigh_release;
6331da177e4SLinus Torvalds 	}
6341da177e4SLinus Torvalds 
635da6a8fa0SDavid Miller 	if (dev->netdev_ops->ndo_neigh_construct) {
636503eebc2SJiri Pirko 		error = dev->netdev_ops->ndo_neigh_construct(dev, n);
637da6a8fa0SDavid Miller 		if (error < 0) {
638da6a8fa0SDavid Miller 			rc = ERR_PTR(error);
639da6a8fa0SDavid Miller 			goto out_neigh_release;
640da6a8fa0SDavid Miller 		}
641da6a8fa0SDavid Miller 	}
642da6a8fa0SDavid Miller 
643447f2191SDavid S. Miller 	/* Device specific setup. */
644447f2191SDavid S. Miller 	if (n->parms->neigh_setup &&
645447f2191SDavid S. Miller 	    (error = n->parms->neigh_setup(n)) < 0) {
646447f2191SDavid S. Miller 		rc = ERR_PTR(error);
647447f2191SDavid S. Miller 		goto out_neigh_release;
648447f2191SDavid S. Miller 	}
649447f2191SDavid S. Miller 
6501f9248e5SJiri Pirko 	n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1);
6511da177e4SLinus Torvalds 
6521da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
653d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
654d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
6551da177e4SLinus Torvalds 
656cd089336SDavid S. Miller 	if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
657cd089336SDavid S. Miller 		nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
6581da177e4SLinus Torvalds 
659096b9854SJim Westfall 	hash_val = tbl->hash(n->primary_key, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
6601da177e4SLinus Torvalds 
6611da177e4SLinus Torvalds 	if (n->parms->dead) {
6621da177e4SLinus Torvalds 		rc = ERR_PTR(-EINVAL);
6631da177e4SLinus Torvalds 		goto out_tbl_unlock;
6641da177e4SLinus Torvalds 	}
6651da177e4SLinus Torvalds 
666767e97e1SEric Dumazet 	for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
667767e97e1SEric Dumazet 					    lockdep_is_held(&tbl->lock));
668767e97e1SEric Dumazet 	     n1 != NULL;
669767e97e1SEric Dumazet 	     n1 = rcu_dereference_protected(n1->next,
670767e97e1SEric Dumazet 			lockdep_is_held(&tbl->lock))) {
671096b9854SJim Westfall 		if (dev == n1->dev && !memcmp(n1->primary_key, n->primary_key, key_len)) {
672a263b309SDavid S. Miller 			if (want_ref)
6731da177e4SLinus Torvalds 				neigh_hold(n1);
6741da177e4SLinus Torvalds 			rc = n1;
6751da177e4SLinus Torvalds 			goto out_tbl_unlock;
6761da177e4SLinus Torvalds 		}
6771da177e4SLinus Torvalds 	}
6781da177e4SLinus Torvalds 
6791da177e4SLinus Torvalds 	n->dead = 0;
680e997f8a2SDavid Ahern 	if (!exempt_from_gc)
6818cc196d6SDavid Ahern 		list_add_tail(&n->gc_list, &n->tbl->gc_list);
6827482e384SDaniel Borkmann 	if (n->flags & NTF_MANAGED)
6837482e384SDaniel Borkmann 		list_add_tail(&n->managed_list, &n->tbl->managed_list);
684a263b309SDavid S. Miller 	if (want_ref)
6851da177e4SLinus Torvalds 		neigh_hold(n);
686767e97e1SEric Dumazet 	rcu_assign_pointer(n->next,
687767e97e1SEric Dumazet 			   rcu_dereference_protected(nht->hash_buckets[hash_val],
688767e97e1SEric Dumazet 						     lockdep_is_held(&tbl->lock)));
689767e97e1SEric Dumazet 	rcu_assign_pointer(nht->hash_buckets[hash_val], n);
6901da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
691d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is created\n", n);
6921da177e4SLinus Torvalds 	rc = n;
6931da177e4SLinus Torvalds out:
6941da177e4SLinus Torvalds 	return rc;
6951da177e4SLinus Torvalds out_tbl_unlock:
6961da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
6971da177e4SLinus Torvalds out_neigh_release:
69864c6f4bbSDavid Ahern 	if (!exempt_from_gc)
69964c6f4bbSDavid Ahern 		atomic_dec(&tbl->gc_entries);
7001da177e4SLinus Torvalds 	neigh_release(n);
7011da177e4SLinus Torvalds 	goto out;
7021da177e4SLinus Torvalds }
70358956317SDavid Ahern 
70458956317SDavid Ahern struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
70558956317SDavid Ahern 				 struct net_device *dev, bool want_ref)
70658956317SDavid Ahern {
707e4400bbfSDaniel Borkmann 	return ___neigh_create(tbl, pkey, dev, 0, false, want_ref);
70858956317SDavid Ahern }
709a263b309SDavid S. Miller EXPORT_SYMBOL(__neigh_create);
7101da177e4SLinus Torvalds 
71101ccdf12SAlexey Dobriyan static u32 pneigh_hash(const void *pkey, unsigned int key_len)
712fa86d322SPavel Emelyanov {
713fa86d322SPavel Emelyanov 	u32 hash_val = *(u32 *)(pkey + key_len - 4);
714fa86d322SPavel Emelyanov 	hash_val ^= (hash_val >> 16);
715fa86d322SPavel Emelyanov 	hash_val ^= hash_val >> 8;
716fa86d322SPavel Emelyanov 	hash_val ^= hash_val >> 4;
717fa86d322SPavel Emelyanov 	hash_val &= PNEIGH_HASHMASK;
718be01d655SYOSHIFUJI Hideaki 	return hash_val;
719fa86d322SPavel Emelyanov }
720fa86d322SPavel Emelyanov 
721be01d655SYOSHIFUJI Hideaki static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
722be01d655SYOSHIFUJI Hideaki 					      struct net *net,
723be01d655SYOSHIFUJI Hideaki 					      const void *pkey,
72401ccdf12SAlexey Dobriyan 					      unsigned int key_len,
725be01d655SYOSHIFUJI Hideaki 					      struct net_device *dev)
726be01d655SYOSHIFUJI Hideaki {
727be01d655SYOSHIFUJI Hideaki 	while (n) {
728be01d655SYOSHIFUJI Hideaki 		if (!memcmp(n->key, pkey, key_len) &&
729be01d655SYOSHIFUJI Hideaki 		    net_eq(pneigh_net(n), net) &&
730be01d655SYOSHIFUJI Hideaki 		    (n->dev == dev || !n->dev))
731fa86d322SPavel Emelyanov 			return n;
732be01d655SYOSHIFUJI Hideaki 		n = n->next;
733be01d655SYOSHIFUJI Hideaki 	}
734be01d655SYOSHIFUJI Hideaki 	return NULL;
735be01d655SYOSHIFUJI Hideaki }
736be01d655SYOSHIFUJI Hideaki 
737be01d655SYOSHIFUJI Hideaki struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
738be01d655SYOSHIFUJI Hideaki 		struct net *net, const void *pkey, struct net_device *dev)
739be01d655SYOSHIFUJI Hideaki {
74001ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
741be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
742be01d655SYOSHIFUJI Hideaki 
743be01d655SYOSHIFUJI Hideaki 	return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
744be01d655SYOSHIFUJI Hideaki 				 net, pkey, key_len, dev);
745fa86d322SPavel Emelyanov }
7460a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL_GPL(__pneigh_lookup);
747fa86d322SPavel Emelyanov 
748426b5303SEric W. Biederman struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
749426b5303SEric W. Biederman 				    struct net *net, const void *pkey,
7501da177e4SLinus Torvalds 				    struct net_device *dev, int creat)
7511da177e4SLinus Torvalds {
7521da177e4SLinus Torvalds 	struct pneigh_entry *n;
75301ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
754be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
7551da177e4SLinus Torvalds 
7561da177e4SLinus Torvalds 	read_lock_bh(&tbl->lock);
757be01d655SYOSHIFUJI Hideaki 	n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
758be01d655SYOSHIFUJI Hideaki 			      net, pkey, key_len, dev);
759be01d655SYOSHIFUJI Hideaki 	read_unlock_bh(&tbl->lock);
7601da177e4SLinus Torvalds 
761be01d655SYOSHIFUJI Hideaki 	if (n || !creat)
7621da177e4SLinus Torvalds 		goto out;
7631da177e4SLinus Torvalds 
7644ae28944SPavel Emelyanov 	ASSERT_RTNL();
7654ae28944SPavel Emelyanov 
766e195e9b5SEric Dumazet 	n = kzalloc(sizeof(*n) + key_len, GFP_KERNEL);
7671da177e4SLinus Torvalds 	if (!n)
7681da177e4SLinus Torvalds 		goto out;
7691da177e4SLinus Torvalds 
770efd7ef1cSEric W. Biederman 	write_pnet(&n->net, net);
7711da177e4SLinus Torvalds 	memcpy(n->key, pkey, key_len);
7721da177e4SLinus Torvalds 	n->dev = dev;
773*d62607c3SJakub Kicinski 	netdev_hold(dev, &n->dev_tracker, GFP_KERNEL);
7741da177e4SLinus Torvalds 
7751da177e4SLinus Torvalds 	if (tbl->pconstructor && tbl->pconstructor(n)) {
776*d62607c3SJakub Kicinski 		netdev_put(dev, &n->dev_tracker);
7771da177e4SLinus Torvalds 		kfree(n);
7781da177e4SLinus Torvalds 		n = NULL;
7791da177e4SLinus Torvalds 		goto out;
7801da177e4SLinus Torvalds 	}
7811da177e4SLinus Torvalds 
7821da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
7831da177e4SLinus Torvalds 	n->next = tbl->phash_buckets[hash_val];
7841da177e4SLinus Torvalds 	tbl->phash_buckets[hash_val] = n;
7851da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
7861da177e4SLinus Torvalds out:
7871da177e4SLinus Torvalds 	return n;
7881da177e4SLinus Torvalds }
7890a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(pneigh_lookup);
7901da177e4SLinus Torvalds 
7911da177e4SLinus Torvalds 
792426b5303SEric W. Biederman int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
7931da177e4SLinus Torvalds 		  struct net_device *dev)
7941da177e4SLinus Torvalds {
7951da177e4SLinus Torvalds 	struct pneigh_entry *n, **np;
79601ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
797be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
7981da177e4SLinus Torvalds 
7991da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
8001da177e4SLinus Torvalds 	for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
8011da177e4SLinus Torvalds 	     np = &n->next) {
802426b5303SEric W. Biederman 		if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
803878628fbSYOSHIFUJI Hideaki 		    net_eq(pneigh_net(n), net)) {
8041da177e4SLinus Torvalds 			*np = n->next;
8051da177e4SLinus Torvalds 			write_unlock_bh(&tbl->lock);
8061da177e4SLinus Torvalds 			if (tbl->pdestructor)
8071da177e4SLinus Torvalds 				tbl->pdestructor(n);
808*d62607c3SJakub Kicinski 			netdev_put(n->dev, &n->dev_tracker);
8091da177e4SLinus Torvalds 			kfree(n);
8101da177e4SLinus Torvalds 			return 0;
8111da177e4SLinus Torvalds 		}
8121da177e4SLinus Torvalds 	}
8131da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
8141da177e4SLinus Torvalds 	return -ENOENT;
8151da177e4SLinus Torvalds }
8161da177e4SLinus Torvalds 
81753b76cdfSWolfgang Bumiller static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
81853b76cdfSWolfgang Bumiller 				    struct net_device *dev)
8191da177e4SLinus Torvalds {
82053b76cdfSWolfgang Bumiller 	struct pneigh_entry *n, **np, *freelist = NULL;
8211da177e4SLinus Torvalds 	u32 h;
8221da177e4SLinus Torvalds 
8231da177e4SLinus Torvalds 	for (h = 0; h <= PNEIGH_HASHMASK; h++) {
8241da177e4SLinus Torvalds 		np = &tbl->phash_buckets[h];
8251da177e4SLinus Torvalds 		while ((n = *np) != NULL) {
8261da177e4SLinus Torvalds 			if (!dev || n->dev == dev) {
8271da177e4SLinus Torvalds 				*np = n->next;
82853b76cdfSWolfgang Bumiller 				n->next = freelist;
82953b76cdfSWolfgang Bumiller 				freelist = n;
83053b76cdfSWolfgang Bumiller 				continue;
83153b76cdfSWolfgang Bumiller 			}
83253b76cdfSWolfgang Bumiller 			np = &n->next;
83353b76cdfSWolfgang Bumiller 		}
83453b76cdfSWolfgang Bumiller 	}
83553b76cdfSWolfgang Bumiller 	write_unlock_bh(&tbl->lock);
83653b76cdfSWolfgang Bumiller 	while ((n = freelist)) {
83753b76cdfSWolfgang Bumiller 		freelist = n->next;
83853b76cdfSWolfgang Bumiller 		n->next = NULL;
8391da177e4SLinus Torvalds 		if (tbl->pdestructor)
8401da177e4SLinus Torvalds 			tbl->pdestructor(n);
841*d62607c3SJakub Kicinski 		netdev_put(n->dev, &n->dev_tracker);
8421da177e4SLinus Torvalds 		kfree(n);
8431da177e4SLinus Torvalds 	}
8441da177e4SLinus Torvalds 	return -ENOENT;
8451da177e4SLinus Torvalds }
8461da177e4SLinus Torvalds 
84706f0511dSDenis V. Lunev static void neigh_parms_destroy(struct neigh_parms *parms);
84806f0511dSDenis V. Lunev 
84906f0511dSDenis V. Lunev static inline void neigh_parms_put(struct neigh_parms *parms)
85006f0511dSDenis V. Lunev {
8516343944bSReshetova, Elena 	if (refcount_dec_and_test(&parms->refcnt))
85206f0511dSDenis V. Lunev 		neigh_parms_destroy(parms);
85306f0511dSDenis V. Lunev }
8541da177e4SLinus Torvalds 
8551da177e4SLinus Torvalds /*
8561da177e4SLinus Torvalds  *	neighbour must already be out of the table;
8571da177e4SLinus Torvalds  *
8581da177e4SLinus Torvalds  */
8591da177e4SLinus Torvalds void neigh_destroy(struct neighbour *neigh)
8601da177e4SLinus Torvalds {
861da6a8fa0SDavid Miller 	struct net_device *dev = neigh->dev;
862da6a8fa0SDavid Miller 
8631da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
8641da177e4SLinus Torvalds 
8651da177e4SLinus Torvalds 	if (!neigh->dead) {
866e005d193SJoe Perches 		pr_warn("Destroying alive neighbour %p\n", neigh);
8671da177e4SLinus Torvalds 		dump_stack();
8681da177e4SLinus Torvalds 		return;
8691da177e4SLinus Torvalds 	}
8701da177e4SLinus Torvalds 
8711da177e4SLinus Torvalds 	if (neigh_del_timer(neigh))
872e005d193SJoe Perches 		pr_warn("Impossible event\n");
8731da177e4SLinus Torvalds 
874c9ab4d85SEric Dumazet 	write_lock_bh(&neigh->lock);
875c9ab4d85SEric Dumazet 	__skb_queue_purge(&neigh->arp_queue);
876c9ab4d85SEric Dumazet 	write_unlock_bh(&neigh->lock);
8778b5c171bSEric Dumazet 	neigh->arp_queue_len_bytes = 0;
8781da177e4SLinus Torvalds 
879447f2191SDavid S. Miller 	if (dev->netdev_ops->ndo_neigh_destroy)
880503eebc2SJiri Pirko 		dev->netdev_ops->ndo_neigh_destroy(dev, neigh);
881447f2191SDavid S. Miller 
882*d62607c3SJakub Kicinski 	netdev_put(dev, &neigh->dev_tracker);
8831da177e4SLinus Torvalds 	neigh_parms_put(neigh->parms);
8841da177e4SLinus Torvalds 
885d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is destroyed\n", neigh);
8861da177e4SLinus Torvalds 
8871da177e4SLinus Torvalds 	atomic_dec(&neigh->tbl->entries);
8885b8b0060SDavid Miller 	kfree_rcu(neigh, rcu);
8891da177e4SLinus Torvalds }
8900a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_destroy);
8911da177e4SLinus Torvalds 
8921da177e4SLinus Torvalds /* Neighbour state is suspicious;
8931da177e4SLinus Torvalds    disable fast path.
8941da177e4SLinus Torvalds 
8951da177e4SLinus Torvalds    Called with write_locked neigh.
8961da177e4SLinus Torvalds  */
8971da177e4SLinus Torvalds static void neigh_suspect(struct neighbour *neigh)
8981da177e4SLinus Torvalds {
899d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is suspected\n", neigh);
9001da177e4SLinus Torvalds 
9011da177e4SLinus Torvalds 	neigh->output = neigh->ops->output;
9021da177e4SLinus Torvalds }
9031da177e4SLinus Torvalds 
9041da177e4SLinus Torvalds /* Neighbour state is OK;
9051da177e4SLinus Torvalds    enable fast path.
9061da177e4SLinus Torvalds 
9071da177e4SLinus Torvalds    Called with write_locked neigh.
9081da177e4SLinus Torvalds  */
9091da177e4SLinus Torvalds static void neigh_connect(struct neighbour *neigh)
9101da177e4SLinus Torvalds {
911d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is connected\n", neigh);
9121da177e4SLinus Torvalds 
9131da177e4SLinus Torvalds 	neigh->output = neigh->ops->connected_output;
9141da177e4SLinus Torvalds }
9151da177e4SLinus Torvalds 
916e4c4e448SEric Dumazet static void neigh_periodic_work(struct work_struct *work)
9171da177e4SLinus Torvalds {
918e4c4e448SEric Dumazet 	struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
919767e97e1SEric Dumazet 	struct neighbour *n;
920767e97e1SEric Dumazet 	struct neighbour __rcu **np;
921e4c4e448SEric Dumazet 	unsigned int i;
922d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
9231da177e4SLinus Torvalds 
9241da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
9251da177e4SLinus Torvalds 
926e4c4e448SEric Dumazet 	write_lock_bh(&tbl->lock);
927d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
928d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
9291da177e4SLinus Torvalds 
9301da177e4SLinus Torvalds 	/*
9311da177e4SLinus Torvalds 	 *	periodically recompute ReachableTime from random function
9321da177e4SLinus Torvalds 	 */
9331da177e4SLinus Torvalds 
934e4c4e448SEric Dumazet 	if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
9351da177e4SLinus Torvalds 		struct neigh_parms *p;
936e4c4e448SEric Dumazet 		tbl->last_rand = jiffies;
93775fbfd33SNicolas Dichtel 		list_for_each_entry(p, &tbl->parms_list, list)
9381da177e4SLinus Torvalds 			p->reachable_time =
9391f9248e5SJiri Pirko 				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
9401da177e4SLinus Torvalds 	}
9411da177e4SLinus Torvalds 
942feff9ab2SDuan Jiong 	if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
943feff9ab2SDuan Jiong 		goto out;
944feff9ab2SDuan Jiong 
945cd089336SDavid S. Miller 	for (i = 0 ; i < (1 << nht->hash_shift); i++) {
946d6bf7817SEric Dumazet 		np = &nht->hash_buckets[i];
9471da177e4SLinus Torvalds 
948767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
949767e97e1SEric Dumazet 				lockdep_is_held(&tbl->lock))) != NULL) {
9501da177e4SLinus Torvalds 			unsigned int state;
9511da177e4SLinus Torvalds 
9521da177e4SLinus Torvalds 			write_lock(&n->lock);
9531da177e4SLinus Torvalds 
9541da177e4SLinus Torvalds 			state = n->nud_state;
9559ce33e46SRoopa Prabhu 			if ((state & (NUD_PERMANENT | NUD_IN_TIMER)) ||
9569ce33e46SRoopa Prabhu 			    (n->flags & NTF_EXT_LEARNED)) {
9571da177e4SLinus Torvalds 				write_unlock(&n->lock);
9581da177e4SLinus Torvalds 				goto next_elt;
9591da177e4SLinus Torvalds 			}
9601da177e4SLinus Torvalds 
9611da177e4SLinus Torvalds 			if (time_before(n->used, n->confirmed))
9621da177e4SLinus Torvalds 				n->used = n->confirmed;
9631da177e4SLinus Torvalds 
9649f237430SReshetova, Elena 			if (refcount_read(&n->refcnt) == 1 &&
9651da177e4SLinus Torvalds 			    (state == NUD_FAILED ||
9661f9248e5SJiri Pirko 			     time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
9671da177e4SLinus Torvalds 				*np = n->next;
96858956317SDavid Ahern 				neigh_mark_dead(n);
9691da177e4SLinus Torvalds 				write_unlock(&n->lock);
9704f494554SThomas Graf 				neigh_cleanup_and_release(n);
9711da177e4SLinus Torvalds 				continue;
9721da177e4SLinus Torvalds 			}
9731da177e4SLinus Torvalds 			write_unlock(&n->lock);
9741da177e4SLinus Torvalds 
9751da177e4SLinus Torvalds next_elt:
9761da177e4SLinus Torvalds 			np = &n->next;
9771da177e4SLinus Torvalds 		}
978e4c4e448SEric Dumazet 		/*
979e4c4e448SEric Dumazet 		 * It's fine to release lock here, even if hash table
980e4c4e448SEric Dumazet 		 * grows while we are preempted.
981e4c4e448SEric Dumazet 		 */
982e4c4e448SEric Dumazet 		write_unlock_bh(&tbl->lock);
983e4c4e448SEric Dumazet 		cond_resched();
984e4c4e448SEric Dumazet 		write_lock_bh(&tbl->lock);
98584338a6cSMichel Machado 		nht = rcu_dereference_protected(tbl->nht,
98684338a6cSMichel Machado 						lockdep_is_held(&tbl->lock));
987e4c4e448SEric Dumazet 	}
9882724680bSYOSHIFUJI Hideaki / 吉藤英明 out:
9891f9248e5SJiri Pirko 	/* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks.
9901f9248e5SJiri Pirko 	 * ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2
9911f9248e5SJiri Pirko 	 * BASE_REACHABLE_TIME.
9921da177e4SLinus Torvalds 	 */
993f618002bSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
9941f9248e5SJiri Pirko 			      NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1);
995e4c4e448SEric Dumazet 	write_unlock_bh(&tbl->lock);
9961da177e4SLinus Torvalds }
9971da177e4SLinus Torvalds 
9981da177e4SLinus Torvalds static __inline__ int neigh_max_probes(struct neighbour *n)
9991da177e4SLinus Torvalds {
10001da177e4SLinus Torvalds 	struct neigh_parms *p = n->parms;
10018da86466SYOSHIFUJI Hideaki/吉藤英明 	return NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) +
10028da86466SYOSHIFUJI Hideaki/吉藤英明 	       (n->nud_state & NUD_PROBE ? NEIGH_VAR(p, MCAST_REPROBES) :
10038da86466SYOSHIFUJI Hideaki/吉藤英明 	        NEIGH_VAR(p, MCAST_PROBES));
10041da177e4SLinus Torvalds }
10051da177e4SLinus Torvalds 
10065ef12d98STimo Teras static void neigh_invalidate(struct neighbour *neigh)
10070a141509SEric Dumazet 	__releases(neigh->lock)
10080a141509SEric Dumazet 	__acquires(neigh->lock)
10095ef12d98STimo Teras {
10105ef12d98STimo Teras 	struct sk_buff *skb;
10115ef12d98STimo Teras 
10125ef12d98STimo Teras 	NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
1013d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is failed\n", neigh);
10145ef12d98STimo Teras 	neigh->updated = jiffies;
10155ef12d98STimo Teras 
10165ef12d98STimo Teras 	/* It is very thin place. report_unreachable is very complicated
10175ef12d98STimo Teras 	   routine. Particularly, it can hit the same neighbour entry!
10185ef12d98STimo Teras 
10195ef12d98STimo Teras 	   So that, we try to be accurate and avoid dead loop. --ANK
10205ef12d98STimo Teras 	 */
10215ef12d98STimo Teras 	while (neigh->nud_state == NUD_FAILED &&
10225ef12d98STimo Teras 	       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
10235ef12d98STimo Teras 		write_unlock(&neigh->lock);
10245ef12d98STimo Teras 		neigh->ops->error_report(neigh, skb);
10255ef12d98STimo Teras 		write_lock(&neigh->lock);
10265ef12d98STimo Teras 	}
1027c9ab4d85SEric Dumazet 	__skb_queue_purge(&neigh->arp_queue);
10288b5c171bSEric Dumazet 	neigh->arp_queue_len_bytes = 0;
10295ef12d98STimo Teras }
10305ef12d98STimo Teras 
1031cd28ca0aSEric Dumazet static void neigh_probe(struct neighbour *neigh)
1032cd28ca0aSEric Dumazet 	__releases(neigh->lock)
1033cd28ca0aSEric Dumazet {
10344ed377e3SHannes Frederic Sowa 	struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);
1035cd28ca0aSEric Dumazet 	/* keep skb alive even if arp_queue overflows */
1036cd28ca0aSEric Dumazet 	if (skb)
103719125c1aSMartin Zhang 		skb = skb_clone(skb, GFP_ATOMIC);
1038cd28ca0aSEric Dumazet 	write_unlock(&neigh->lock);
103948481c8fSEric Dumazet 	if (neigh->ops->solicit)
1040cd28ca0aSEric Dumazet 		neigh->ops->solicit(neigh, skb);
1041cd28ca0aSEric Dumazet 	atomic_inc(&neigh->probes);
104287fff3caSYang Wei 	consume_skb(skb);
1043cd28ca0aSEric Dumazet }
1044cd28ca0aSEric Dumazet 
10451da177e4SLinus Torvalds /* Called when a timer expires for a neighbour entry. */
10461da177e4SLinus Torvalds 
1047e99e88a9SKees Cook static void neigh_timer_handler(struct timer_list *t)
10481da177e4SLinus Torvalds {
10491da177e4SLinus Torvalds 	unsigned long now, next;
1050e99e88a9SKees Cook 	struct neighbour *neigh = from_timer(neigh, t, timer);
105195c96174SEric Dumazet 	unsigned int state;
10521da177e4SLinus Torvalds 	int notify = 0;
10531da177e4SLinus Torvalds 
10541da177e4SLinus Torvalds 	write_lock(&neigh->lock);
10551da177e4SLinus Torvalds 
10561da177e4SLinus Torvalds 	state = neigh->nud_state;
10571da177e4SLinus Torvalds 	now = jiffies;
10581da177e4SLinus Torvalds 	next = now + HZ;
10591da177e4SLinus Torvalds 
1060045f7b3bSDavid S. Miller 	if (!(state & NUD_IN_TIMER))
10611da177e4SLinus Torvalds 		goto out;
10621da177e4SLinus Torvalds 
10631da177e4SLinus Torvalds 	if (state & NUD_REACHABLE) {
10641da177e4SLinus Torvalds 		if (time_before_eq(now,
10651da177e4SLinus Torvalds 				   neigh->confirmed + neigh->parms->reachable_time)) {
1066d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is still alive\n", neigh);
10671da177e4SLinus Torvalds 			next = neigh->confirmed + neigh->parms->reachable_time;
10681da177e4SLinus Torvalds 		} else if (time_before_eq(now,
10691f9248e5SJiri Pirko 					  neigh->used +
10701f9248e5SJiri Pirko 					  NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
1071d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is delayed\n", neigh);
10721da177e4SLinus Torvalds 			neigh->nud_state = NUD_DELAY;
1073955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10741da177e4SLinus Torvalds 			neigh_suspect(neigh);
10751f9248e5SJiri Pirko 			next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME);
10761da177e4SLinus Torvalds 		} else {
1077d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is suspected\n", neigh);
10781da177e4SLinus Torvalds 			neigh->nud_state = NUD_STALE;
1079955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10801da177e4SLinus Torvalds 			neigh_suspect(neigh);
10818d71740cSTom Tucker 			notify = 1;
10821da177e4SLinus Torvalds 		}
10831da177e4SLinus Torvalds 	} else if (state & NUD_DELAY) {
10841da177e4SLinus Torvalds 		if (time_before_eq(now,
10851f9248e5SJiri Pirko 				   neigh->confirmed +
10861f9248e5SJiri Pirko 				   NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
1087d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is now reachable\n", neigh);
10881da177e4SLinus Torvalds 			neigh->nud_state = NUD_REACHABLE;
1089955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10901da177e4SLinus Torvalds 			neigh_connect(neigh);
10918d71740cSTom Tucker 			notify = 1;
10921da177e4SLinus Torvalds 			next = neigh->confirmed + neigh->parms->reachable_time;
10931da177e4SLinus Torvalds 		} else {
1094d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is probed\n", neigh);
10951da177e4SLinus Torvalds 			neigh->nud_state = NUD_PROBE;
1096955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10971da177e4SLinus Torvalds 			atomic_set(&neigh->probes, 0);
1098765c9c63SErik Kline 			notify = 1;
109919e16d22SHangbin Liu 			next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
110019e16d22SHangbin Liu 					 HZ/100);
11011da177e4SLinus Torvalds 		}
11021da177e4SLinus Torvalds 	} else {
11031da177e4SLinus Torvalds 		/* NUD_PROBE|NUD_INCOMPLETE */
110419e16d22SHangbin Liu 		next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME), HZ/100);
11051da177e4SLinus Torvalds 	}
11061da177e4SLinus Torvalds 
11071da177e4SLinus Torvalds 	if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
11081da177e4SLinus Torvalds 	    atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
11091da177e4SLinus Torvalds 		neigh->nud_state = NUD_FAILED;
11101da177e4SLinus Torvalds 		notify = 1;
11115ef12d98STimo Teras 		neigh_invalidate(neigh);
11125e2c21dcSDuan Jiong 		goto out;
11131da177e4SLinus Torvalds 	}
11141da177e4SLinus Torvalds 
11151da177e4SLinus Torvalds 	if (neigh->nud_state & NUD_IN_TIMER) {
111696d10d5bSHangbin Liu 		if (time_before(next, jiffies + HZ/100))
111796d10d5bSHangbin Liu 			next = jiffies + HZ/100;
11186fb9974fSHerbert Xu 		if (!mod_timer(&neigh->timer, next))
11196fb9974fSHerbert Xu 			neigh_hold(neigh);
11201da177e4SLinus Torvalds 	}
11211da177e4SLinus Torvalds 	if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
1122cd28ca0aSEric Dumazet 		neigh_probe(neigh);
11239ff56607SDavid S. Miller 	} else {
11241da177e4SLinus Torvalds out:
11251da177e4SLinus Torvalds 		write_unlock(&neigh->lock);
11269ff56607SDavid S. Miller 	}
11271da177e4SLinus Torvalds 
1128d961db35SThomas Graf 	if (notify)
11297b8f7a40SRoopa Prabhu 		neigh_update_notify(neigh, 0);
1130d961db35SThomas Graf 
113156dd18a4SRoopa Prabhu 	trace_neigh_timer_handler(neigh, 0);
113256dd18a4SRoopa Prabhu 
11331da177e4SLinus Torvalds 	neigh_release(neigh);
11341da177e4SLinus Torvalds }
11351da177e4SLinus Torvalds 
11364a81f6daSDaniel Borkmann int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb,
11374a81f6daSDaniel Borkmann 		       const bool immediate_ok)
11381da177e4SLinus Torvalds {
11391da177e4SLinus Torvalds 	int rc;
1140cd28ca0aSEric Dumazet 	bool immediate_probe = false;
11411da177e4SLinus Torvalds 
11421da177e4SLinus Torvalds 	write_lock_bh(&neigh->lock);
11431da177e4SLinus Torvalds 
11441da177e4SLinus Torvalds 	rc = 0;
11451da177e4SLinus Torvalds 	if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
11461da177e4SLinus Torvalds 		goto out_unlock_bh;
11472c51a97fSJulian Anastasov 	if (neigh->dead)
11482c51a97fSJulian Anastasov 		goto out_dead;
11491da177e4SLinus Torvalds 
11501da177e4SLinus Torvalds 	if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
11511f9248e5SJiri Pirko 		if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
11521f9248e5SJiri Pirko 		    NEIGH_VAR(neigh->parms, APP_PROBES)) {
1153cd28ca0aSEric Dumazet 			unsigned long next, now = jiffies;
1154cd28ca0aSEric Dumazet 
11551f9248e5SJiri Pirko 			atomic_set(&neigh->probes,
11561f9248e5SJiri Pirko 				   NEIGH_VAR(neigh->parms, UCAST_PROBES));
1157071c3798SLorenzo Bianconi 			neigh_del_timer(neigh);
11581da177e4SLinus Torvalds 			neigh->nud_state = NUD_INCOMPLETE;
1159cd28ca0aSEric Dumazet 			neigh->updated = now;
11604a81f6daSDaniel Borkmann 			if (!immediate_ok) {
11614a81f6daSDaniel Borkmann 				next = now + 1;
11624a81f6daSDaniel Borkmann 			} else {
1163cd28ca0aSEric Dumazet 				immediate_probe = true;
11644a81f6daSDaniel Borkmann 				next = now + max(NEIGH_VAR(neigh->parms,
11654a81f6daSDaniel Borkmann 							   RETRANS_TIME),
11664a81f6daSDaniel Borkmann 						 HZ / 100);
11674a81f6daSDaniel Borkmann 			}
11684a81f6daSDaniel Borkmann 			neigh_add_timer(neigh, next);
11691da177e4SLinus Torvalds 		} else {
11701da177e4SLinus Torvalds 			neigh->nud_state = NUD_FAILED;
1171955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
11721da177e4SLinus Torvalds 			write_unlock_bh(&neigh->lock);
11731da177e4SLinus Torvalds 
1174a5736eddSMenglong Dong 			kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_FAILED);
11751da177e4SLinus Torvalds 			return 1;
11761da177e4SLinus Torvalds 		}
11771da177e4SLinus Torvalds 	} else if (neigh->nud_state & NUD_STALE) {
1178d5d427cdSJoe Perches 		neigh_dbg(2, "neigh %p is delayed\n", neigh);
1179071c3798SLorenzo Bianconi 		neigh_del_timer(neigh);
11801da177e4SLinus Torvalds 		neigh->nud_state = NUD_DELAY;
1181955aaa2fSYOSHIFUJI Hideaki 		neigh->updated = jiffies;
11821f9248e5SJiri Pirko 		neigh_add_timer(neigh, jiffies +
11831f9248e5SJiri Pirko 				NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME));
11841da177e4SLinus Torvalds 	}
11851da177e4SLinus Torvalds 
11861da177e4SLinus Torvalds 	if (neigh->nud_state == NUD_INCOMPLETE) {
11871da177e4SLinus Torvalds 		if (skb) {
11888b5c171bSEric Dumazet 			while (neigh->arp_queue_len_bytes + skb->truesize >
11891f9248e5SJiri Pirko 			       NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) {
11901da177e4SLinus Torvalds 				struct sk_buff *buff;
11918b5c171bSEric Dumazet 
1192f72051b0SDavid S. Miller 				buff = __skb_dequeue(&neigh->arp_queue);
11938b5c171bSEric Dumazet 				if (!buff)
11948b5c171bSEric Dumazet 					break;
11958b5c171bSEric Dumazet 				neigh->arp_queue_len_bytes -= buff->truesize;
1196a5736eddSMenglong Dong 				kfree_skb_reason(buff, SKB_DROP_REASON_NEIGH_QUEUEFULL);
11979a6d276eSNeil Horman 				NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
11981da177e4SLinus Torvalds 			}
1199a4731138SEric Dumazet 			skb_dst_force(skb);
12001da177e4SLinus Torvalds 			__skb_queue_tail(&neigh->arp_queue, skb);
12018b5c171bSEric Dumazet 			neigh->arp_queue_len_bytes += skb->truesize;
12021da177e4SLinus Torvalds 		}
12031da177e4SLinus Torvalds 		rc = 1;
12041da177e4SLinus Torvalds 	}
12051da177e4SLinus Torvalds out_unlock_bh:
1206cd28ca0aSEric Dumazet 	if (immediate_probe)
1207cd28ca0aSEric Dumazet 		neigh_probe(neigh);
1208cd28ca0aSEric Dumazet 	else
1209cd28ca0aSEric Dumazet 		write_unlock(&neigh->lock);
1210cd28ca0aSEric Dumazet 	local_bh_enable();
121156dd18a4SRoopa Prabhu 	trace_neigh_event_send_done(neigh, rc);
12121da177e4SLinus Torvalds 	return rc;
12132c51a97fSJulian Anastasov 
12142c51a97fSJulian Anastasov out_dead:
12152c51a97fSJulian Anastasov 	if (neigh->nud_state & NUD_STALE)
12162c51a97fSJulian Anastasov 		goto out_unlock_bh;
12172c51a97fSJulian Anastasov 	write_unlock_bh(&neigh->lock);
1218a5736eddSMenglong Dong 	kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_DEAD);
121956dd18a4SRoopa Prabhu 	trace_neigh_event_send_dead(neigh, 1);
12202c51a97fSJulian Anastasov 	return 1;
12211da177e4SLinus Torvalds }
12220a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(__neigh_event_send);
12231da177e4SLinus Torvalds 
1224f6b72b62SDavid S. Miller static void neigh_update_hhs(struct neighbour *neigh)
12251da177e4SLinus Torvalds {
12261da177e4SLinus Torvalds 	struct hh_cache *hh;
12273b04dddeSStephen Hemminger 	void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
122891a72a70SDoug Kehn 		= NULL;
122991a72a70SDoug Kehn 
123091a72a70SDoug Kehn 	if (neigh->dev->header_ops)
123191a72a70SDoug Kehn 		update = neigh->dev->header_ops->cache_update;
12321da177e4SLinus Torvalds 
12331da177e4SLinus Torvalds 	if (update) {
1234f6b72b62SDavid S. Miller 		hh = &neigh->hh;
1235c305c6aeSEric Dumazet 		if (READ_ONCE(hh->hh_len)) {
12363644f0ceSStephen Hemminger 			write_seqlock_bh(&hh->hh_lock);
12371da177e4SLinus Torvalds 			update(hh, neigh->dev, neigh->ha);
12383644f0ceSStephen Hemminger 			write_sequnlock_bh(&hh->hh_lock);
12391da177e4SLinus Torvalds 		}
12401da177e4SLinus Torvalds 	}
12411da177e4SLinus Torvalds }
12421da177e4SLinus Torvalds 
12431da177e4SLinus Torvalds /* Generic update routine.
12441da177e4SLinus Torvalds    -- lladdr is new lladdr or NULL, if it is not supplied.
12451da177e4SLinus Torvalds    -- new    is new state.
12461da177e4SLinus Torvalds    -- flags
12471da177e4SLinus Torvalds 	NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
12481da177e4SLinus Torvalds 				if it is different.
12491da177e4SLinus Torvalds 	NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
12501da177e4SLinus Torvalds 				lladdr instead of overriding it
12511da177e4SLinus Torvalds 				if it is different.
12521da177e4SLinus Torvalds 	NEIGH_UPDATE_F_ADMIN	means that the change is administrative.
12533dc20f47SDaniel Borkmann 	NEIGH_UPDATE_F_USE	means that the entry is user triggered.
12547482e384SDaniel Borkmann 	NEIGH_UPDATE_F_MANAGED	means that the entry will be auto-refreshed.
12551da177e4SLinus Torvalds 	NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
12561da177e4SLinus Torvalds 				NTF_ROUTER flag.
12571da177e4SLinus Torvalds 	NEIGH_UPDATE_F_ISROUTER	indicates if the neighbour is known as
12581da177e4SLinus Torvalds 				a router.
12591da177e4SLinus Torvalds 
12601da177e4SLinus Torvalds    Caller MUST hold reference count on the entry.
12611da177e4SLinus Torvalds  */
12627a35a50dSDavid Ahern static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
12637a35a50dSDavid Ahern 			  u8 new, u32 flags, u32 nlmsg_pid,
12647a35a50dSDavid Ahern 			  struct netlink_ext_ack *extack)
12651da177e4SLinus Torvalds {
12667482e384SDaniel Borkmann 	bool gc_update = false, managed_update = false;
12671da177e4SLinus Torvalds 	int update_isrouter = 0;
12687482e384SDaniel Borkmann 	struct net_device *dev;
12697482e384SDaniel Borkmann 	int err, notify = 0;
12707482e384SDaniel Borkmann 	u8 old;
12711da177e4SLinus Torvalds 
127256dd18a4SRoopa Prabhu 	trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid);
127356dd18a4SRoopa Prabhu 
12741da177e4SLinus Torvalds 	write_lock_bh(&neigh->lock);
12751da177e4SLinus Torvalds 
12761da177e4SLinus Torvalds 	dev    = neigh->dev;
12771da177e4SLinus Torvalds 	old    = neigh->nud_state;
12781da177e4SLinus Torvalds 	err    = -EPERM;
12791da177e4SLinus Torvalds 
1280eb4e8facSChinmay Agarwal 	if (neigh->dead) {
1281eb4e8facSChinmay Agarwal 		NL_SET_ERR_MSG(extack, "Neighbor entry is now dead");
1282eb4e8facSChinmay Agarwal 		new = old;
1283eb4e8facSChinmay Agarwal 		goto out;
1284eb4e8facSChinmay Agarwal 	}
12851da177e4SLinus Torvalds 	if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
12861da177e4SLinus Torvalds 	    (old & (NUD_NOARP | NUD_PERMANENT)))
12871da177e4SLinus Torvalds 		goto out;
12881da177e4SLinus Torvalds 
12897482e384SDaniel Borkmann 	neigh_update_flags(neigh, flags, &notify, &gc_update, &managed_update);
12907482e384SDaniel Borkmann 	if (flags & (NEIGH_UPDATE_F_USE | NEIGH_UPDATE_F_MANAGED)) {
12913dc20f47SDaniel Borkmann 		new = old & ~NUD_PERMANENT;
12923dc20f47SDaniel Borkmann 		neigh->nud_state = new;
12933dc20f47SDaniel Borkmann 		err = 0;
12943dc20f47SDaniel Borkmann 		goto out;
12953dc20f47SDaniel Borkmann 	}
12969ce33e46SRoopa Prabhu 
12971da177e4SLinus Torvalds 	if (!(new & NUD_VALID)) {
12981da177e4SLinus Torvalds 		neigh_del_timer(neigh);
12991da177e4SLinus Torvalds 		if (old & NUD_CONNECTED)
13001da177e4SLinus Torvalds 			neigh_suspect(neigh);
13019c29a2f5SDavid Ahern 		neigh->nud_state = new;
13021da177e4SLinus Torvalds 		err = 0;
13031da177e4SLinus Torvalds 		notify = old & NUD_VALID;
1304d2fb4fb8SRoopa Prabhu 		if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
13055ef12d98STimo Teras 		    (new & NUD_FAILED)) {
13065ef12d98STimo Teras 			neigh_invalidate(neigh);
13075ef12d98STimo Teras 			notify = 1;
13085ef12d98STimo Teras 		}
13091da177e4SLinus Torvalds 		goto out;
13101da177e4SLinus Torvalds 	}
13111da177e4SLinus Torvalds 
13121da177e4SLinus Torvalds 	/* Compare new lladdr with cached one */
13131da177e4SLinus Torvalds 	if (!dev->addr_len) {
13141da177e4SLinus Torvalds 		/* First case: device needs no address. */
13151da177e4SLinus Torvalds 		lladdr = neigh->ha;
13161da177e4SLinus Torvalds 	} else if (lladdr) {
13171da177e4SLinus Torvalds 		/* The second case: if something is already cached
13181da177e4SLinus Torvalds 		   and a new address is proposed:
13191da177e4SLinus Torvalds 		   - compare new & old
13201da177e4SLinus Torvalds 		   - if they are different, check override flag
13211da177e4SLinus Torvalds 		 */
13221da177e4SLinus Torvalds 		if ((old & NUD_VALID) &&
13231da177e4SLinus Torvalds 		    !memcmp(lladdr, neigh->ha, dev->addr_len))
13241da177e4SLinus Torvalds 			lladdr = neigh->ha;
13251da177e4SLinus Torvalds 	} else {
13261da177e4SLinus Torvalds 		/* No address is supplied; if we know something,
13271da177e4SLinus Torvalds 		   use it, otherwise discard the request.
13281da177e4SLinus Torvalds 		 */
13291da177e4SLinus Torvalds 		err = -EINVAL;
13307a35a50dSDavid Ahern 		if (!(old & NUD_VALID)) {
13317a35a50dSDavid Ahern 			NL_SET_ERR_MSG(extack, "No link layer address given");
13321da177e4SLinus Torvalds 			goto out;
13337a35a50dSDavid Ahern 		}
13341da177e4SLinus Torvalds 		lladdr = neigh->ha;
13351da177e4SLinus Torvalds 	}
13361da177e4SLinus Torvalds 
1337f0e0d044SVasily Khoruzhick 	/* Update confirmed timestamp for neighbour entry after we
1338f0e0d044SVasily Khoruzhick 	 * received ARP packet even if it doesn't change IP to MAC binding.
1339f0e0d044SVasily Khoruzhick 	 */
1340f0e0d044SVasily Khoruzhick 	if (new & NUD_CONNECTED)
1341f0e0d044SVasily Khoruzhick 		neigh->confirmed = jiffies;
1342f0e0d044SVasily Khoruzhick 
13431da177e4SLinus Torvalds 	/* If entry was valid and address is not changed,
13441da177e4SLinus Torvalds 	   do not change entry state, if new one is STALE.
13451da177e4SLinus Torvalds 	 */
13461da177e4SLinus Torvalds 	err = 0;
13471da177e4SLinus Torvalds 	update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
13481da177e4SLinus Torvalds 	if (old & NUD_VALID) {
13491da177e4SLinus Torvalds 		if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
13501da177e4SLinus Torvalds 			update_isrouter = 0;
13511da177e4SLinus Torvalds 			if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
13521da177e4SLinus Torvalds 			    (old & NUD_CONNECTED)) {
13531da177e4SLinus Torvalds 				lladdr = neigh->ha;
13541da177e4SLinus Torvalds 				new = NUD_STALE;
13551da177e4SLinus Torvalds 			} else
13561da177e4SLinus Torvalds 				goto out;
13571da177e4SLinus Torvalds 		} else {
13580e7bbcc1SJulian Anastasov 			if (lladdr == neigh->ha && new == NUD_STALE &&
13590e7bbcc1SJulian Anastasov 			    !(flags & NEIGH_UPDATE_F_ADMIN))
13601da177e4SLinus Torvalds 				new = old;
13611da177e4SLinus Torvalds 		}
13621da177e4SLinus Torvalds 	}
13631da177e4SLinus Torvalds 
1364f0e0d044SVasily Khoruzhick 	/* Update timestamp only once we know we will make a change to the
136577d71233SIhar Hrachyshka 	 * neighbour entry. Otherwise we risk to move the locktime window with
136677d71233SIhar Hrachyshka 	 * noop updates and ignore relevant ARP updates.
136777d71233SIhar Hrachyshka 	 */
1368f0e0d044SVasily Khoruzhick 	if (new != old || lladdr != neigh->ha)
136977d71233SIhar Hrachyshka 		neigh->updated = jiffies;
137077d71233SIhar Hrachyshka 
13711da177e4SLinus Torvalds 	if (new != old) {
13721da177e4SLinus Torvalds 		neigh_del_timer(neigh);
1373765c9c63SErik Kline 		if (new & NUD_PROBE)
1374765c9c63SErik Kline 			atomic_set(&neigh->probes, 0);
1375a43d8994SPavel Emelyanov 		if (new & NUD_IN_TIMER)
1376667347f1SDavid S. Miller 			neigh_add_timer(neigh, (jiffies +
13771da177e4SLinus Torvalds 						((new & NUD_REACHABLE) ?
1378667347f1SDavid S. Miller 						 neigh->parms->reachable_time :
1379667347f1SDavid S. Miller 						 0)));
13809c29a2f5SDavid Ahern 		neigh->nud_state = new;
138153385d2dSBob Gilligan 		notify = 1;
13821da177e4SLinus Torvalds 	}
13831da177e4SLinus Torvalds 
13841da177e4SLinus Torvalds 	if (lladdr != neigh->ha) {
13850ed8ddf4SEric Dumazet 		write_seqlock(&neigh->ha_lock);
13861da177e4SLinus Torvalds 		memcpy(&neigh->ha, lladdr, dev->addr_len);
13870ed8ddf4SEric Dumazet 		write_sequnlock(&neigh->ha_lock);
13881da177e4SLinus Torvalds 		neigh_update_hhs(neigh);
13891da177e4SLinus Torvalds 		if (!(new & NUD_CONNECTED))
13901da177e4SLinus Torvalds 			neigh->confirmed = jiffies -
13911f9248e5SJiri Pirko 				      (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1);
13921da177e4SLinus Torvalds 		notify = 1;
13931da177e4SLinus Torvalds 	}
13941da177e4SLinus Torvalds 	if (new == old)
13951da177e4SLinus Torvalds 		goto out;
13961da177e4SLinus Torvalds 	if (new & NUD_CONNECTED)
13971da177e4SLinus Torvalds 		neigh_connect(neigh);
13981da177e4SLinus Torvalds 	else
13991da177e4SLinus Torvalds 		neigh_suspect(neigh);
14001da177e4SLinus Torvalds 	if (!(old & NUD_VALID)) {
14011da177e4SLinus Torvalds 		struct sk_buff *skb;
14021da177e4SLinus Torvalds 
14031da177e4SLinus Torvalds 		/* Again: avoid dead loop if something went wrong */
14041da177e4SLinus Torvalds 
14051da177e4SLinus Torvalds 		while (neigh->nud_state & NUD_VALID &&
14061da177e4SLinus Torvalds 		       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
140769cce1d1SDavid S. Miller 			struct dst_entry *dst = skb_dst(skb);
140869cce1d1SDavid S. Miller 			struct neighbour *n2, *n1 = neigh;
14091da177e4SLinus Torvalds 			write_unlock_bh(&neigh->lock);
1410e049f288Sroy.qing.li@gmail.com 
1411e049f288Sroy.qing.li@gmail.com 			rcu_read_lock();
141213a43d94SDavid S. Miller 
141313a43d94SDavid S. Miller 			/* Why not just use 'neigh' as-is?  The problem is that
141413a43d94SDavid S. Miller 			 * things such as shaper, eql, and sch_teql can end up
141513a43d94SDavid S. Miller 			 * using alternative, different, neigh objects to output
141613a43d94SDavid S. Miller 			 * the packet in the output path.  So what we need to do
141713a43d94SDavid S. Miller 			 * here is re-lookup the top-level neigh in the path so
141813a43d94SDavid S. Miller 			 * we can reinject the packet there.
141913a43d94SDavid S. Miller 			 */
142013a43d94SDavid S. Miller 			n2 = NULL;
1421d47ec7a0STong Zhu 			if (dst && dst->obsolete != DST_OBSOLETE_DEAD) {
142213a43d94SDavid S. Miller 				n2 = dst_neigh_lookup_skb(dst, skb);
142313a43d94SDavid S. Miller 				if (n2)
142469cce1d1SDavid S. Miller 					n1 = n2;
142513a43d94SDavid S. Miller 			}
14268f40b161SDavid S. Miller 			n1->output(n1, skb);
142713a43d94SDavid S. Miller 			if (n2)
142813a43d94SDavid S. Miller 				neigh_release(n2);
1429e049f288Sroy.qing.li@gmail.com 			rcu_read_unlock();
1430e049f288Sroy.qing.li@gmail.com 
14311da177e4SLinus Torvalds 			write_lock_bh(&neigh->lock);
14321da177e4SLinus Torvalds 		}
1433c9ab4d85SEric Dumazet 		__skb_queue_purge(&neigh->arp_queue);
14348b5c171bSEric Dumazet 		neigh->arp_queue_len_bytes = 0;
14351da177e4SLinus Torvalds 	}
14361da177e4SLinus Torvalds out:
1437fc6e8073SRoopa Prabhu 	if (update_isrouter)
1438fc6e8073SRoopa Prabhu 		neigh_update_is_router(neigh, flags, &notify);
14391da177e4SLinus Torvalds 	write_unlock_bh(&neigh->lock);
14407482e384SDaniel Borkmann 	if (((new ^ old) & NUD_PERMANENT) || gc_update)
14419c29a2f5SDavid Ahern 		neigh_update_gc_list(neigh);
14427482e384SDaniel Borkmann 	if (managed_update)
14437482e384SDaniel Borkmann 		neigh_update_managed_list(neigh);
14448d71740cSTom Tucker 	if (notify)
14457b8f7a40SRoopa Prabhu 		neigh_update_notify(neigh, nlmsg_pid);
144656dd18a4SRoopa Prabhu 	trace_neigh_update_done(neigh, err);
14471da177e4SLinus Torvalds 	return err;
14481da177e4SLinus Torvalds }
14497a35a50dSDavid Ahern 
14507a35a50dSDavid Ahern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
14517a35a50dSDavid Ahern 		 u32 flags, u32 nlmsg_pid)
14527a35a50dSDavid Ahern {
14537a35a50dSDavid Ahern 	return __neigh_update(neigh, lladdr, new, flags, nlmsg_pid, NULL);
14547a35a50dSDavid Ahern }
14550a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_update);
14561da177e4SLinus Torvalds 
14577e980569SJiri Benc /* Update the neigh to listen temporarily for probe responses, even if it is
14587e980569SJiri Benc  * in a NUD_FAILED state. The caller has to hold neigh->lock for writing.
14597e980569SJiri Benc  */
14607e980569SJiri Benc void __neigh_set_probe_once(struct neighbour *neigh)
14617e980569SJiri Benc {
14622c51a97fSJulian Anastasov 	if (neigh->dead)
14632c51a97fSJulian Anastasov 		return;
14647e980569SJiri Benc 	neigh->updated = jiffies;
14657e980569SJiri Benc 	if (!(neigh->nud_state & NUD_FAILED))
14667e980569SJiri Benc 		return;
14672176d5d4SDuan Jiong 	neigh->nud_state = NUD_INCOMPLETE;
14682176d5d4SDuan Jiong 	atomic_set(&neigh->probes, neigh_max_probes(neigh));
14697e980569SJiri Benc 	neigh_add_timer(neigh,
147019e16d22SHangbin Liu 			jiffies + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
147119e16d22SHangbin Liu 				      HZ/100));
14727e980569SJiri Benc }
14737e980569SJiri Benc EXPORT_SYMBOL(__neigh_set_probe_once);
14747e980569SJiri Benc 
14751da177e4SLinus Torvalds struct neighbour *neigh_event_ns(struct neigh_table *tbl,
14761da177e4SLinus Torvalds 				 u8 *lladdr, void *saddr,
14771da177e4SLinus Torvalds 				 struct net_device *dev)
14781da177e4SLinus Torvalds {
14791da177e4SLinus Torvalds 	struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
14801da177e4SLinus Torvalds 						 lladdr || !dev->addr_len);
14811da177e4SLinus Torvalds 	if (neigh)
14821da177e4SLinus Torvalds 		neigh_update(neigh, lladdr, NUD_STALE,
14837b8f7a40SRoopa Prabhu 			     NEIGH_UPDATE_F_OVERRIDE, 0);
14841da177e4SLinus Torvalds 	return neigh;
14851da177e4SLinus Torvalds }
14860a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_event_ns);
14871da177e4SLinus Torvalds 
148834d101ddSEric Dumazet /* called with read_lock_bh(&n->lock); */
1489bdf53c58SEric W. Biederman static void neigh_hh_init(struct neighbour *n)
14901da177e4SLinus Torvalds {
1491bdf53c58SEric W. Biederman 	struct net_device *dev = n->dev;
1492bdf53c58SEric W. Biederman 	__be16 prot = n->tbl->protocol;
1493f6b72b62SDavid S. Miller 	struct hh_cache	*hh = &n->hh;
14940ed8ddf4SEric Dumazet 
14950ed8ddf4SEric Dumazet 	write_lock_bh(&n->lock);
149634d101ddSEric Dumazet 
1497f6b72b62SDavid S. Miller 	/* Only one thread can come in here and initialize the
1498f6b72b62SDavid S. Miller 	 * hh_cache entry.
1499f6b72b62SDavid S. Miller 	 */
1500b23b5455SDavid S. Miller 	if (!hh->hh_len)
1501b23b5455SDavid S. Miller 		dev->header_ops->cache(n, hh, prot);
1502f6b72b62SDavid S. Miller 
15030ed8ddf4SEric Dumazet 	write_unlock_bh(&n->lock);
15041da177e4SLinus Torvalds }
15051da177e4SLinus Torvalds 
15061da177e4SLinus Torvalds /* Slow and careful. */
15071da177e4SLinus Torvalds 
15088f40b161SDavid S. Miller int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
15091da177e4SLinus Torvalds {
15101da177e4SLinus Torvalds 	int rc = 0;
15111da177e4SLinus Torvalds 
15121da177e4SLinus Torvalds 	if (!neigh_event_send(neigh, skb)) {
15131da177e4SLinus Torvalds 		int err;
15141da177e4SLinus Torvalds 		struct net_device *dev = neigh->dev;
15150ed8ddf4SEric Dumazet 		unsigned int seq;
151634d101ddSEric Dumazet 
1517c305c6aeSEric Dumazet 		if (dev->header_ops->cache && !READ_ONCE(neigh->hh.hh_len))
1518bdf53c58SEric W. Biederman 			neigh_hh_init(neigh);
151934d101ddSEric Dumazet 
15200ed8ddf4SEric Dumazet 		do {
1521e1f16503Sramesh.nagappa@gmail.com 			__skb_pull(skb, skb_network_offset(skb));
15220ed8ddf4SEric Dumazet 			seq = read_seqbegin(&neigh->ha_lock);
15230c4e8581SStephen Hemminger 			err = dev_hard_header(skb, dev, ntohs(skb->protocol),
15241da177e4SLinus Torvalds 					      neigh->ha, NULL, skb->len);
15250ed8ddf4SEric Dumazet 		} while (read_seqretry(&neigh->ha_lock, seq));
152634d101ddSEric Dumazet 
15271da177e4SLinus Torvalds 		if (err >= 0)
1528542d4d68SDavid S. Miller 			rc = dev_queue_xmit(skb);
15291da177e4SLinus Torvalds 		else
15301da177e4SLinus Torvalds 			goto out_kfree_skb;
15311da177e4SLinus Torvalds 	}
15321da177e4SLinus Torvalds out:
15331da177e4SLinus Torvalds 	return rc;
15341da177e4SLinus Torvalds out_kfree_skb:
15351da177e4SLinus Torvalds 	rc = -EINVAL;
15361da177e4SLinus Torvalds 	kfree_skb(skb);
15371da177e4SLinus Torvalds 	goto out;
15381da177e4SLinus Torvalds }
15390a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_resolve_output);
15401da177e4SLinus Torvalds 
15411da177e4SLinus Torvalds /* As fast as possible without hh cache */
15421da177e4SLinus Torvalds 
15438f40b161SDavid S. Miller int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
15441da177e4SLinus Torvalds {
15451da177e4SLinus Torvalds 	struct net_device *dev = neigh->dev;
15460ed8ddf4SEric Dumazet 	unsigned int seq;
15478f40b161SDavid S. Miller 	int err;
15481da177e4SLinus Torvalds 
15490ed8ddf4SEric Dumazet 	do {
1550e1f16503Sramesh.nagappa@gmail.com 		__skb_pull(skb, skb_network_offset(skb));
15510ed8ddf4SEric Dumazet 		seq = read_seqbegin(&neigh->ha_lock);
15520c4e8581SStephen Hemminger 		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
15531da177e4SLinus Torvalds 				      neigh->ha, NULL, skb->len);
15540ed8ddf4SEric Dumazet 	} while (read_seqretry(&neigh->ha_lock, seq));
15550ed8ddf4SEric Dumazet 
15561da177e4SLinus Torvalds 	if (err >= 0)
1557542d4d68SDavid S. Miller 		err = dev_queue_xmit(skb);
15581da177e4SLinus Torvalds 	else {
15591da177e4SLinus Torvalds 		err = -EINVAL;
15601da177e4SLinus Torvalds 		kfree_skb(skb);
15611da177e4SLinus Torvalds 	}
15621da177e4SLinus Torvalds 	return err;
15631da177e4SLinus Torvalds }
15640a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_connected_output);
15651da177e4SLinus Torvalds 
15668f40b161SDavid S. Miller int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
15678f40b161SDavid S. Miller {
15688f40b161SDavid S. Miller 	return dev_queue_xmit(skb);
15698f40b161SDavid S. Miller }
15708f40b161SDavid S. Miller EXPORT_SYMBOL(neigh_direct_output);
15718f40b161SDavid S. Miller 
15727482e384SDaniel Borkmann static void neigh_managed_work(struct work_struct *work)
15737482e384SDaniel Borkmann {
15747482e384SDaniel Borkmann 	struct neigh_table *tbl = container_of(work, struct neigh_table,
15757482e384SDaniel Borkmann 					       managed_work.work);
15767482e384SDaniel Borkmann 	struct neighbour *neigh;
15777482e384SDaniel Borkmann 
15787482e384SDaniel Borkmann 	write_lock_bh(&tbl->lock);
15797482e384SDaniel Borkmann 	list_for_each_entry(neigh, &tbl->managed_list, managed_list)
15804a81f6daSDaniel Borkmann 		neigh_event_send_probe(neigh, NULL, false);
15817482e384SDaniel Borkmann 	queue_delayed_work(system_power_efficient_wq, &tbl->managed_work,
1582ed6cd6a1SDaniel Borkmann 			   max(NEIGH_VAR(&tbl->parms, DELAY_PROBE_TIME), HZ));
15837482e384SDaniel Borkmann 	write_unlock_bh(&tbl->lock);
15847482e384SDaniel Borkmann }
15857482e384SDaniel Borkmann 
1586e99e88a9SKees Cook static void neigh_proxy_process(struct timer_list *t)
15871da177e4SLinus Torvalds {
1588e99e88a9SKees Cook 	struct neigh_table *tbl = from_timer(tbl, t, proxy_timer);
15891da177e4SLinus Torvalds 	long sched_next = 0;
15901da177e4SLinus Torvalds 	unsigned long now = jiffies;
1591f72051b0SDavid S. Miller 	struct sk_buff *skb, *n;
15921da177e4SLinus Torvalds 
15931da177e4SLinus Torvalds 	spin_lock(&tbl->proxy_queue.lock);
15941da177e4SLinus Torvalds 
1595f72051b0SDavid S. Miller 	skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1596f72051b0SDavid S. Miller 		long tdif = NEIGH_CB(skb)->sched_next - now;
15971da177e4SLinus Torvalds 
15981da177e4SLinus Torvalds 		if (tdif <= 0) {
1599f72051b0SDavid S. Miller 			struct net_device *dev = skb->dev;
160020e6074eSEric Dumazet 
1601f72051b0SDavid S. Miller 			__skb_unlink(skb, &tbl->proxy_queue);
160220e6074eSEric Dumazet 			if (tbl->proxy_redo && netif_running(dev)) {
160320e6074eSEric Dumazet 				rcu_read_lock();
1604f72051b0SDavid S. Miller 				tbl->proxy_redo(skb);
160520e6074eSEric Dumazet 				rcu_read_unlock();
160620e6074eSEric Dumazet 			} else {
1607f72051b0SDavid S. Miller 				kfree_skb(skb);
160820e6074eSEric Dumazet 			}
16091da177e4SLinus Torvalds 
16101da177e4SLinus Torvalds 			dev_put(dev);
16111da177e4SLinus Torvalds 		} else if (!sched_next || tdif < sched_next)
16121da177e4SLinus Torvalds 			sched_next = tdif;
16131da177e4SLinus Torvalds 	}
16141da177e4SLinus Torvalds 	del_timer(&tbl->proxy_timer);
16151da177e4SLinus Torvalds 	if (sched_next)
16161da177e4SLinus Torvalds 		mod_timer(&tbl->proxy_timer, jiffies + sched_next);
16171da177e4SLinus Torvalds 	spin_unlock(&tbl->proxy_queue.lock);
16181da177e4SLinus Torvalds }
16191da177e4SLinus Torvalds 
16201da177e4SLinus Torvalds void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
16211da177e4SLinus Torvalds 		    struct sk_buff *skb)
16221da177e4SLinus Torvalds {
1623a533b70aSweichenchen 	unsigned long sched_next = jiffies +
1624a533b70aSweichenchen 			prandom_u32_max(NEIGH_VAR(p, PROXY_DELAY));
16251da177e4SLinus Torvalds 
16261f9248e5SJiri Pirko 	if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) {
16271da177e4SLinus Torvalds 		kfree_skb(skb);
16281da177e4SLinus Torvalds 		return;
16291da177e4SLinus Torvalds 	}
1630a61bbcf2SPatrick McHardy 
1631a61bbcf2SPatrick McHardy 	NEIGH_CB(skb)->sched_next = sched_next;
1632a61bbcf2SPatrick McHardy 	NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
16331da177e4SLinus Torvalds 
16341da177e4SLinus Torvalds 	spin_lock(&tbl->proxy_queue.lock);
16351da177e4SLinus Torvalds 	if (del_timer(&tbl->proxy_timer)) {
16361da177e4SLinus Torvalds 		if (time_before(tbl->proxy_timer.expires, sched_next))
16371da177e4SLinus Torvalds 			sched_next = tbl->proxy_timer.expires;
16381da177e4SLinus Torvalds 	}
1639adf30907SEric Dumazet 	skb_dst_drop(skb);
16401da177e4SLinus Torvalds 	dev_hold(skb->dev);
16411da177e4SLinus Torvalds 	__skb_queue_tail(&tbl->proxy_queue, skb);
16421da177e4SLinus Torvalds 	mod_timer(&tbl->proxy_timer, sched_next);
16431da177e4SLinus Torvalds 	spin_unlock(&tbl->proxy_queue.lock);
16441da177e4SLinus Torvalds }
16450a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(pneigh_enqueue);
16461da177e4SLinus Torvalds 
164797fd5bc7STobias Klauser static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
1648426b5303SEric W. Biederman 						      struct net *net, int ifindex)
1649426b5303SEric W. Biederman {
1650426b5303SEric W. Biederman 	struct neigh_parms *p;
1651426b5303SEric W. Biederman 
165275fbfd33SNicolas Dichtel 	list_for_each_entry(p, &tbl->parms_list, list) {
1653878628fbSYOSHIFUJI Hideaki 		if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
1654170d6f99SGao feng 		    (!p->dev && !ifindex && net_eq(net, &init_net)))
1655426b5303SEric W. Biederman 			return p;
1656426b5303SEric W. Biederman 	}
1657426b5303SEric W. Biederman 
1658426b5303SEric W. Biederman 	return NULL;
1659426b5303SEric W. Biederman }
16601da177e4SLinus Torvalds 
16611da177e4SLinus Torvalds struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
16621da177e4SLinus Torvalds 				      struct neigh_table *tbl)
16631da177e4SLinus Torvalds {
1664cf89d6b2SGao feng 	struct neigh_parms *p;
166500829823SStephen Hemminger 	struct net *net = dev_net(dev);
166600829823SStephen Hemminger 	const struct net_device_ops *ops = dev->netdev_ops;
16671da177e4SLinus Torvalds 
1668cf89d6b2SGao feng 	p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL);
16691da177e4SLinus Torvalds 	if (p) {
16701da177e4SLinus Torvalds 		p->tbl		  = tbl;
16716343944bSReshetova, Elena 		refcount_set(&p->refcnt, 1);
16721da177e4SLinus Torvalds 		p->reachable_time =
16731f9248e5SJiri Pirko 				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
1674*d62607c3SJakub Kicinski 		netdev_hold(dev, &p->dev_tracker, GFP_KERNEL);
1675c7fb64dbSThomas Graf 		p->dev = dev;
1676efd7ef1cSEric W. Biederman 		write_pnet(&p->net, net);
16771da177e4SLinus Torvalds 		p->sysctl_table = NULL;
167863134803SVeaceslav Falico 
167963134803SVeaceslav Falico 		if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
1680*d62607c3SJakub Kicinski 			netdev_put(dev, &p->dev_tracker);
168163134803SVeaceslav Falico 			kfree(p);
168263134803SVeaceslav Falico 			return NULL;
168363134803SVeaceslav Falico 		}
168463134803SVeaceslav Falico 
16851da177e4SLinus Torvalds 		write_lock_bh(&tbl->lock);
168675fbfd33SNicolas Dichtel 		list_add(&p->list, &tbl->parms.list);
16871da177e4SLinus Torvalds 		write_unlock_bh(&tbl->lock);
16881d4c8c29SJiri Pirko 
16891d4c8c29SJiri Pirko 		neigh_parms_data_state_cleanall(p);
16901da177e4SLinus Torvalds 	}
16911da177e4SLinus Torvalds 	return p;
16921da177e4SLinus Torvalds }
16930a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_parms_alloc);
16941da177e4SLinus Torvalds 
16951da177e4SLinus Torvalds static void neigh_rcu_free_parms(struct rcu_head *head)
16961da177e4SLinus Torvalds {
16971da177e4SLinus Torvalds 	struct neigh_parms *parms =
16981da177e4SLinus Torvalds 		container_of(head, struct neigh_parms, rcu_head);
16991da177e4SLinus Torvalds 
17001da177e4SLinus Torvalds 	neigh_parms_put(parms);
17011da177e4SLinus Torvalds }
17021da177e4SLinus Torvalds 
17031da177e4SLinus Torvalds void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
17041da177e4SLinus Torvalds {
17051da177e4SLinus Torvalds 	if (!parms || parms == &tbl->parms)
17061da177e4SLinus Torvalds 		return;
17071da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
170875fbfd33SNicolas Dichtel 	list_del(&parms->list);
17091da177e4SLinus Torvalds 	parms->dead = 1;
17101da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
1711*d62607c3SJakub Kicinski 	netdev_put(parms->dev, &parms->dev_tracker);
17121da177e4SLinus Torvalds 	call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
17131da177e4SLinus Torvalds }
17140a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_parms_release);
17151da177e4SLinus Torvalds 
171606f0511dSDenis V. Lunev static void neigh_parms_destroy(struct neigh_parms *parms)
17171da177e4SLinus Torvalds {
17181da177e4SLinus Torvalds 	kfree(parms);
17191da177e4SLinus Torvalds }
17201da177e4SLinus Torvalds 
1721c2ecba71SPavel Emelianov static struct lock_class_key neigh_table_proxy_queue_class;
1722c2ecba71SPavel Emelianov 
1723d7480fd3SWANG Cong static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly;
1724d7480fd3SWANG Cong 
1725d7480fd3SWANG Cong void neigh_table_init(int index, struct neigh_table *tbl)
17261da177e4SLinus Torvalds {
17271da177e4SLinus Torvalds 	unsigned long now = jiffies;
17281da177e4SLinus Torvalds 	unsigned long phsize;
17291da177e4SLinus Torvalds 
173075fbfd33SNicolas Dichtel 	INIT_LIST_HEAD(&tbl->parms_list);
173158956317SDavid Ahern 	INIT_LIST_HEAD(&tbl->gc_list);
17327482e384SDaniel Borkmann 	INIT_LIST_HEAD(&tbl->managed_list);
17337482e384SDaniel Borkmann 
173475fbfd33SNicolas Dichtel 	list_add(&tbl->parms.list, &tbl->parms_list);
1735e42ea986SEric Dumazet 	write_pnet(&tbl->parms.net, &init_net);
17366343944bSReshetova, Elena 	refcount_set(&tbl->parms.refcnt, 1);
17371da177e4SLinus Torvalds 	tbl->parms.reachable_time =
17381f9248e5SJiri Pirko 			  neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME));
17391da177e4SLinus Torvalds 
17401da177e4SLinus Torvalds 	tbl->stats = alloc_percpu(struct neigh_statistics);
17411da177e4SLinus Torvalds 	if (!tbl->stats)
17421da177e4SLinus Torvalds 		panic("cannot create neighbour cache statistics");
17431da177e4SLinus Torvalds 
17441da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
174571a5053aSChristoph Hellwig 	if (!proc_create_seq_data(tbl->id, 0, init_net.proc_net_stat,
174671a5053aSChristoph Hellwig 			      &neigh_stat_seq_ops, tbl))
17471da177e4SLinus Torvalds 		panic("cannot create neighbour proc dir entry");
17481da177e4SLinus Torvalds #endif
17491da177e4SLinus Torvalds 
1750cd089336SDavid S. Miller 	RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
17511da177e4SLinus Torvalds 
17521da177e4SLinus Torvalds 	phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
175377d04bd9SAndrew Morton 	tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
17541da177e4SLinus Torvalds 
1755d6bf7817SEric Dumazet 	if (!tbl->nht || !tbl->phash_buckets)
17561da177e4SLinus Torvalds 		panic("cannot allocate neighbour cache hashes");
17571da177e4SLinus Torvalds 
175808433effSYOSHIFUJI Hideaki / 吉藤英明 	if (!tbl->entry_size)
175908433effSYOSHIFUJI Hideaki / 吉藤英明 		tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
176008433effSYOSHIFUJI Hideaki / 吉藤英明 					tbl->key_len, NEIGH_PRIV_ALIGN);
176108433effSYOSHIFUJI Hideaki / 吉藤英明 	else
176208433effSYOSHIFUJI Hideaki / 吉藤英明 		WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
176308433effSYOSHIFUJI Hideaki / 吉藤英明 
17641da177e4SLinus Torvalds 	rwlock_init(&tbl->lock);
17657482e384SDaniel Borkmann 
1766203b42f7STejun Heo 	INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
1767f618002bSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
1768f618002bSviresh kumar 			tbl->parms.reachable_time);
17697482e384SDaniel Borkmann 	INIT_DEFERRABLE_WORK(&tbl->managed_work, neigh_managed_work);
17707482e384SDaniel Borkmann 	queue_delayed_work(system_power_efficient_wq, &tbl->managed_work, 0);
17717482e384SDaniel Borkmann 
1772e99e88a9SKees Cook 	timer_setup(&tbl->proxy_timer, neigh_proxy_process, 0);
1773c2ecba71SPavel Emelianov 	skb_queue_head_init_class(&tbl->proxy_queue,
1774c2ecba71SPavel Emelianov 			&neigh_table_proxy_queue_class);
17751da177e4SLinus Torvalds 
17761da177e4SLinus Torvalds 	tbl->last_flush = now;
17771da177e4SLinus Torvalds 	tbl->last_rand	= now + tbl->parms.reachable_time * 20;
1778bd89efc5SSimon Kelley 
1779d7480fd3SWANG Cong 	neigh_tables[index] = tbl;
17801da177e4SLinus Torvalds }
17810a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_table_init);
17821da177e4SLinus Torvalds 
1783d7480fd3SWANG Cong int neigh_table_clear(int index, struct neigh_table *tbl)
17841da177e4SLinus Torvalds {
1785d7480fd3SWANG Cong 	neigh_tables[index] = NULL;
17861da177e4SLinus Torvalds 	/* It is not clean... Fix it to unload IPv6 module safely */
17874177d5b0SDaniel Borkmann 	cancel_delayed_work_sync(&tbl->managed_work);
1788a5c30b34STejun Heo 	cancel_delayed_work_sync(&tbl->gc_work);
17891da177e4SLinus Torvalds 	del_timer_sync(&tbl->proxy_timer);
17901da177e4SLinus Torvalds 	pneigh_queue_purge(&tbl->proxy_queue);
17911da177e4SLinus Torvalds 	neigh_ifdown(tbl, NULL);
17921da177e4SLinus Torvalds 	if (atomic_read(&tbl->entries))
1793e005d193SJoe Perches 		pr_crit("neighbour leakage\n");
17941da177e4SLinus Torvalds 
17956193d2beSEric Dumazet 	call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
17966193d2beSEric Dumazet 		 neigh_hash_free_rcu);
1797d6bf7817SEric Dumazet 	tbl->nht = NULL;
17981da177e4SLinus Torvalds 
17991da177e4SLinus Torvalds 	kfree(tbl->phash_buckets);
18001da177e4SLinus Torvalds 	tbl->phash_buckets = NULL;
18011da177e4SLinus Torvalds 
18023f192b5cSAlexey Dobriyan 	remove_proc_entry(tbl->id, init_net.proc_net_stat);
18033f192b5cSAlexey Dobriyan 
18043fcde74bSKirill Korotaev 	free_percpu(tbl->stats);
18053fcde74bSKirill Korotaev 	tbl->stats = NULL;
18063fcde74bSKirill Korotaev 
18071da177e4SLinus Torvalds 	return 0;
18081da177e4SLinus Torvalds }
18090a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_table_clear);
18101da177e4SLinus Torvalds 
1811d7480fd3SWANG Cong static struct neigh_table *neigh_find_table(int family)
1812d7480fd3SWANG Cong {
1813d7480fd3SWANG Cong 	struct neigh_table *tbl = NULL;
1814d7480fd3SWANG Cong 
1815d7480fd3SWANG Cong 	switch (family) {
1816d7480fd3SWANG Cong 	case AF_INET:
1817d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_ARP_TABLE];
1818d7480fd3SWANG Cong 		break;
1819d7480fd3SWANG Cong 	case AF_INET6:
1820d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_ND_TABLE];
1821d7480fd3SWANG Cong 		break;
1822d7480fd3SWANG Cong 	case AF_DECnet:
1823d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_DN_TABLE];
1824d7480fd3SWANG Cong 		break;
1825d7480fd3SWANG Cong 	}
1826d7480fd3SWANG Cong 
1827d7480fd3SWANG Cong 	return tbl;
1828d7480fd3SWANG Cong }
1829d7480fd3SWANG Cong 
183082cbb5c6SRoopa Prabhu const struct nla_policy nda_policy[NDA_MAX+1] = {
18311274e1ccSRoopa Prabhu 	[NDA_UNSPEC]		= { .strict_start_type = NDA_NH_ID },
183282cbb5c6SRoopa Prabhu 	[NDA_DST]		= { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
183382cbb5c6SRoopa Prabhu 	[NDA_LLADDR]		= { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
183482cbb5c6SRoopa Prabhu 	[NDA_CACHEINFO]		= { .len = sizeof(struct nda_cacheinfo) },
183582cbb5c6SRoopa Prabhu 	[NDA_PROBES]		= { .type = NLA_U32 },
183682cbb5c6SRoopa Prabhu 	[NDA_VLAN]		= { .type = NLA_U16 },
183782cbb5c6SRoopa Prabhu 	[NDA_PORT]		= { .type = NLA_U16 },
183882cbb5c6SRoopa Prabhu 	[NDA_VNI]		= { .type = NLA_U32 },
183982cbb5c6SRoopa Prabhu 	[NDA_IFINDEX]		= { .type = NLA_U32 },
184082cbb5c6SRoopa Prabhu 	[NDA_MASTER]		= { .type = NLA_U32 },
1841a9cd3439SDavid Ahern 	[NDA_PROTOCOL]		= { .type = NLA_U8 },
18421274e1ccSRoopa Prabhu 	[NDA_NH_ID]		= { .type = NLA_U32 },
1843c8e80c11SDaniel Borkmann 	[NDA_FLAGS_EXT]		= NLA_POLICY_MASK(NLA_U32, NTF_EXT_MASK),
1844899426b3SNikolay Aleksandrov 	[NDA_FDB_EXT_ATTRS]	= { .type = NLA_NESTED },
184582cbb5c6SRoopa Prabhu };
184682cbb5c6SRoopa Prabhu 
1847c21ef3e3SDavid Ahern static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
1848c21ef3e3SDavid Ahern 			struct netlink_ext_ack *extack)
18491da177e4SLinus Torvalds {
18503b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
1851a14a49d2SThomas Graf 	struct ndmsg *ndm;
1852a14a49d2SThomas Graf 	struct nlattr *dst_attr;
18531da177e4SLinus Torvalds 	struct neigh_table *tbl;
1854d7480fd3SWANG Cong 	struct neighbour *neigh;
18551da177e4SLinus Torvalds 	struct net_device *dev = NULL;
1856a14a49d2SThomas Graf 	int err = -EINVAL;
18571da177e4SLinus Torvalds 
1858110b2499SEric Dumazet 	ASSERT_RTNL();
1859a14a49d2SThomas Graf 	if (nlmsg_len(nlh) < sizeof(*ndm))
18601da177e4SLinus Torvalds 		goto out;
18611da177e4SLinus Torvalds 
1862a14a49d2SThomas Graf 	dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
18637a35a50dSDavid Ahern 	if (!dst_attr) {
18647a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Network address not specified");
1865a14a49d2SThomas Graf 		goto out;
18667a35a50dSDavid Ahern 	}
1867a14a49d2SThomas Graf 
1868a14a49d2SThomas Graf 	ndm = nlmsg_data(nlh);
1869a14a49d2SThomas Graf 	if (ndm->ndm_ifindex) {
1870110b2499SEric Dumazet 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
1871a14a49d2SThomas Graf 		if (dev == NULL) {
1872a14a49d2SThomas Graf 			err = -ENODEV;
1873a14a49d2SThomas Graf 			goto out;
1874a14a49d2SThomas Graf 		}
1875a14a49d2SThomas Graf 	}
1876a14a49d2SThomas Graf 
1877d7480fd3SWANG Cong 	tbl = neigh_find_table(ndm->ndm_family);
1878d7480fd3SWANG Cong 	if (tbl == NULL)
1879d7480fd3SWANG Cong 		return -EAFNOSUPPORT;
18801da177e4SLinus Torvalds 
18817a35a50dSDavid Ahern 	if (nla_len(dst_attr) < (int)tbl->key_len) {
18827a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid network address");
1883110b2499SEric Dumazet 		goto out;
18847a35a50dSDavid Ahern 	}
18851da177e4SLinus Torvalds 
18861da177e4SLinus Torvalds 	if (ndm->ndm_flags & NTF_PROXY) {
1887426b5303SEric W. Biederman 		err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
1888110b2499SEric Dumazet 		goto out;
18891da177e4SLinus Torvalds 	}
18901da177e4SLinus Torvalds 
1891a14a49d2SThomas Graf 	if (dev == NULL)
1892110b2499SEric Dumazet 		goto out;
18931da177e4SLinus Torvalds 
1894a14a49d2SThomas Graf 	neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1895a14a49d2SThomas Graf 	if (neigh == NULL) {
1896a14a49d2SThomas Graf 		err = -ENOENT;
1897110b2499SEric Dumazet 		goto out;
1898a14a49d2SThomas Graf 	}
1899a14a49d2SThomas Graf 
19007a35a50dSDavid Ahern 	err = __neigh_update(neigh, NULL, NUD_FAILED,
19017a35a50dSDavid Ahern 			     NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN,
19027a35a50dSDavid Ahern 			     NETLINK_CB(skb).portid, extack);
19035071034eSSowmini Varadhan 	write_lock_bh(&tbl->lock);
1904a14a49d2SThomas Graf 	neigh_release(neigh);
19055071034eSSowmini Varadhan 	neigh_remove_one(neigh, tbl);
19065071034eSSowmini Varadhan 	write_unlock_bh(&tbl->lock);
1907a14a49d2SThomas Graf 
19081da177e4SLinus Torvalds out:
19091da177e4SLinus Torvalds 	return err;
19101da177e4SLinus Torvalds }
19111da177e4SLinus Torvalds 
1912c21ef3e3SDavid Ahern static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
1913c21ef3e3SDavid Ahern 		     struct netlink_ext_ack *extack)
19141da177e4SLinus Torvalds {
1915f7aa74e4SRoopa Prabhu 	int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE |
1916f7aa74e4SRoopa Prabhu 		    NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
19173b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
19185208debdSThomas Graf 	struct ndmsg *ndm;
19195208debdSThomas Graf 	struct nlattr *tb[NDA_MAX+1];
19201da177e4SLinus Torvalds 	struct neigh_table *tbl;
19211da177e4SLinus Torvalds 	struct net_device *dev = NULL;
1922d7480fd3SWANG Cong 	struct neighbour *neigh;
1923d7480fd3SWANG Cong 	void *dst, *lladdr;
1924df9b0e30SDavid Ahern 	u8 protocol = 0;
19252c611ad9SRoopa Prabhu 	u32 ndm_flags;
19265208debdSThomas Graf 	int err;
19271da177e4SLinus Torvalds 
1928110b2499SEric Dumazet 	ASSERT_RTNL();
19298cb08174SJohannes Berg 	err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX,
19308cb08174SJohannes Berg 				     nda_policy, extack);
19315208debdSThomas Graf 	if (err < 0)
19321da177e4SLinus Torvalds 		goto out;
19331da177e4SLinus Torvalds 
19345208debdSThomas Graf 	err = -EINVAL;
19357a35a50dSDavid Ahern 	if (!tb[NDA_DST]) {
19367a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Network address not specified");
19375208debdSThomas Graf 		goto out;
19387a35a50dSDavid Ahern 	}
19395208debdSThomas Graf 
19405208debdSThomas Graf 	ndm = nlmsg_data(nlh);
19412c611ad9SRoopa Prabhu 	ndm_flags = ndm->ndm_flags;
19422c611ad9SRoopa Prabhu 	if (tb[NDA_FLAGS_EXT]) {
19432c611ad9SRoopa Prabhu 		u32 ext = nla_get_u32(tb[NDA_FLAGS_EXT]);
19442c611ad9SRoopa Prabhu 
1945507c2f1dSDaniel Borkmann 		BUILD_BUG_ON(sizeof(neigh->flags) * BITS_PER_BYTE <
1946507c2f1dSDaniel Borkmann 			     (sizeof(ndm->ndm_flags) * BITS_PER_BYTE +
1947507c2f1dSDaniel Borkmann 			      hweight32(NTF_EXT_MASK)));
19482c611ad9SRoopa Prabhu 		ndm_flags |= (ext << NTF_EXT_SHIFT);
19492c611ad9SRoopa Prabhu 	}
19505208debdSThomas Graf 	if (ndm->ndm_ifindex) {
1951110b2499SEric Dumazet 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
19525208debdSThomas Graf 		if (dev == NULL) {
19535208debdSThomas Graf 			err = -ENODEV;
19545208debdSThomas Graf 			goto out;
19555208debdSThomas Graf 		}
19565208debdSThomas Graf 
19577a35a50dSDavid Ahern 		if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) {
19587a35a50dSDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid link address");
1959110b2499SEric Dumazet 			goto out;
19605208debdSThomas Graf 		}
19617a35a50dSDavid Ahern 	}
19625208debdSThomas Graf 
1963d7480fd3SWANG Cong 	tbl = neigh_find_table(ndm->ndm_family);
1964d7480fd3SWANG Cong 	if (tbl == NULL)
1965d7480fd3SWANG Cong 		return -EAFNOSUPPORT;
19661da177e4SLinus Torvalds 
19677a35a50dSDavid Ahern 	if (nla_len(tb[NDA_DST]) < (int)tbl->key_len) {
19687a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid network address");
1969110b2499SEric Dumazet 		goto out;
19707a35a50dSDavid Ahern 	}
19717a35a50dSDavid Ahern 
19725208debdSThomas Graf 	dst = nla_data(tb[NDA_DST]);
19735208debdSThomas Graf 	lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
19741da177e4SLinus Torvalds 
1975a9cd3439SDavid Ahern 	if (tb[NDA_PROTOCOL])
1976df9b0e30SDavid Ahern 		protocol = nla_get_u8(tb[NDA_PROTOCOL]);
19772c611ad9SRoopa Prabhu 	if (ndm_flags & NTF_PROXY) {
197862dd9318SVille Nuorvala 		struct pneigh_entry *pn;
197962dd9318SVille Nuorvala 
19807482e384SDaniel Borkmann 		if (ndm_flags & NTF_MANAGED) {
19817482e384SDaniel Borkmann 			NL_SET_ERR_MSG(extack, "Invalid NTF_* flag combination");
19827482e384SDaniel Borkmann 			goto out;
19837482e384SDaniel Borkmann 		}
19847482e384SDaniel Borkmann 
19855208debdSThomas Graf 		err = -ENOBUFS;
1986426b5303SEric W. Biederman 		pn = pneigh_lookup(tbl, net, dst, dev, 1);
198762dd9318SVille Nuorvala 		if (pn) {
19882c611ad9SRoopa Prabhu 			pn->flags = ndm_flags;
1989df9b0e30SDavid Ahern 			if (protocol)
1990df9b0e30SDavid Ahern 				pn->protocol = protocol;
199162dd9318SVille Nuorvala 			err = 0;
199262dd9318SVille Nuorvala 		}
1993110b2499SEric Dumazet 		goto out;
19941da177e4SLinus Torvalds 	}
19951da177e4SLinus Torvalds 
19967a35a50dSDavid Ahern 	if (!dev) {
19977a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Device not specified");
1998110b2499SEric Dumazet 		goto out;
19997a35a50dSDavid Ahern 	}
20001da177e4SLinus Torvalds 
2001b8fb1ab4SDavid Ahern 	if (tbl->allow_add && !tbl->allow_add(dev, extack)) {
2002b8fb1ab4SDavid Ahern 		err = -EINVAL;
2003b8fb1ab4SDavid Ahern 		goto out;
2004b8fb1ab4SDavid Ahern 	}
2005b8fb1ab4SDavid Ahern 
20065208debdSThomas Graf 	neigh = neigh_lookup(tbl, dst, dev);
20075208debdSThomas Graf 	if (neigh == NULL) {
200830fc7efaSDaniel Borkmann 		bool ndm_permanent  = ndm->ndm_state & NUD_PERMANENT;
200930fc7efaSDaniel Borkmann 		bool exempt_from_gc = ndm_permanent ||
201030fc7efaSDaniel Borkmann 				      ndm_flags & NTF_EXT_LEARNED;
2011e997f8a2SDavid Ahern 
20125208debdSThomas Graf 		if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
20131da177e4SLinus Torvalds 			err = -ENOENT;
2014110b2499SEric Dumazet 			goto out;
20155208debdSThomas Graf 		}
201630fc7efaSDaniel Borkmann 		if (ndm_permanent && (ndm_flags & NTF_MANAGED)) {
201730fc7efaSDaniel Borkmann 			NL_SET_ERR_MSG(extack, "Invalid NTF_* flag for permanent entry");
201830fc7efaSDaniel Borkmann 			err = -EINVAL;
201930fc7efaSDaniel Borkmann 			goto out;
202030fc7efaSDaniel Borkmann 		}
20215208debdSThomas Graf 
2022e4400bbfSDaniel Borkmann 		neigh = ___neigh_create(tbl, dst, dev,
20237482e384SDaniel Borkmann 					ndm_flags &
20247482e384SDaniel Borkmann 					(NTF_EXT_LEARNED | NTF_MANAGED),
2025e4400bbfSDaniel Borkmann 					exempt_from_gc, true);
20265208debdSThomas Graf 		if (IS_ERR(neigh)) {
20275208debdSThomas Graf 			err = PTR_ERR(neigh);
2028110b2499SEric Dumazet 			goto out;
20291da177e4SLinus Torvalds 		}
20305208debdSThomas Graf 	} else {
20315208debdSThomas Graf 		if (nlh->nlmsg_flags & NLM_F_EXCL) {
20325208debdSThomas Graf 			err = -EEXIST;
20335208debdSThomas Graf 			neigh_release(neigh);
2034110b2499SEric Dumazet 			goto out;
20351da177e4SLinus Torvalds 		}
20361da177e4SLinus Torvalds 
20375208debdSThomas Graf 		if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
2038f7aa74e4SRoopa Prabhu 			flags &= ~(NEIGH_UPDATE_F_OVERRIDE |
2039f7aa74e4SRoopa Prabhu 				   NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
20405208debdSThomas Graf 	}
20411da177e4SLinus Torvalds 
204238212bb3SRoman Mashak 	if (protocol)
204338212bb3SRoman Mashak 		neigh->protocol = protocol;
20442c611ad9SRoopa Prabhu 	if (ndm_flags & NTF_EXT_LEARNED)
20459ce33e46SRoopa Prabhu 		flags |= NEIGH_UPDATE_F_EXT_LEARNED;
20462c611ad9SRoopa Prabhu 	if (ndm_flags & NTF_ROUTER)
2047f7aa74e4SRoopa Prabhu 		flags |= NEIGH_UPDATE_F_ISROUTER;
20487482e384SDaniel Borkmann 	if (ndm_flags & NTF_MANAGED)
20497482e384SDaniel Borkmann 		flags |= NEIGH_UPDATE_F_MANAGED;
20502c611ad9SRoopa Prabhu 	if (ndm_flags & NTF_USE)
20513dc20f47SDaniel Borkmann 		flags |= NEIGH_UPDATE_F_USE;
2052f7aa74e4SRoopa Prabhu 
20537a35a50dSDavid Ahern 	err = __neigh_update(neigh, lladdr, ndm->ndm_state, flags,
20547a35a50dSDavid Ahern 			     NETLINK_CB(skb).portid, extack);
20557482e384SDaniel Borkmann 	if (!err && ndm_flags & (NTF_USE | NTF_MANAGED)) {
20563dc20f47SDaniel Borkmann 		neigh_event_send(neigh, NULL);
20573dc20f47SDaniel Borkmann 		err = 0;
20583dc20f47SDaniel Borkmann 	}
20595208debdSThomas Graf 	neigh_release(neigh);
20601da177e4SLinus Torvalds out:
20611da177e4SLinus Torvalds 	return err;
20621da177e4SLinus Torvalds }
20631da177e4SLinus Torvalds 
2064c7fb64dbSThomas Graf static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
2065c7fb64dbSThomas Graf {
2066ca860fb3SThomas Graf 	struct nlattr *nest;
2067e386c6ebSThomas Graf 
2068ae0be8deSMichal Kubecek 	nest = nla_nest_start_noflag(skb, NDTA_PARMS);
2069ca860fb3SThomas Graf 	if (nest == NULL)
2070ca860fb3SThomas Graf 		return -ENOBUFS;
2071c7fb64dbSThomas Graf 
20729a6308d7SDavid S. Miller 	if ((parms->dev &&
20739a6308d7SDavid S. Miller 	     nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
20746343944bSReshetova, Elena 	    nla_put_u32(skb, NDTPA_REFCNT, refcount_read(&parms->refcnt)) ||
20751f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_QUEUE_LENBYTES,
20761f9248e5SJiri Pirko 			NEIGH_VAR(parms, QUEUE_LEN_BYTES)) ||
20778b5c171bSEric Dumazet 	    /* approximative value for deprecated QUEUE_LEN (in packets) */
20789a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTPA_QUEUE_LEN,
20791f9248e5SJiri Pirko 			NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) ||
20801f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) ||
20811f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) ||
20821f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_UCAST_PROBES,
20831f9248e5SJiri Pirko 			NEIGH_VAR(parms, UCAST_PROBES)) ||
20841f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_MCAST_PROBES,
20851f9248e5SJiri Pirko 			NEIGH_VAR(parms, MCAST_PROBES)) ||
20868da86466SYOSHIFUJI Hideaki/吉藤英明 	    nla_put_u32(skb, NDTPA_MCAST_REPROBES,
20878da86466SYOSHIFUJI Hideaki/吉藤英明 			NEIGH_VAR(parms, MCAST_REPROBES)) ||
20882175d87cSNicolas Dichtel 	    nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time,
20892175d87cSNicolas Dichtel 			  NDTPA_PAD) ||
20909a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
20912175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, BASE_REACHABLE_TIME), NDTPA_PAD) ||
20921f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_GC_STALETIME,
20932175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, GC_STALETIME), NDTPA_PAD) ||
20949a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
20952175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, DELAY_PROBE_TIME), NDTPA_PAD) ||
20961f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_RETRANS_TIME,
20972175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, RETRANS_TIME), NDTPA_PAD) ||
20981f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_ANYCAST_DELAY,
20992175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, ANYCAST_DELAY), NDTPA_PAD) ||
21001f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_PROXY_DELAY,
21012175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, PROXY_DELAY), NDTPA_PAD) ||
21021f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_LOCKTIME,
21032175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, LOCKTIME), NDTPA_PAD))
21049a6308d7SDavid S. Miller 		goto nla_put_failure;
2105ca860fb3SThomas Graf 	return nla_nest_end(skb, nest);
2106c7fb64dbSThomas Graf 
2107ca860fb3SThomas Graf nla_put_failure:
2108bc3ed28cSThomas Graf 	nla_nest_cancel(skb, nest);
2109bc3ed28cSThomas Graf 	return -EMSGSIZE;
2110c7fb64dbSThomas Graf }
2111c7fb64dbSThomas Graf 
2112ca860fb3SThomas Graf static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
2113ca860fb3SThomas Graf 			      u32 pid, u32 seq, int type, int flags)
2114c7fb64dbSThomas Graf {
2115c7fb64dbSThomas Graf 	struct nlmsghdr *nlh;
2116c7fb64dbSThomas Graf 	struct ndtmsg *ndtmsg;
2117c7fb64dbSThomas Graf 
2118ca860fb3SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2119ca860fb3SThomas Graf 	if (nlh == NULL)
212026932566SPatrick McHardy 		return -EMSGSIZE;
2121c7fb64dbSThomas Graf 
2122ca860fb3SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2123c7fb64dbSThomas Graf 
2124c7fb64dbSThomas Graf 	read_lock_bh(&tbl->lock);
2125c7fb64dbSThomas Graf 	ndtmsg->ndtm_family = tbl->family;
21269ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad1   = 0;
21279ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad2   = 0;
2128c7fb64dbSThomas Graf 
21299a6308d7SDavid S. Miller 	if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
21302175d87cSNicolas Dichtel 	    nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval, NDTA_PAD) ||
21319a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
21329a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
21339a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
21349a6308d7SDavid S. Miller 		goto nla_put_failure;
2135c7fb64dbSThomas Graf 	{
2136c7fb64dbSThomas Graf 		unsigned long now = jiffies;
21379d027e3aSEric Dumazet 		long flush_delta = now - tbl->last_flush;
21389d027e3aSEric Dumazet 		long rand_delta = now - tbl->last_rand;
2139d6bf7817SEric Dumazet 		struct neigh_hash_table *nht;
2140c7fb64dbSThomas Graf 		struct ndt_config ndc = {
2141c7fb64dbSThomas Graf 			.ndtc_key_len		= tbl->key_len,
2142c7fb64dbSThomas Graf 			.ndtc_entry_size	= tbl->entry_size,
2143c7fb64dbSThomas Graf 			.ndtc_entries		= atomic_read(&tbl->entries),
2144c7fb64dbSThomas Graf 			.ndtc_last_flush	= jiffies_to_msecs(flush_delta),
2145c7fb64dbSThomas Graf 			.ndtc_last_rand		= jiffies_to_msecs(rand_delta),
2146c7fb64dbSThomas Graf 			.ndtc_proxy_qlen	= tbl->proxy_queue.qlen,
2147c7fb64dbSThomas Graf 		};
2148c7fb64dbSThomas Graf 
2149d6bf7817SEric Dumazet 		rcu_read_lock_bh();
2150d6bf7817SEric Dumazet 		nht = rcu_dereference_bh(tbl->nht);
21512c2aba6cSDavid S. Miller 		ndc.ndtc_hash_rnd = nht->hash_rnd[0];
2152cd089336SDavid S. Miller 		ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
2153d6bf7817SEric Dumazet 		rcu_read_unlock_bh();
2154d6bf7817SEric Dumazet 
21559a6308d7SDavid S. Miller 		if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
21569a6308d7SDavid S. Miller 			goto nla_put_failure;
2157c7fb64dbSThomas Graf 	}
2158c7fb64dbSThomas Graf 
2159c7fb64dbSThomas Graf 	{
2160c7fb64dbSThomas Graf 		int cpu;
2161c7fb64dbSThomas Graf 		struct ndt_stats ndst;
2162c7fb64dbSThomas Graf 
2163c7fb64dbSThomas Graf 		memset(&ndst, 0, sizeof(ndst));
2164c7fb64dbSThomas Graf 
21656f912042SKAMEZAWA Hiroyuki 		for_each_possible_cpu(cpu) {
2166c7fb64dbSThomas Graf 			struct neigh_statistics	*st;
2167c7fb64dbSThomas Graf 
2168c7fb64dbSThomas Graf 			st = per_cpu_ptr(tbl->stats, cpu);
2169c7fb64dbSThomas Graf 			ndst.ndts_allocs		+= st->allocs;
2170c7fb64dbSThomas Graf 			ndst.ndts_destroys		+= st->destroys;
2171c7fb64dbSThomas Graf 			ndst.ndts_hash_grows		+= st->hash_grows;
2172c7fb64dbSThomas Graf 			ndst.ndts_res_failed		+= st->res_failed;
2173c7fb64dbSThomas Graf 			ndst.ndts_lookups		+= st->lookups;
2174c7fb64dbSThomas Graf 			ndst.ndts_hits			+= st->hits;
2175c7fb64dbSThomas Graf 			ndst.ndts_rcv_probes_mcast	+= st->rcv_probes_mcast;
2176c7fb64dbSThomas Graf 			ndst.ndts_rcv_probes_ucast	+= st->rcv_probes_ucast;
2177c7fb64dbSThomas Graf 			ndst.ndts_periodic_gc_runs	+= st->periodic_gc_runs;
2178c7fb64dbSThomas Graf 			ndst.ndts_forced_gc_runs	+= st->forced_gc_runs;
2179fb811395SRick Jones 			ndst.ndts_table_fulls		+= st->table_fulls;
2180c7fb64dbSThomas Graf 		}
2181c7fb64dbSThomas Graf 
2182b676338fSNicolas Dichtel 		if (nla_put_64bit(skb, NDTA_STATS, sizeof(ndst), &ndst,
2183b676338fSNicolas Dichtel 				  NDTA_PAD))
21849a6308d7SDavid S. Miller 			goto nla_put_failure;
2185c7fb64dbSThomas Graf 	}
2186c7fb64dbSThomas Graf 
2187c7fb64dbSThomas Graf 	BUG_ON(tbl->parms.dev);
2188c7fb64dbSThomas Graf 	if (neightbl_fill_parms(skb, &tbl->parms) < 0)
2189ca860fb3SThomas Graf 		goto nla_put_failure;
2190c7fb64dbSThomas Graf 
2191c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
2192053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2193053c095aSJohannes Berg 	return 0;
2194c7fb64dbSThomas Graf 
2195ca860fb3SThomas Graf nla_put_failure:
2196c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
219726932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
219826932566SPatrick McHardy 	return -EMSGSIZE;
2199c7fb64dbSThomas Graf }
2200c7fb64dbSThomas Graf 
2201ca860fb3SThomas Graf static int neightbl_fill_param_info(struct sk_buff *skb,
2202ca860fb3SThomas Graf 				    struct neigh_table *tbl,
2203c7fb64dbSThomas Graf 				    struct neigh_parms *parms,
2204ca860fb3SThomas Graf 				    u32 pid, u32 seq, int type,
2205ca860fb3SThomas Graf 				    unsigned int flags)
2206c7fb64dbSThomas Graf {
2207c7fb64dbSThomas Graf 	struct ndtmsg *ndtmsg;
2208c7fb64dbSThomas Graf 	struct nlmsghdr *nlh;
2209c7fb64dbSThomas Graf 
2210ca860fb3SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2211ca860fb3SThomas Graf 	if (nlh == NULL)
221226932566SPatrick McHardy 		return -EMSGSIZE;
2213c7fb64dbSThomas Graf 
2214ca860fb3SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2215c7fb64dbSThomas Graf 
2216c7fb64dbSThomas Graf 	read_lock_bh(&tbl->lock);
2217c7fb64dbSThomas Graf 	ndtmsg->ndtm_family = tbl->family;
22189ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad1   = 0;
22199ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad2   = 0;
2220c7fb64dbSThomas Graf 
2221ca860fb3SThomas Graf 	if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
2222ca860fb3SThomas Graf 	    neightbl_fill_parms(skb, parms) < 0)
2223ca860fb3SThomas Graf 		goto errout;
2224c7fb64dbSThomas Graf 
2225c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
2226053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2227053c095aSJohannes Berg 	return 0;
2228ca860fb3SThomas Graf errout:
2229c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
223026932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
223126932566SPatrick McHardy 	return -EMSGSIZE;
2232c7fb64dbSThomas Graf }
2233c7fb64dbSThomas Graf 
2234ef7c79edSPatrick McHardy static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
22356b3f8674SThomas Graf 	[NDTA_NAME]		= { .type = NLA_STRING },
22366b3f8674SThomas Graf 	[NDTA_THRESH1]		= { .type = NLA_U32 },
22376b3f8674SThomas Graf 	[NDTA_THRESH2]		= { .type = NLA_U32 },
22386b3f8674SThomas Graf 	[NDTA_THRESH3]		= { .type = NLA_U32 },
22396b3f8674SThomas Graf 	[NDTA_GC_INTERVAL]	= { .type = NLA_U64 },
22406b3f8674SThomas Graf 	[NDTA_PARMS]		= { .type = NLA_NESTED },
22416b3f8674SThomas Graf };
22426b3f8674SThomas Graf 
2243ef7c79edSPatrick McHardy static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
22446b3f8674SThomas Graf 	[NDTPA_IFINDEX]			= { .type = NLA_U32 },
22456b3f8674SThomas Graf 	[NDTPA_QUEUE_LEN]		= { .type = NLA_U32 },
22466b3f8674SThomas Graf 	[NDTPA_PROXY_QLEN]		= { .type = NLA_U32 },
22476b3f8674SThomas Graf 	[NDTPA_APP_PROBES]		= { .type = NLA_U32 },
22486b3f8674SThomas Graf 	[NDTPA_UCAST_PROBES]		= { .type = NLA_U32 },
22496b3f8674SThomas Graf 	[NDTPA_MCAST_PROBES]		= { .type = NLA_U32 },
22508da86466SYOSHIFUJI Hideaki/吉藤英明 	[NDTPA_MCAST_REPROBES]		= { .type = NLA_U32 },
22516b3f8674SThomas Graf 	[NDTPA_BASE_REACHABLE_TIME]	= { .type = NLA_U64 },
22526b3f8674SThomas Graf 	[NDTPA_GC_STALETIME]		= { .type = NLA_U64 },
22536b3f8674SThomas Graf 	[NDTPA_DELAY_PROBE_TIME]	= { .type = NLA_U64 },
22546b3f8674SThomas Graf 	[NDTPA_RETRANS_TIME]		= { .type = NLA_U64 },
22556b3f8674SThomas Graf 	[NDTPA_ANYCAST_DELAY]		= { .type = NLA_U64 },
22566b3f8674SThomas Graf 	[NDTPA_PROXY_DELAY]		= { .type = NLA_U64 },
22576b3f8674SThomas Graf 	[NDTPA_LOCKTIME]		= { .type = NLA_U64 },
22586b3f8674SThomas Graf };
22596b3f8674SThomas Graf 
2260c21ef3e3SDavid Ahern static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
2261c21ef3e3SDavid Ahern 			struct netlink_ext_ack *extack)
2262c7fb64dbSThomas Graf {
22633b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
2264c7fb64dbSThomas Graf 	struct neigh_table *tbl;
22656b3f8674SThomas Graf 	struct ndtmsg *ndtmsg;
22666b3f8674SThomas Graf 	struct nlattr *tb[NDTA_MAX+1];
2267d7480fd3SWANG Cong 	bool found = false;
2268d7480fd3SWANG Cong 	int err, tidx;
2269c7fb64dbSThomas Graf 
22708cb08174SJohannes Berg 	err = nlmsg_parse_deprecated(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
2271c21ef3e3SDavid Ahern 				     nl_neightbl_policy, extack);
22726b3f8674SThomas Graf 	if (err < 0)
22736b3f8674SThomas Graf 		goto errout;
2274c7fb64dbSThomas Graf 
22756b3f8674SThomas Graf 	if (tb[NDTA_NAME] == NULL) {
22766b3f8674SThomas Graf 		err = -EINVAL;
22776b3f8674SThomas Graf 		goto errout;
22786b3f8674SThomas Graf 	}
22796b3f8674SThomas Graf 
22806b3f8674SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2281d7480fd3SWANG Cong 
2282d7480fd3SWANG Cong 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2283d7480fd3SWANG Cong 		tbl = neigh_tables[tidx];
2284d7480fd3SWANG Cong 		if (!tbl)
2285d7480fd3SWANG Cong 			continue;
2286c7fb64dbSThomas Graf 		if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
2287c7fb64dbSThomas Graf 			continue;
2288d7480fd3SWANG Cong 		if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) {
2289d7480fd3SWANG Cong 			found = true;
2290c7fb64dbSThomas Graf 			break;
2291c7fb64dbSThomas Graf 		}
2292c7fb64dbSThomas Graf 	}
2293c7fb64dbSThomas Graf 
2294d7480fd3SWANG Cong 	if (!found)
2295d7480fd3SWANG Cong 		return -ENOENT;
2296d7480fd3SWANG Cong 
2297c7fb64dbSThomas Graf 	/*
2298c7fb64dbSThomas Graf 	 * We acquire tbl->lock to be nice to the periodic timers and
2299c7fb64dbSThomas Graf 	 * make sure they always see a consistent set of values.
2300c7fb64dbSThomas Graf 	 */
2301c7fb64dbSThomas Graf 	write_lock_bh(&tbl->lock);
2302c7fb64dbSThomas Graf 
23036b3f8674SThomas Graf 	if (tb[NDTA_PARMS]) {
23046b3f8674SThomas Graf 		struct nlattr *tbp[NDTPA_MAX+1];
2305c7fb64dbSThomas Graf 		struct neigh_parms *p;
23066b3f8674SThomas Graf 		int i, ifindex = 0;
2307c7fb64dbSThomas Graf 
23088cb08174SJohannes Berg 		err = nla_parse_nested_deprecated(tbp, NDTPA_MAX,
23098cb08174SJohannes Berg 						  tb[NDTA_PARMS],
2310c21ef3e3SDavid Ahern 						  nl_ntbl_parm_policy, extack);
23116b3f8674SThomas Graf 		if (err < 0)
23126b3f8674SThomas Graf 			goto errout_tbl_lock;
2313c7fb64dbSThomas Graf 
23146b3f8674SThomas Graf 		if (tbp[NDTPA_IFINDEX])
23156b3f8674SThomas Graf 			ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
2316c7fb64dbSThomas Graf 
231797fd5bc7STobias Klauser 		p = lookup_neigh_parms(tbl, net, ifindex);
2318c7fb64dbSThomas Graf 		if (p == NULL) {
2319c7fb64dbSThomas Graf 			err = -ENOENT;
23206b3f8674SThomas Graf 			goto errout_tbl_lock;
2321c7fb64dbSThomas Graf 		}
2322c7fb64dbSThomas Graf 
23236b3f8674SThomas Graf 		for (i = 1; i <= NDTPA_MAX; i++) {
23246b3f8674SThomas Graf 			if (tbp[i] == NULL)
23256b3f8674SThomas Graf 				continue;
2326c7fb64dbSThomas Graf 
23276b3f8674SThomas Graf 			switch (i) {
23286b3f8674SThomas Graf 			case NDTPA_QUEUE_LEN:
23291f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
23301f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]) *
23311f9248e5SJiri Pirko 					      SKB_TRUESIZE(ETH_FRAME_LEN));
23328b5c171bSEric Dumazet 				break;
23338b5c171bSEric Dumazet 			case NDTPA_QUEUE_LENBYTES:
23341f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
23351f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23366b3f8674SThomas Graf 				break;
23376b3f8674SThomas Graf 			case NDTPA_PROXY_QLEN:
23381f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, PROXY_QLEN,
23391f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23406b3f8674SThomas Graf 				break;
23416b3f8674SThomas Graf 			case NDTPA_APP_PROBES:
23421f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, APP_PROBES,
23431f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23446b3f8674SThomas Graf 				break;
23456b3f8674SThomas Graf 			case NDTPA_UCAST_PROBES:
23461f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, UCAST_PROBES,
23471f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23486b3f8674SThomas Graf 				break;
23496b3f8674SThomas Graf 			case NDTPA_MCAST_PROBES:
23501f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, MCAST_PROBES,
23511f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
23526b3f8674SThomas Graf 				break;
23538da86466SYOSHIFUJI Hideaki/吉藤英明 			case NDTPA_MCAST_REPROBES:
23548da86466SYOSHIFUJI Hideaki/吉藤英明 				NEIGH_VAR_SET(p, MCAST_REPROBES,
23558da86466SYOSHIFUJI Hideaki/吉藤英明 					      nla_get_u32(tbp[i]));
23568da86466SYOSHIFUJI Hideaki/吉藤英明 				break;
23576b3f8674SThomas Graf 			case NDTPA_BASE_REACHABLE_TIME:
23581f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,
23591f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
23604bf6980dSJean-Francois Remy 				/* update reachable_time as well, otherwise, the change will
23614bf6980dSJean-Francois Remy 				 * only be effective after the next time neigh_periodic_work
23624bf6980dSJean-Francois Remy 				 * decides to recompute it (can be multiple minutes)
23634bf6980dSJean-Francois Remy 				 */
23644bf6980dSJean-Francois Remy 				p->reachable_time =
23654bf6980dSJean-Francois Remy 					neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
23666b3f8674SThomas Graf 				break;
23676b3f8674SThomas Graf 			case NDTPA_GC_STALETIME:
23681f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, GC_STALETIME,
23691f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
23706b3f8674SThomas Graf 				break;
23716b3f8674SThomas Graf 			case NDTPA_DELAY_PROBE_TIME:
23721f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, DELAY_PROBE_TIME,
23731f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
23742a4501aeSIdo Schimmel 				call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
23756b3f8674SThomas Graf 				break;
23766b3f8674SThomas Graf 			case NDTPA_RETRANS_TIME:
23771f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, RETRANS_TIME,
23781f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
23796b3f8674SThomas Graf 				break;
23806b3f8674SThomas Graf 			case NDTPA_ANYCAST_DELAY:
23813977458cSJiri Pirko 				NEIGH_VAR_SET(p, ANYCAST_DELAY,
23823977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
23836b3f8674SThomas Graf 				break;
23846b3f8674SThomas Graf 			case NDTPA_PROXY_DELAY:
23853977458cSJiri Pirko 				NEIGH_VAR_SET(p, PROXY_DELAY,
23863977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
23876b3f8674SThomas Graf 				break;
23886b3f8674SThomas Graf 			case NDTPA_LOCKTIME:
23893977458cSJiri Pirko 				NEIGH_VAR_SET(p, LOCKTIME,
23903977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
23916b3f8674SThomas Graf 				break;
2392c7fb64dbSThomas Graf 			}
23936b3f8674SThomas Graf 		}
23946b3f8674SThomas Graf 	}
23956b3f8674SThomas Graf 
2396dc25c676SGao feng 	err = -ENOENT;
2397dc25c676SGao feng 	if ((tb[NDTA_THRESH1] || tb[NDTA_THRESH2] ||
2398dc25c676SGao feng 	     tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]) &&
2399dc25c676SGao feng 	    !net_eq(net, &init_net))
2400dc25c676SGao feng 		goto errout_tbl_lock;
2401dc25c676SGao feng 
24026b3f8674SThomas Graf 	if (tb[NDTA_THRESH1])
24036b3f8674SThomas Graf 		tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
24046b3f8674SThomas Graf 
24056b3f8674SThomas Graf 	if (tb[NDTA_THRESH2])
24066b3f8674SThomas Graf 		tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
24076b3f8674SThomas Graf 
24086b3f8674SThomas Graf 	if (tb[NDTA_THRESH3])
24096b3f8674SThomas Graf 		tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
24106b3f8674SThomas Graf 
24116b3f8674SThomas Graf 	if (tb[NDTA_GC_INTERVAL])
24126b3f8674SThomas Graf 		tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2413c7fb64dbSThomas Graf 
2414c7fb64dbSThomas Graf 	err = 0;
2415c7fb64dbSThomas Graf 
24166b3f8674SThomas Graf errout_tbl_lock:
2417c7fb64dbSThomas Graf 	write_unlock_bh(&tbl->lock);
24186b3f8674SThomas Graf errout:
2419c7fb64dbSThomas Graf 	return err;
2420c7fb64dbSThomas Graf }
2421c7fb64dbSThomas Graf 
24229632d47fSDavid Ahern static int neightbl_valid_dump_info(const struct nlmsghdr *nlh,
24239632d47fSDavid Ahern 				    struct netlink_ext_ack *extack)
24249632d47fSDavid Ahern {
24259632d47fSDavid Ahern 	struct ndtmsg *ndtm;
24269632d47fSDavid Ahern 
24279632d47fSDavid Ahern 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndtm))) {
24289632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid header for neighbor table dump request");
24299632d47fSDavid Ahern 		return -EINVAL;
24309632d47fSDavid Ahern 	}
24319632d47fSDavid Ahern 
24329632d47fSDavid Ahern 	ndtm = nlmsg_data(nlh);
24339632d47fSDavid Ahern 	if (ndtm->ndtm_pad1  || ndtm->ndtm_pad2) {
24349632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor table dump request");
24359632d47fSDavid Ahern 		return -EINVAL;
24369632d47fSDavid Ahern 	}
24379632d47fSDavid Ahern 
24389632d47fSDavid Ahern 	if (nlmsg_attrlen(nlh, sizeof(*ndtm))) {
24399632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid data after header in neighbor table dump request");
24409632d47fSDavid Ahern 		return -EINVAL;
24419632d47fSDavid Ahern 	}
24429632d47fSDavid Ahern 
24439632d47fSDavid Ahern 	return 0;
24449632d47fSDavid Ahern }
24459632d47fSDavid Ahern 
2446c8822a4eSThomas Graf static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
2447c7fb64dbSThomas Graf {
24489632d47fSDavid Ahern 	const struct nlmsghdr *nlh = cb->nlh;
24493b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
2450ca860fb3SThomas Graf 	int family, tidx, nidx = 0;
2451ca860fb3SThomas Graf 	int tbl_skip = cb->args[0];
2452ca860fb3SThomas Graf 	int neigh_skip = cb->args[1];
2453c7fb64dbSThomas Graf 	struct neigh_table *tbl;
2454c7fb64dbSThomas Graf 
24559632d47fSDavid Ahern 	if (cb->strict_check) {
24569632d47fSDavid Ahern 		int err = neightbl_valid_dump_info(nlh, cb->extack);
24579632d47fSDavid Ahern 
24589632d47fSDavid Ahern 		if (err < 0)
24599632d47fSDavid Ahern 			return err;
24609632d47fSDavid Ahern 	}
24619632d47fSDavid Ahern 
24629632d47fSDavid Ahern 	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
2463c7fb64dbSThomas Graf 
2464d7480fd3SWANG Cong 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2465c7fb64dbSThomas Graf 		struct neigh_parms *p;
2466c7fb64dbSThomas Graf 
2467d7480fd3SWANG Cong 		tbl = neigh_tables[tidx];
2468d7480fd3SWANG Cong 		if (!tbl)
2469d7480fd3SWANG Cong 			continue;
2470d7480fd3SWANG Cong 
2471ca860fb3SThomas Graf 		if (tidx < tbl_skip || (family && tbl->family != family))
2472c7fb64dbSThomas Graf 			continue;
2473c7fb64dbSThomas Graf 
247415e47304SEric W. Biederman 		if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
24759632d47fSDavid Ahern 				       nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
24767b46a644SDavid S. Miller 				       NLM_F_MULTI) < 0)
2477c7fb64dbSThomas Graf 			break;
2478c7fb64dbSThomas Graf 
247975fbfd33SNicolas Dichtel 		nidx = 0;
248075fbfd33SNicolas Dichtel 		p = list_next_entry(&tbl->parms, list);
248175fbfd33SNicolas Dichtel 		list_for_each_entry_from(p, &tbl->parms_list, list) {
2482878628fbSYOSHIFUJI Hideaki 			if (!net_eq(neigh_parms_net(p), net))
2483426b5303SEric W. Biederman 				continue;
2484426b5303SEric W. Biederman 
2485efc683fcSGautam Kachroo 			if (nidx < neigh_skip)
2486efc683fcSGautam Kachroo 				goto next;
2487c7fb64dbSThomas Graf 
2488ca860fb3SThomas Graf 			if (neightbl_fill_param_info(skb, tbl, p,
248915e47304SEric W. Biederman 						     NETLINK_CB(cb->skb).portid,
24909632d47fSDavid Ahern 						     nlh->nlmsg_seq,
2491ca860fb3SThomas Graf 						     RTM_NEWNEIGHTBL,
24927b46a644SDavid S. Miller 						     NLM_F_MULTI) < 0)
2493c7fb64dbSThomas Graf 				goto out;
2494efc683fcSGautam Kachroo 		next:
2495efc683fcSGautam Kachroo 			nidx++;
2496c7fb64dbSThomas Graf 		}
2497c7fb64dbSThomas Graf 
2498ca860fb3SThomas Graf 		neigh_skip = 0;
2499c7fb64dbSThomas Graf 	}
2500c7fb64dbSThomas Graf out:
2501ca860fb3SThomas Graf 	cb->args[0] = tidx;
2502ca860fb3SThomas Graf 	cb->args[1] = nidx;
2503c7fb64dbSThomas Graf 
2504c7fb64dbSThomas Graf 	return skb->len;
2505c7fb64dbSThomas Graf }
25061da177e4SLinus Torvalds 
25078b8aec50SThomas Graf static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
25088b8aec50SThomas Graf 			   u32 pid, u32 seq, int type, unsigned int flags)
25091da177e4SLinus Torvalds {
25102c611ad9SRoopa Prabhu 	u32 neigh_flags, neigh_flags_ext;
25111da177e4SLinus Torvalds 	unsigned long now = jiffies;
25121da177e4SLinus Torvalds 	struct nda_cacheinfo ci;
25138b8aec50SThomas Graf 	struct nlmsghdr *nlh;
25148b8aec50SThomas Graf 	struct ndmsg *ndm;
25151da177e4SLinus Torvalds 
25168b8aec50SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
25178b8aec50SThomas Graf 	if (nlh == NULL)
251826932566SPatrick McHardy 		return -EMSGSIZE;
25198b8aec50SThomas Graf 
25202c611ad9SRoopa Prabhu 	neigh_flags_ext = neigh->flags >> NTF_EXT_SHIFT;
25212c611ad9SRoopa Prabhu 	neigh_flags     = neigh->flags & NTF_OLD_MASK;
25222c611ad9SRoopa Prabhu 
25238b8aec50SThomas Graf 	ndm = nlmsg_data(nlh);
25248b8aec50SThomas Graf 	ndm->ndm_family	 = neigh->ops->family;
25259ef1d4c7SPatrick McHardy 	ndm->ndm_pad1    = 0;
25269ef1d4c7SPatrick McHardy 	ndm->ndm_pad2    = 0;
25272c611ad9SRoopa Prabhu 	ndm->ndm_flags	 = neigh_flags;
25288b8aec50SThomas Graf 	ndm->ndm_type	 = neigh->type;
25298b8aec50SThomas Graf 	ndm->ndm_ifindex = neigh->dev->ifindex;
25301da177e4SLinus Torvalds 
25319a6308d7SDavid S. Miller 	if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
25329a6308d7SDavid S. Miller 		goto nla_put_failure;
25338b8aec50SThomas Graf 
25348b8aec50SThomas Graf 	read_lock_bh(&neigh->lock);
25358b8aec50SThomas Graf 	ndm->ndm_state	 = neigh->nud_state;
25360ed8ddf4SEric Dumazet 	if (neigh->nud_state & NUD_VALID) {
25370ed8ddf4SEric Dumazet 		char haddr[MAX_ADDR_LEN];
25380ed8ddf4SEric Dumazet 
25390ed8ddf4SEric Dumazet 		neigh_ha_snapshot(haddr, neigh, neigh->dev);
25400ed8ddf4SEric Dumazet 		if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
25418b8aec50SThomas Graf 			read_unlock_bh(&neigh->lock);
25428b8aec50SThomas Graf 			goto nla_put_failure;
25438b8aec50SThomas Graf 		}
25440ed8ddf4SEric Dumazet 	}
25458b8aec50SThomas Graf 
2546b9f5f52cSStephen Hemminger 	ci.ndm_used	 = jiffies_to_clock_t(now - neigh->used);
2547b9f5f52cSStephen Hemminger 	ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2548b9f5f52cSStephen Hemminger 	ci.ndm_updated	 = jiffies_to_clock_t(now - neigh->updated);
25499f237430SReshetova, Elena 	ci.ndm_refcnt	 = refcount_read(&neigh->refcnt) - 1;
25508b8aec50SThomas Graf 	read_unlock_bh(&neigh->lock);
25518b8aec50SThomas Graf 
25529a6308d7SDavid S. Miller 	if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
25539a6308d7SDavid S. Miller 	    nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
25549a6308d7SDavid S. Miller 		goto nla_put_failure;
25558b8aec50SThomas Graf 
2556df9b0e30SDavid Ahern 	if (neigh->protocol && nla_put_u8(skb, NDA_PROTOCOL, neigh->protocol))
2557df9b0e30SDavid Ahern 		goto nla_put_failure;
25582c611ad9SRoopa Prabhu 	if (neigh_flags_ext && nla_put_u32(skb, NDA_FLAGS_EXT, neigh_flags_ext))
25592c611ad9SRoopa Prabhu 		goto nla_put_failure;
2560df9b0e30SDavid Ahern 
2561053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2562053c095aSJohannes Berg 	return 0;
25638b8aec50SThomas Graf 
25648b8aec50SThomas Graf nla_put_failure:
256526932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
256626932566SPatrick McHardy 	return -EMSGSIZE;
25671da177e4SLinus Torvalds }
25681da177e4SLinus Torvalds 
256984920c14STony Zelenoff static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
257084920c14STony Zelenoff 			    u32 pid, u32 seq, int type, unsigned int flags,
257184920c14STony Zelenoff 			    struct neigh_table *tbl)
257284920c14STony Zelenoff {
25732c611ad9SRoopa Prabhu 	u32 neigh_flags, neigh_flags_ext;
257484920c14STony Zelenoff 	struct nlmsghdr *nlh;
257584920c14STony Zelenoff 	struct ndmsg *ndm;
257684920c14STony Zelenoff 
257784920c14STony Zelenoff 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
257884920c14STony Zelenoff 	if (nlh == NULL)
257984920c14STony Zelenoff 		return -EMSGSIZE;
258084920c14STony Zelenoff 
25812c611ad9SRoopa Prabhu 	neigh_flags_ext = pn->flags >> NTF_EXT_SHIFT;
25822c611ad9SRoopa Prabhu 	neigh_flags     = pn->flags & NTF_OLD_MASK;
25832c611ad9SRoopa Prabhu 
258484920c14STony Zelenoff 	ndm = nlmsg_data(nlh);
258584920c14STony Zelenoff 	ndm->ndm_family	 = tbl->family;
258684920c14STony Zelenoff 	ndm->ndm_pad1    = 0;
258784920c14STony Zelenoff 	ndm->ndm_pad2    = 0;
25882c611ad9SRoopa Prabhu 	ndm->ndm_flags	 = neigh_flags | NTF_PROXY;
2589545469f7SJun Zhao 	ndm->ndm_type	 = RTN_UNICAST;
25906adc5fd6SKonstantin Khlebnikov 	ndm->ndm_ifindex = pn->dev ? pn->dev->ifindex : 0;
259184920c14STony Zelenoff 	ndm->ndm_state	 = NUD_NONE;
259284920c14STony Zelenoff 
25939a6308d7SDavid S. Miller 	if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
25949a6308d7SDavid S. Miller 		goto nla_put_failure;
259584920c14STony Zelenoff 
2596df9b0e30SDavid Ahern 	if (pn->protocol && nla_put_u8(skb, NDA_PROTOCOL, pn->protocol))
2597df9b0e30SDavid Ahern 		goto nla_put_failure;
25982c611ad9SRoopa Prabhu 	if (neigh_flags_ext && nla_put_u32(skb, NDA_FLAGS_EXT, neigh_flags_ext))
25992c611ad9SRoopa Prabhu 		goto nla_put_failure;
2600df9b0e30SDavid Ahern 
2601053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2602053c095aSJohannes Berg 	return 0;
260384920c14STony Zelenoff 
260484920c14STony Zelenoff nla_put_failure:
260584920c14STony Zelenoff 	nlmsg_cancel(skb, nlh);
260684920c14STony Zelenoff 	return -EMSGSIZE;
260784920c14STony Zelenoff }
260884920c14STony Zelenoff 
26097b8f7a40SRoopa Prabhu static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid)
2610d961db35SThomas Graf {
2611d961db35SThomas Graf 	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
26127b8f7a40SRoopa Prabhu 	__neigh_notify(neigh, RTM_NEWNEIGH, 0, nlmsg_pid);
2613d961db35SThomas Graf }
26141da177e4SLinus Torvalds 
261521fdd092SDavid Ahern static bool neigh_master_filtered(struct net_device *dev, int master_idx)
261621fdd092SDavid Ahern {
261721fdd092SDavid Ahern 	struct net_device *master;
261821fdd092SDavid Ahern 
261921fdd092SDavid Ahern 	if (!master_idx)
262021fdd092SDavid Ahern 		return false;
262121fdd092SDavid Ahern 
2622aab456dfSEric Dumazet 	master = dev ? netdev_master_upper_dev_get(dev) : NULL;
2623d3432bf1SLahav Schlesinger 
2624d3432bf1SLahav Schlesinger 	/* 0 is already used to denote NDA_MASTER wasn't passed, therefore need another
2625d3432bf1SLahav Schlesinger 	 * invalid value for ifindex to denote "no master".
2626d3432bf1SLahav Schlesinger 	 */
2627d3432bf1SLahav Schlesinger 	if (master_idx == -1)
2628d3432bf1SLahav Schlesinger 		return !!master;
2629d3432bf1SLahav Schlesinger 
263021fdd092SDavid Ahern 	if (!master || master->ifindex != master_idx)
263121fdd092SDavid Ahern 		return true;
263221fdd092SDavid Ahern 
263321fdd092SDavid Ahern 	return false;
263421fdd092SDavid Ahern }
263521fdd092SDavid Ahern 
263616660f0bSDavid Ahern static bool neigh_ifindex_filtered(struct net_device *dev, int filter_idx)
263716660f0bSDavid Ahern {
2638aab456dfSEric Dumazet 	if (filter_idx && (!dev || dev->ifindex != filter_idx))
263916660f0bSDavid Ahern 		return true;
264016660f0bSDavid Ahern 
264116660f0bSDavid Ahern 	return false;
264216660f0bSDavid Ahern }
264316660f0bSDavid Ahern 
26446f52f80eSDavid Ahern struct neigh_dump_filter {
26456f52f80eSDavid Ahern 	int master_idx;
26466f52f80eSDavid Ahern 	int dev_idx;
26476f52f80eSDavid Ahern };
26486f52f80eSDavid Ahern 
26491da177e4SLinus Torvalds static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
26506f52f80eSDavid Ahern 			    struct netlink_callback *cb,
26516f52f80eSDavid Ahern 			    struct neigh_dump_filter *filter)
26521da177e4SLinus Torvalds {
26533b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
26541da177e4SLinus Torvalds 	struct neighbour *n;
26551da177e4SLinus Torvalds 	int rc, h, s_h = cb->args[1];
26561da177e4SLinus Torvalds 	int idx, s_idx = idx = cb->args[2];
2657d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
265821fdd092SDavid Ahern 	unsigned int flags = NLM_F_MULTI;
265921fdd092SDavid Ahern 
26606f52f80eSDavid Ahern 	if (filter->dev_idx || filter->master_idx)
266121fdd092SDavid Ahern 		flags |= NLM_F_DUMP_FILTERED;
26621da177e4SLinus Torvalds 
2663d6bf7817SEric Dumazet 	rcu_read_lock_bh();
2664d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
2665d6bf7817SEric Dumazet 
26664bd6683bSEric Dumazet 	for (h = s_h; h < (1 << nht->hash_shift); h++) {
26671da177e4SLinus Torvalds 		if (h > s_h)
26681da177e4SLinus Torvalds 			s_idx = 0;
2669767e97e1SEric Dumazet 		for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2670767e97e1SEric Dumazet 		     n != NULL;
2671767e97e1SEric Dumazet 		     n = rcu_dereference_bh(n->next)) {
267218502acdSZhang Shengju 			if (idx < s_idx || !net_eq(dev_net(n->dev), net))
267318502acdSZhang Shengju 				goto next;
26746f52f80eSDavid Ahern 			if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
26756f52f80eSDavid Ahern 			    neigh_master_filtered(n->dev, filter->master_idx))
2676efc683fcSGautam Kachroo 				goto next;
267715e47304SEric W. Biederman 			if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
26781da177e4SLinus Torvalds 					    cb->nlh->nlmsg_seq,
2679b6544c0bSJamal Hadi Salim 					    RTM_NEWNEIGH,
268021fdd092SDavid Ahern 					    flags) < 0) {
26811da177e4SLinus Torvalds 				rc = -1;
26821da177e4SLinus Torvalds 				goto out;
26831da177e4SLinus Torvalds 			}
2684efc683fcSGautam Kachroo next:
2685efc683fcSGautam Kachroo 			idx++;
26861da177e4SLinus Torvalds 		}
26871da177e4SLinus Torvalds 	}
26881da177e4SLinus Torvalds 	rc = skb->len;
26891da177e4SLinus Torvalds out:
2690d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
26911da177e4SLinus Torvalds 	cb->args[1] = h;
26921da177e4SLinus Torvalds 	cb->args[2] = idx;
26931da177e4SLinus Torvalds 	return rc;
26941da177e4SLinus Torvalds }
26951da177e4SLinus Torvalds 
269684920c14STony Zelenoff static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
26976f52f80eSDavid Ahern 			     struct netlink_callback *cb,
26986f52f80eSDavid Ahern 			     struct neigh_dump_filter *filter)
269984920c14STony Zelenoff {
270084920c14STony Zelenoff 	struct pneigh_entry *n;
270184920c14STony Zelenoff 	struct net *net = sock_net(skb->sk);
270284920c14STony Zelenoff 	int rc, h, s_h = cb->args[3];
270384920c14STony Zelenoff 	int idx, s_idx = idx = cb->args[4];
27046f52f80eSDavid Ahern 	unsigned int flags = NLM_F_MULTI;
27056f52f80eSDavid Ahern 
27066f52f80eSDavid Ahern 	if (filter->dev_idx || filter->master_idx)
27076f52f80eSDavid Ahern 		flags |= NLM_F_DUMP_FILTERED;
270884920c14STony Zelenoff 
270984920c14STony Zelenoff 	read_lock_bh(&tbl->lock);
271084920c14STony Zelenoff 
27114bd6683bSEric Dumazet 	for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
271284920c14STony Zelenoff 		if (h > s_h)
271384920c14STony Zelenoff 			s_idx = 0;
271484920c14STony Zelenoff 		for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
271518502acdSZhang Shengju 			if (idx < s_idx || pneigh_net(n) != net)
271684920c14STony Zelenoff 				goto next;
27176f52f80eSDavid Ahern 			if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
27186f52f80eSDavid Ahern 			    neigh_master_filtered(n->dev, filter->master_idx))
27196f52f80eSDavid Ahern 				goto next;
272015e47304SEric W. Biederman 			if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
272184920c14STony Zelenoff 					    cb->nlh->nlmsg_seq,
27226f52f80eSDavid Ahern 					    RTM_NEWNEIGH, flags, tbl) < 0) {
272384920c14STony Zelenoff 				read_unlock_bh(&tbl->lock);
272484920c14STony Zelenoff 				rc = -1;
272584920c14STony Zelenoff 				goto out;
272684920c14STony Zelenoff 			}
272784920c14STony Zelenoff 		next:
272884920c14STony Zelenoff 			idx++;
272984920c14STony Zelenoff 		}
273084920c14STony Zelenoff 	}
273184920c14STony Zelenoff 
273284920c14STony Zelenoff 	read_unlock_bh(&tbl->lock);
273384920c14STony Zelenoff 	rc = skb->len;
273484920c14STony Zelenoff out:
273584920c14STony Zelenoff 	cb->args[3] = h;
273684920c14STony Zelenoff 	cb->args[4] = idx;
273784920c14STony Zelenoff 	return rc;
273884920c14STony Zelenoff 
273984920c14STony Zelenoff }
274084920c14STony Zelenoff 
274151183d23SDavid Ahern static int neigh_valid_dump_req(const struct nlmsghdr *nlh,
274251183d23SDavid Ahern 				bool strict_check,
274351183d23SDavid Ahern 				struct neigh_dump_filter *filter,
274451183d23SDavid Ahern 				struct netlink_ext_ack *extack)
274551183d23SDavid Ahern {
274651183d23SDavid Ahern 	struct nlattr *tb[NDA_MAX + 1];
274751183d23SDavid Ahern 	int err, i;
274851183d23SDavid Ahern 
274951183d23SDavid Ahern 	if (strict_check) {
275051183d23SDavid Ahern 		struct ndmsg *ndm;
275151183d23SDavid Ahern 
275251183d23SDavid Ahern 		if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
275351183d23SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid header for neighbor dump request");
275451183d23SDavid Ahern 			return -EINVAL;
275551183d23SDavid Ahern 		}
275651183d23SDavid Ahern 
275751183d23SDavid Ahern 		ndm = nlmsg_data(nlh);
275851183d23SDavid Ahern 		if (ndm->ndm_pad1  || ndm->ndm_pad2  || ndm->ndm_ifindex ||
2759c0fde870SDavid Ahern 		    ndm->ndm_state || ndm->ndm_type) {
276051183d23SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor dump request");
276151183d23SDavid Ahern 			return -EINVAL;
276251183d23SDavid Ahern 		}
276351183d23SDavid Ahern 
2764c0fde870SDavid Ahern 		if (ndm->ndm_flags & ~NTF_PROXY) {
2765c0fde870SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor dump request");
2766c0fde870SDavid Ahern 			return -EINVAL;
2767c0fde870SDavid Ahern 		}
2768c0fde870SDavid Ahern 
27698cb08174SJohannes Berg 		err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg),
27708cb08174SJohannes Berg 						    tb, NDA_MAX, nda_policy,
27718cb08174SJohannes Berg 						    extack);
277251183d23SDavid Ahern 	} else {
27738cb08174SJohannes Berg 		err = nlmsg_parse_deprecated(nlh, sizeof(struct ndmsg), tb,
27748cb08174SJohannes Berg 					     NDA_MAX, nda_policy, extack);
277551183d23SDavid Ahern 	}
277651183d23SDavid Ahern 	if (err < 0)
277751183d23SDavid Ahern 		return err;
277851183d23SDavid Ahern 
277951183d23SDavid Ahern 	for (i = 0; i <= NDA_MAX; ++i) {
278051183d23SDavid Ahern 		if (!tb[i])
278151183d23SDavid Ahern 			continue;
278251183d23SDavid Ahern 
278351183d23SDavid Ahern 		/* all new attributes should require strict_check */
278451183d23SDavid Ahern 		switch (i) {
278551183d23SDavid Ahern 		case NDA_IFINDEX:
278651183d23SDavid Ahern 			filter->dev_idx = nla_get_u32(tb[i]);
278751183d23SDavid Ahern 			break;
278851183d23SDavid Ahern 		case NDA_MASTER:
278951183d23SDavid Ahern 			filter->master_idx = nla_get_u32(tb[i]);
279051183d23SDavid Ahern 			break;
279151183d23SDavid Ahern 		default:
279251183d23SDavid Ahern 			if (strict_check) {
279351183d23SDavid Ahern 				NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor dump request");
279451183d23SDavid Ahern 				return -EINVAL;
279551183d23SDavid Ahern 			}
279651183d23SDavid Ahern 		}
279751183d23SDavid Ahern 	}
279851183d23SDavid Ahern 
279951183d23SDavid Ahern 	return 0;
280051183d23SDavid Ahern }
280151183d23SDavid Ahern 
2802c8822a4eSThomas Graf static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
28031da177e4SLinus Torvalds {
28046f52f80eSDavid Ahern 	const struct nlmsghdr *nlh = cb->nlh;
28056f52f80eSDavid Ahern 	struct neigh_dump_filter filter = {};
28061da177e4SLinus Torvalds 	struct neigh_table *tbl;
28071da177e4SLinus Torvalds 	int t, family, s_t;
280884920c14STony Zelenoff 	int proxy = 0;
28094bd6683bSEric Dumazet 	int err;
28101da177e4SLinus Torvalds 
28116f52f80eSDavid Ahern 	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
281284920c14STony Zelenoff 
281384920c14STony Zelenoff 	/* check for full ndmsg structure presence, family member is
281484920c14STony Zelenoff 	 * the same for both structures
281584920c14STony Zelenoff 	 */
28166f52f80eSDavid Ahern 	if (nlmsg_len(nlh) >= sizeof(struct ndmsg) &&
28176f52f80eSDavid Ahern 	    ((struct ndmsg *)nlmsg_data(nlh))->ndm_flags == NTF_PROXY)
281884920c14STony Zelenoff 		proxy = 1;
281984920c14STony Zelenoff 
282051183d23SDavid Ahern 	err = neigh_valid_dump_req(nlh, cb->strict_check, &filter, cb->extack);
282151183d23SDavid Ahern 	if (err < 0 && cb->strict_check)
282251183d23SDavid Ahern 		return err;
282351183d23SDavid Ahern 
28241da177e4SLinus Torvalds 	s_t = cb->args[0];
28251da177e4SLinus Torvalds 
2826d7480fd3SWANG Cong 	for (t = 0; t < NEIGH_NR_TABLES; t++) {
2827d7480fd3SWANG Cong 		tbl = neigh_tables[t];
2828d7480fd3SWANG Cong 
2829d7480fd3SWANG Cong 		if (!tbl)
2830d7480fd3SWANG Cong 			continue;
28311da177e4SLinus Torvalds 		if (t < s_t || (family && tbl->family != family))
28321da177e4SLinus Torvalds 			continue;
28331da177e4SLinus Torvalds 		if (t > s_t)
28341da177e4SLinus Torvalds 			memset(&cb->args[1], 0, sizeof(cb->args) -
28351da177e4SLinus Torvalds 						sizeof(cb->args[0]));
283684920c14STony Zelenoff 		if (proxy)
28376f52f80eSDavid Ahern 			err = pneigh_dump_table(tbl, skb, cb, &filter);
283884920c14STony Zelenoff 		else
28396f52f80eSDavid Ahern 			err = neigh_dump_table(tbl, skb, cb, &filter);
28404bd6683bSEric Dumazet 		if (err < 0)
28414bd6683bSEric Dumazet 			break;
28421da177e4SLinus Torvalds 	}
28431da177e4SLinus Torvalds 
28441da177e4SLinus Torvalds 	cb->args[0] = t;
28451da177e4SLinus Torvalds 	return skb->len;
28461da177e4SLinus Torvalds }
28471da177e4SLinus Torvalds 
284882cbb5c6SRoopa Prabhu static int neigh_valid_get_req(const struct nlmsghdr *nlh,
284982cbb5c6SRoopa Prabhu 			       struct neigh_table **tbl,
285082cbb5c6SRoopa Prabhu 			       void **dst, int *dev_idx, u8 *ndm_flags,
285182cbb5c6SRoopa Prabhu 			       struct netlink_ext_ack *extack)
285282cbb5c6SRoopa Prabhu {
285382cbb5c6SRoopa Prabhu 	struct nlattr *tb[NDA_MAX + 1];
285482cbb5c6SRoopa Prabhu 	struct ndmsg *ndm;
285582cbb5c6SRoopa Prabhu 	int err, i;
285682cbb5c6SRoopa Prabhu 
285782cbb5c6SRoopa Prabhu 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
285882cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid header for neighbor get request");
285982cbb5c6SRoopa Prabhu 		return -EINVAL;
286082cbb5c6SRoopa Prabhu 	}
286182cbb5c6SRoopa Prabhu 
286282cbb5c6SRoopa Prabhu 	ndm = nlmsg_data(nlh);
286382cbb5c6SRoopa Prabhu 	if (ndm->ndm_pad1  || ndm->ndm_pad2  || ndm->ndm_state ||
286482cbb5c6SRoopa Prabhu 	    ndm->ndm_type) {
286582cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor get request");
286682cbb5c6SRoopa Prabhu 		return -EINVAL;
286782cbb5c6SRoopa Prabhu 	}
286882cbb5c6SRoopa Prabhu 
286982cbb5c6SRoopa Prabhu 	if (ndm->ndm_flags & ~NTF_PROXY) {
287082cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor get request");
287182cbb5c6SRoopa Prabhu 		return -EINVAL;
287282cbb5c6SRoopa Prabhu 	}
287382cbb5c6SRoopa Prabhu 
28748cb08174SJohannes Berg 	err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb,
28758cb08174SJohannes Berg 					    NDA_MAX, nda_policy, extack);
287682cbb5c6SRoopa Prabhu 	if (err < 0)
287782cbb5c6SRoopa Prabhu 		return err;
287882cbb5c6SRoopa Prabhu 
287982cbb5c6SRoopa Prabhu 	*ndm_flags = ndm->ndm_flags;
288082cbb5c6SRoopa Prabhu 	*dev_idx = ndm->ndm_ifindex;
288182cbb5c6SRoopa Prabhu 	*tbl = neigh_find_table(ndm->ndm_family);
288282cbb5c6SRoopa Prabhu 	if (*tbl == NULL) {
288382cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
288482cbb5c6SRoopa Prabhu 		return -EAFNOSUPPORT;
288582cbb5c6SRoopa Prabhu 	}
288682cbb5c6SRoopa Prabhu 
288782cbb5c6SRoopa Prabhu 	for (i = 0; i <= NDA_MAX; ++i) {
288882cbb5c6SRoopa Prabhu 		if (!tb[i])
288982cbb5c6SRoopa Prabhu 			continue;
289082cbb5c6SRoopa Prabhu 
289182cbb5c6SRoopa Prabhu 		switch (i) {
289282cbb5c6SRoopa Prabhu 		case NDA_DST:
289382cbb5c6SRoopa Prabhu 			if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
289482cbb5c6SRoopa Prabhu 				NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
289582cbb5c6SRoopa Prabhu 				return -EINVAL;
289682cbb5c6SRoopa Prabhu 			}
289782cbb5c6SRoopa Prabhu 			*dst = nla_data(tb[i]);
289882cbb5c6SRoopa Prabhu 			break;
289982cbb5c6SRoopa Prabhu 		default:
290082cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request");
290182cbb5c6SRoopa Prabhu 			return -EINVAL;
290282cbb5c6SRoopa Prabhu 		}
290382cbb5c6SRoopa Prabhu 	}
290482cbb5c6SRoopa Prabhu 
290582cbb5c6SRoopa Prabhu 	return 0;
290682cbb5c6SRoopa Prabhu }
290782cbb5c6SRoopa Prabhu 
290882cbb5c6SRoopa Prabhu static inline size_t neigh_nlmsg_size(void)
290982cbb5c6SRoopa Prabhu {
291082cbb5c6SRoopa Prabhu 	return NLMSG_ALIGN(sizeof(struct ndmsg))
291182cbb5c6SRoopa Prabhu 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
291282cbb5c6SRoopa Prabhu 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
291382cbb5c6SRoopa Prabhu 	       + nla_total_size(sizeof(struct nda_cacheinfo))
291482cbb5c6SRoopa Prabhu 	       + nla_total_size(4)  /* NDA_PROBES */
29152c611ad9SRoopa Prabhu 	       + nla_total_size(4)  /* NDA_FLAGS_EXT */
291682cbb5c6SRoopa Prabhu 	       + nla_total_size(1); /* NDA_PROTOCOL */
291782cbb5c6SRoopa Prabhu }
291882cbb5c6SRoopa Prabhu 
291982cbb5c6SRoopa Prabhu static int neigh_get_reply(struct net *net, struct neighbour *neigh,
292082cbb5c6SRoopa Prabhu 			   u32 pid, u32 seq)
292182cbb5c6SRoopa Prabhu {
292282cbb5c6SRoopa Prabhu 	struct sk_buff *skb;
292382cbb5c6SRoopa Prabhu 	int err = 0;
292482cbb5c6SRoopa Prabhu 
292582cbb5c6SRoopa Prabhu 	skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL);
292682cbb5c6SRoopa Prabhu 	if (!skb)
292782cbb5c6SRoopa Prabhu 		return -ENOBUFS;
292882cbb5c6SRoopa Prabhu 
292982cbb5c6SRoopa Prabhu 	err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0);
293082cbb5c6SRoopa Prabhu 	if (err) {
293182cbb5c6SRoopa Prabhu 		kfree_skb(skb);
293282cbb5c6SRoopa Prabhu 		goto errout;
293382cbb5c6SRoopa Prabhu 	}
293482cbb5c6SRoopa Prabhu 
293582cbb5c6SRoopa Prabhu 	err = rtnl_unicast(skb, net, pid);
293682cbb5c6SRoopa Prabhu errout:
293782cbb5c6SRoopa Prabhu 	return err;
293882cbb5c6SRoopa Prabhu }
293982cbb5c6SRoopa Prabhu 
294082cbb5c6SRoopa Prabhu static inline size_t pneigh_nlmsg_size(void)
294182cbb5c6SRoopa Prabhu {
294282cbb5c6SRoopa Prabhu 	return NLMSG_ALIGN(sizeof(struct ndmsg))
2943463561e6SColin Ian King 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
29442c611ad9SRoopa Prabhu 	       + nla_total_size(4)  /* NDA_FLAGS_EXT */
294582cbb5c6SRoopa Prabhu 	       + nla_total_size(1); /* NDA_PROTOCOL */
294682cbb5c6SRoopa Prabhu }
294782cbb5c6SRoopa Prabhu 
294882cbb5c6SRoopa Prabhu static int pneigh_get_reply(struct net *net, struct pneigh_entry *neigh,
294982cbb5c6SRoopa Prabhu 			    u32 pid, u32 seq, struct neigh_table *tbl)
295082cbb5c6SRoopa Prabhu {
295182cbb5c6SRoopa Prabhu 	struct sk_buff *skb;
295282cbb5c6SRoopa Prabhu 	int err = 0;
295382cbb5c6SRoopa Prabhu 
295482cbb5c6SRoopa Prabhu 	skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL);
295582cbb5c6SRoopa Prabhu 	if (!skb)
295682cbb5c6SRoopa Prabhu 		return -ENOBUFS;
295782cbb5c6SRoopa Prabhu 
295882cbb5c6SRoopa Prabhu 	err = pneigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0, tbl);
295982cbb5c6SRoopa Prabhu 	if (err) {
296082cbb5c6SRoopa Prabhu 		kfree_skb(skb);
296182cbb5c6SRoopa Prabhu 		goto errout;
296282cbb5c6SRoopa Prabhu 	}
296382cbb5c6SRoopa Prabhu 
296482cbb5c6SRoopa Prabhu 	err = rtnl_unicast(skb, net, pid);
296582cbb5c6SRoopa Prabhu errout:
296682cbb5c6SRoopa Prabhu 	return err;
296782cbb5c6SRoopa Prabhu }
296882cbb5c6SRoopa Prabhu 
296982cbb5c6SRoopa Prabhu static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
297082cbb5c6SRoopa Prabhu 		     struct netlink_ext_ack *extack)
297182cbb5c6SRoopa Prabhu {
297282cbb5c6SRoopa Prabhu 	struct net *net = sock_net(in_skb->sk);
297382cbb5c6SRoopa Prabhu 	struct net_device *dev = NULL;
297482cbb5c6SRoopa Prabhu 	struct neigh_table *tbl = NULL;
297582cbb5c6SRoopa Prabhu 	struct neighbour *neigh;
297682cbb5c6SRoopa Prabhu 	void *dst = NULL;
297782cbb5c6SRoopa Prabhu 	u8 ndm_flags = 0;
297882cbb5c6SRoopa Prabhu 	int dev_idx = 0;
297982cbb5c6SRoopa Prabhu 	int err;
298082cbb5c6SRoopa Prabhu 
298182cbb5c6SRoopa Prabhu 	err = neigh_valid_get_req(nlh, &tbl, &dst, &dev_idx, &ndm_flags,
298282cbb5c6SRoopa Prabhu 				  extack);
298382cbb5c6SRoopa Prabhu 	if (err < 0)
298482cbb5c6SRoopa Prabhu 		return err;
298582cbb5c6SRoopa Prabhu 
298682cbb5c6SRoopa Prabhu 	if (dev_idx) {
298782cbb5c6SRoopa Prabhu 		dev = __dev_get_by_index(net, dev_idx);
298882cbb5c6SRoopa Prabhu 		if (!dev) {
298982cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Unknown device ifindex");
299082cbb5c6SRoopa Prabhu 			return -ENODEV;
299182cbb5c6SRoopa Prabhu 		}
299282cbb5c6SRoopa Prabhu 	}
299382cbb5c6SRoopa Prabhu 
299482cbb5c6SRoopa Prabhu 	if (!dst) {
299582cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Network address not specified");
299682cbb5c6SRoopa Prabhu 		return -EINVAL;
299782cbb5c6SRoopa Prabhu 	}
299882cbb5c6SRoopa Prabhu 
299982cbb5c6SRoopa Prabhu 	if (ndm_flags & NTF_PROXY) {
300082cbb5c6SRoopa Prabhu 		struct pneigh_entry *pn;
300182cbb5c6SRoopa Prabhu 
300282cbb5c6SRoopa Prabhu 		pn = pneigh_lookup(tbl, net, dst, dev, 0);
300382cbb5c6SRoopa Prabhu 		if (!pn) {
300482cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Proxy neighbour entry not found");
300582cbb5c6SRoopa Prabhu 			return -ENOENT;
300682cbb5c6SRoopa Prabhu 		}
300782cbb5c6SRoopa Prabhu 		return pneigh_get_reply(net, pn, NETLINK_CB(in_skb).portid,
300882cbb5c6SRoopa Prabhu 					nlh->nlmsg_seq, tbl);
300982cbb5c6SRoopa Prabhu 	}
301082cbb5c6SRoopa Prabhu 
301182cbb5c6SRoopa Prabhu 	if (!dev) {
301282cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "No device specified");
301382cbb5c6SRoopa Prabhu 		return -EINVAL;
301482cbb5c6SRoopa Prabhu 	}
301582cbb5c6SRoopa Prabhu 
301682cbb5c6SRoopa Prabhu 	neigh = neigh_lookup(tbl, dst, dev);
301782cbb5c6SRoopa Prabhu 	if (!neigh) {
301882cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Neighbour entry not found");
301982cbb5c6SRoopa Prabhu 		return -ENOENT;
302082cbb5c6SRoopa Prabhu 	}
302182cbb5c6SRoopa Prabhu 
302282cbb5c6SRoopa Prabhu 	err = neigh_get_reply(net, neigh, NETLINK_CB(in_skb).portid,
302382cbb5c6SRoopa Prabhu 			      nlh->nlmsg_seq);
302482cbb5c6SRoopa Prabhu 
302582cbb5c6SRoopa Prabhu 	neigh_release(neigh);
302682cbb5c6SRoopa Prabhu 
302782cbb5c6SRoopa Prabhu 	return err;
302882cbb5c6SRoopa Prabhu }
302982cbb5c6SRoopa Prabhu 
30301da177e4SLinus Torvalds void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
30311da177e4SLinus Torvalds {
30321da177e4SLinus Torvalds 	int chain;
3033d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
30341da177e4SLinus Torvalds 
3035d6bf7817SEric Dumazet 	rcu_read_lock_bh();
3036d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
3037d6bf7817SEric Dumazet 
3038767e97e1SEric Dumazet 	read_lock(&tbl->lock); /* avoid resizes */
3039cd089336SDavid S. Miller 	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
30401da177e4SLinus Torvalds 		struct neighbour *n;
30411da177e4SLinus Torvalds 
3042767e97e1SEric Dumazet 		for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
3043767e97e1SEric Dumazet 		     n != NULL;
3044767e97e1SEric Dumazet 		     n = rcu_dereference_bh(n->next))
30451da177e4SLinus Torvalds 			cb(n, cookie);
30461da177e4SLinus Torvalds 	}
3047d6bf7817SEric Dumazet 	read_unlock(&tbl->lock);
3048d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
30491da177e4SLinus Torvalds }
30501da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_for_each);
30511da177e4SLinus Torvalds 
30521da177e4SLinus Torvalds /* The tbl->lock must be held as a writer and BH disabled. */
30531da177e4SLinus Torvalds void __neigh_for_each_release(struct neigh_table *tbl,
30541da177e4SLinus Torvalds 			      int (*cb)(struct neighbour *))
30551da177e4SLinus Torvalds {
30561da177e4SLinus Torvalds 	int chain;
3057d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
30581da177e4SLinus Torvalds 
3059d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
3060d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
3061cd089336SDavid S. Miller 	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
3062767e97e1SEric Dumazet 		struct neighbour *n;
3063767e97e1SEric Dumazet 		struct neighbour __rcu **np;
30641da177e4SLinus Torvalds 
3065d6bf7817SEric Dumazet 		np = &nht->hash_buckets[chain];
3066767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
3067767e97e1SEric Dumazet 					lockdep_is_held(&tbl->lock))) != NULL) {
30681da177e4SLinus Torvalds 			int release;
30691da177e4SLinus Torvalds 
30701da177e4SLinus Torvalds 			write_lock(&n->lock);
30711da177e4SLinus Torvalds 			release = cb(n);
30721da177e4SLinus Torvalds 			if (release) {
3073767e97e1SEric Dumazet 				rcu_assign_pointer(*np,
3074767e97e1SEric Dumazet 					rcu_dereference_protected(n->next,
3075767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
307658956317SDavid Ahern 				neigh_mark_dead(n);
30771da177e4SLinus Torvalds 			} else
30781da177e4SLinus Torvalds 				np = &n->next;
30791da177e4SLinus Torvalds 			write_unlock(&n->lock);
30804f494554SThomas Graf 			if (release)
30814f494554SThomas Graf 				neigh_cleanup_and_release(n);
30821da177e4SLinus Torvalds 		}
30831da177e4SLinus Torvalds 	}
3084ecbb4169SAlexey Kuznetsov }
30851da177e4SLinus Torvalds EXPORT_SYMBOL(__neigh_for_each_release);
30861da177e4SLinus Torvalds 
3087b79bda3dSEric W. Biederman int neigh_xmit(int index, struct net_device *dev,
30884fd3d7d9SEric W. Biederman 	       const void *addr, struct sk_buff *skb)
30894fd3d7d9SEric W. Biederman {
3090b79bda3dSEric W. Biederman 	int err = -EAFNOSUPPORT;
3091b79bda3dSEric W. Biederman 	if (likely(index < NEIGH_NR_TABLES)) {
30924fd3d7d9SEric W. Biederman 		struct neigh_table *tbl;
30934fd3d7d9SEric W. Biederman 		struct neighbour *neigh;
30944fd3d7d9SEric W. Biederman 
3095b79bda3dSEric W. Biederman 		tbl = neigh_tables[index];
30964fd3d7d9SEric W. Biederman 		if (!tbl)
30974fd3d7d9SEric W. Biederman 			goto out;
3098b560f03dSDavid Barroso 		rcu_read_lock_bh();
30994b2a2bfeSDavid Ahern 		if (index == NEIGH_ARP_TABLE) {
31004b2a2bfeSDavid Ahern 			u32 key = *((u32 *)addr);
31014b2a2bfeSDavid Ahern 
31024b2a2bfeSDavid Ahern 			neigh = __ipv4_neigh_lookup_noref(dev, key);
31034b2a2bfeSDavid Ahern 		} else {
31044fd3d7d9SEric W. Biederman 			neigh = __neigh_lookup_noref(tbl, addr, dev);
31054b2a2bfeSDavid Ahern 		}
31064fd3d7d9SEric W. Biederman 		if (!neigh)
31074fd3d7d9SEric W. Biederman 			neigh = __neigh_create(tbl, addr, dev, false);
31084fd3d7d9SEric W. Biederman 		err = PTR_ERR(neigh);
3109b560f03dSDavid Barroso 		if (IS_ERR(neigh)) {
3110b560f03dSDavid Barroso 			rcu_read_unlock_bh();
31114fd3d7d9SEric W. Biederman 			goto out_kfree_skb;
3112b560f03dSDavid Barroso 		}
31134fd3d7d9SEric W. Biederman 		err = neigh->output(neigh, skb);
3114b560f03dSDavid Barroso 		rcu_read_unlock_bh();
31154fd3d7d9SEric W. Biederman 	}
3116b79bda3dSEric W. Biederman 	else if (index == NEIGH_LINK_TABLE) {
3117b79bda3dSEric W. Biederman 		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
3118b79bda3dSEric W. Biederman 				      addr, NULL, skb->len);
3119b79bda3dSEric W. Biederman 		if (err < 0)
3120b79bda3dSEric W. Biederman 			goto out_kfree_skb;
3121b79bda3dSEric W. Biederman 		err = dev_queue_xmit(skb);
3122b79bda3dSEric W. Biederman 	}
31234fd3d7d9SEric W. Biederman out:
31244fd3d7d9SEric W. Biederman 	return err;
31254fd3d7d9SEric W. Biederman out_kfree_skb:
31264fd3d7d9SEric W. Biederman 	kfree_skb(skb);
31274fd3d7d9SEric W. Biederman 	goto out;
31284fd3d7d9SEric W. Biederman }
31294fd3d7d9SEric W. Biederman EXPORT_SYMBOL(neigh_xmit);
31304fd3d7d9SEric W. Biederman 
31311da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
31321da177e4SLinus Torvalds 
31331da177e4SLinus Torvalds static struct neighbour *neigh_get_first(struct seq_file *seq)
31341da177e4SLinus Torvalds {
31351da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
31361218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
3137d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = state->nht;
31381da177e4SLinus Torvalds 	struct neighbour *n = NULL;
3139f530eed6SColin Ian King 	int bucket;
31401da177e4SLinus Torvalds 
31411da177e4SLinus Torvalds 	state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
3142cd089336SDavid S. Miller 	for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
3143767e97e1SEric Dumazet 		n = rcu_dereference_bh(nht->hash_buckets[bucket]);
31441da177e4SLinus Torvalds 
31451da177e4SLinus Torvalds 		while (n) {
3146878628fbSYOSHIFUJI Hideaki 			if (!net_eq(dev_net(n->dev), net))
3147426b5303SEric W. Biederman 				goto next;
31481da177e4SLinus Torvalds 			if (state->neigh_sub_iter) {
31491da177e4SLinus Torvalds 				loff_t fakep = 0;
31501da177e4SLinus Torvalds 				void *v;
31511da177e4SLinus Torvalds 
31521da177e4SLinus Torvalds 				v = state->neigh_sub_iter(state, n, &fakep);
31531da177e4SLinus Torvalds 				if (!v)
31541da177e4SLinus Torvalds 					goto next;
31551da177e4SLinus Torvalds 			}
31561da177e4SLinus Torvalds 			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
31571da177e4SLinus Torvalds 				break;
31581da177e4SLinus Torvalds 			if (n->nud_state & ~NUD_NOARP)
31591da177e4SLinus Torvalds 				break;
31601da177e4SLinus Torvalds next:
3161767e97e1SEric Dumazet 			n = rcu_dereference_bh(n->next);
31621da177e4SLinus Torvalds 		}
31631da177e4SLinus Torvalds 
31641da177e4SLinus Torvalds 		if (n)
31651da177e4SLinus Torvalds 			break;
31661da177e4SLinus Torvalds 	}
31671da177e4SLinus Torvalds 	state->bucket = bucket;
31681da177e4SLinus Torvalds 
31691da177e4SLinus Torvalds 	return n;
31701da177e4SLinus Torvalds }
31711da177e4SLinus Torvalds 
31721da177e4SLinus Torvalds static struct neighbour *neigh_get_next(struct seq_file *seq,
31731da177e4SLinus Torvalds 					struct neighbour *n,
31741da177e4SLinus Torvalds 					loff_t *pos)
31751da177e4SLinus Torvalds {
31761da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
31771218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
3178d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = state->nht;
31791da177e4SLinus Torvalds 
31801da177e4SLinus Torvalds 	if (state->neigh_sub_iter) {
31811da177e4SLinus Torvalds 		void *v = state->neigh_sub_iter(state, n, pos);
31821da177e4SLinus Torvalds 		if (v)
31831da177e4SLinus Torvalds 			return n;
31841da177e4SLinus Torvalds 	}
3185767e97e1SEric Dumazet 	n = rcu_dereference_bh(n->next);
31861da177e4SLinus Torvalds 
31871da177e4SLinus Torvalds 	while (1) {
31881da177e4SLinus Torvalds 		while (n) {
3189878628fbSYOSHIFUJI Hideaki 			if (!net_eq(dev_net(n->dev), net))
3190426b5303SEric W. Biederman 				goto next;
31911da177e4SLinus Torvalds 			if (state->neigh_sub_iter) {
31921da177e4SLinus Torvalds 				void *v = state->neigh_sub_iter(state, n, pos);
31931da177e4SLinus Torvalds 				if (v)
31941da177e4SLinus Torvalds 					return n;
31951da177e4SLinus Torvalds 				goto next;
31961da177e4SLinus Torvalds 			}
31971da177e4SLinus Torvalds 			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
31981da177e4SLinus Torvalds 				break;
31991da177e4SLinus Torvalds 
32001da177e4SLinus Torvalds 			if (n->nud_state & ~NUD_NOARP)
32011da177e4SLinus Torvalds 				break;
32021da177e4SLinus Torvalds next:
3203767e97e1SEric Dumazet 			n = rcu_dereference_bh(n->next);
32041da177e4SLinus Torvalds 		}
32051da177e4SLinus Torvalds 
32061da177e4SLinus Torvalds 		if (n)
32071da177e4SLinus Torvalds 			break;
32081da177e4SLinus Torvalds 
3209cd089336SDavid S. Miller 		if (++state->bucket >= (1 << nht->hash_shift))
32101da177e4SLinus Torvalds 			break;
32111da177e4SLinus Torvalds 
3212767e97e1SEric Dumazet 		n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
32131da177e4SLinus Torvalds 	}
32141da177e4SLinus Torvalds 
32151da177e4SLinus Torvalds 	if (n && pos)
32161da177e4SLinus Torvalds 		--(*pos);
32171da177e4SLinus Torvalds 	return n;
32181da177e4SLinus Torvalds }
32191da177e4SLinus Torvalds 
32201da177e4SLinus Torvalds static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
32211da177e4SLinus Torvalds {
32221da177e4SLinus Torvalds 	struct neighbour *n = neigh_get_first(seq);
32231da177e4SLinus Torvalds 
32241da177e4SLinus Torvalds 	if (n) {
3225745e2031SChris Larson 		--(*pos);
32261da177e4SLinus Torvalds 		while (*pos) {
32271da177e4SLinus Torvalds 			n = neigh_get_next(seq, n, pos);
32281da177e4SLinus Torvalds 			if (!n)
32291da177e4SLinus Torvalds 				break;
32301da177e4SLinus Torvalds 		}
32311da177e4SLinus Torvalds 	}
32321da177e4SLinus Torvalds 	return *pos ? NULL : n;
32331da177e4SLinus Torvalds }
32341da177e4SLinus Torvalds 
32351da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
32361da177e4SLinus Torvalds {
32371da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
32381218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
32391da177e4SLinus Torvalds 	struct neigh_table *tbl = state->tbl;
32401da177e4SLinus Torvalds 	struct pneigh_entry *pn = NULL;
324148de7c0cSYang Li 	int bucket;
32421da177e4SLinus Torvalds 
32431da177e4SLinus Torvalds 	state->flags |= NEIGH_SEQ_IS_PNEIGH;
32441da177e4SLinus Torvalds 	for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
32451da177e4SLinus Torvalds 		pn = tbl->phash_buckets[bucket];
3246878628fbSYOSHIFUJI Hideaki 		while (pn && !net_eq(pneigh_net(pn), net))
3247426b5303SEric W. Biederman 			pn = pn->next;
32481da177e4SLinus Torvalds 		if (pn)
32491da177e4SLinus Torvalds 			break;
32501da177e4SLinus Torvalds 	}
32511da177e4SLinus Torvalds 	state->bucket = bucket;
32521da177e4SLinus Torvalds 
32531da177e4SLinus Torvalds 	return pn;
32541da177e4SLinus Torvalds }
32551da177e4SLinus Torvalds 
32561da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
32571da177e4SLinus Torvalds 					    struct pneigh_entry *pn,
32581da177e4SLinus Torvalds 					    loff_t *pos)
32591da177e4SLinus Torvalds {
32601da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
32611218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
32621da177e4SLinus Torvalds 	struct neigh_table *tbl = state->tbl;
32631da177e4SLinus Torvalds 
3264df07a94cSJorge Boncompte [DTI2] 	do {
32651da177e4SLinus Torvalds 		pn = pn->next;
3266df07a94cSJorge Boncompte [DTI2] 	} while (pn && !net_eq(pneigh_net(pn), net));
3267df07a94cSJorge Boncompte [DTI2] 
32681da177e4SLinus Torvalds 	while (!pn) {
32691da177e4SLinus Torvalds 		if (++state->bucket > PNEIGH_HASHMASK)
32701da177e4SLinus Torvalds 			break;
32711da177e4SLinus Torvalds 		pn = tbl->phash_buckets[state->bucket];
3272878628fbSYOSHIFUJI Hideaki 		while (pn && !net_eq(pneigh_net(pn), net))
3273426b5303SEric W. Biederman 			pn = pn->next;
32741da177e4SLinus Torvalds 		if (pn)
32751da177e4SLinus Torvalds 			break;
32761da177e4SLinus Torvalds 	}
32771da177e4SLinus Torvalds 
32781da177e4SLinus Torvalds 	if (pn && pos)
32791da177e4SLinus Torvalds 		--(*pos);
32801da177e4SLinus Torvalds 
32811da177e4SLinus Torvalds 	return pn;
32821da177e4SLinus Torvalds }
32831da177e4SLinus Torvalds 
32841da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
32851da177e4SLinus Torvalds {
32861da177e4SLinus Torvalds 	struct pneigh_entry *pn = pneigh_get_first(seq);
32871da177e4SLinus Torvalds 
32881da177e4SLinus Torvalds 	if (pn) {
3289745e2031SChris Larson 		--(*pos);
32901da177e4SLinus Torvalds 		while (*pos) {
32911da177e4SLinus Torvalds 			pn = pneigh_get_next(seq, pn, pos);
32921da177e4SLinus Torvalds 			if (!pn)
32931da177e4SLinus Torvalds 				break;
32941da177e4SLinus Torvalds 		}
32951da177e4SLinus Torvalds 	}
32961da177e4SLinus Torvalds 	return *pos ? NULL : pn;
32971da177e4SLinus Torvalds }
32981da177e4SLinus Torvalds 
32991da177e4SLinus Torvalds static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
33001da177e4SLinus Torvalds {
33011da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
33021da177e4SLinus Torvalds 	void *rc;
3303745e2031SChris Larson 	loff_t idxpos = *pos;
33041da177e4SLinus Torvalds 
3305745e2031SChris Larson 	rc = neigh_get_idx(seq, &idxpos);
33061da177e4SLinus Torvalds 	if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
3307745e2031SChris Larson 		rc = pneigh_get_idx(seq, &idxpos);
33081da177e4SLinus Torvalds 
33091da177e4SLinus Torvalds 	return rc;
33101da177e4SLinus Torvalds }
33111da177e4SLinus Torvalds 
33121da177e4SLinus Torvalds void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags)
3313f3e92cb8SEric Dumazet 	__acquires(tbl->lock)
3314d6bf7817SEric Dumazet 	__acquires(rcu_bh)
33151da177e4SLinus Torvalds {
33161da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
33171da177e4SLinus Torvalds 
33181da177e4SLinus Torvalds 	state->tbl = tbl;
33191da177e4SLinus Torvalds 	state->bucket = 0;
33201da177e4SLinus Torvalds 	state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
33211da177e4SLinus Torvalds 
3322d6bf7817SEric Dumazet 	rcu_read_lock_bh();
3323d6bf7817SEric Dumazet 	state->nht = rcu_dereference_bh(tbl->nht);
3324f3e92cb8SEric Dumazet 	read_lock(&tbl->lock);
3325767e97e1SEric Dumazet 
3326745e2031SChris Larson 	return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
33271da177e4SLinus Torvalds }
33281da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_start);
33291da177e4SLinus Torvalds 
33301da177e4SLinus Torvalds void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
33311da177e4SLinus Torvalds {
33321da177e4SLinus Torvalds 	struct neigh_seq_state *state;
33331da177e4SLinus Torvalds 	void *rc;
33341da177e4SLinus Torvalds 
33351da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN) {
3336bff69732SChris Larson 		rc = neigh_get_first(seq);
33371da177e4SLinus Torvalds 		goto out;
33381da177e4SLinus Torvalds 	}
33391da177e4SLinus Torvalds 
33401da177e4SLinus Torvalds 	state = seq->private;
33411da177e4SLinus Torvalds 	if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
33421da177e4SLinus Torvalds 		rc = neigh_get_next(seq, v, NULL);
33431da177e4SLinus Torvalds 		if (rc)
33441da177e4SLinus Torvalds 			goto out;
33451da177e4SLinus Torvalds 		if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
33461da177e4SLinus Torvalds 			rc = pneigh_get_first(seq);
33471da177e4SLinus Torvalds 	} else {
33481da177e4SLinus Torvalds 		BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
33491da177e4SLinus Torvalds 		rc = pneigh_get_next(seq, v, NULL);
33501da177e4SLinus Torvalds 	}
33511da177e4SLinus Torvalds out:
33521da177e4SLinus Torvalds 	++(*pos);
33531da177e4SLinus Torvalds 	return rc;
33541da177e4SLinus Torvalds }
33551da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_next);
33561da177e4SLinus Torvalds 
33571da177e4SLinus Torvalds void neigh_seq_stop(struct seq_file *seq, void *v)
3358f3e92cb8SEric Dumazet 	__releases(tbl->lock)
3359d6bf7817SEric Dumazet 	__releases(rcu_bh)
33601da177e4SLinus Torvalds {
3361f3e92cb8SEric Dumazet 	struct neigh_seq_state *state = seq->private;
3362f3e92cb8SEric Dumazet 	struct neigh_table *tbl = state->tbl;
3363f3e92cb8SEric Dumazet 
3364f3e92cb8SEric Dumazet 	read_unlock(&tbl->lock);
3365d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
33661da177e4SLinus Torvalds }
33671da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_stop);
33681da177e4SLinus Torvalds 
33691da177e4SLinus Torvalds /* statistics via seq_file */
33701da177e4SLinus Torvalds 
33711da177e4SLinus Torvalds static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
33721da177e4SLinus Torvalds {
3373359745d7SMuchun Song 	struct neigh_table *tbl = pde_data(file_inode(seq->file));
33741da177e4SLinus Torvalds 	int cpu;
33751da177e4SLinus Torvalds 
33761da177e4SLinus Torvalds 	if (*pos == 0)
33771da177e4SLinus Torvalds 		return SEQ_START_TOKEN;
33781da177e4SLinus Torvalds 
33790f23174aSRusty Russell 	for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
33801da177e4SLinus Torvalds 		if (!cpu_possible(cpu))
33811da177e4SLinus Torvalds 			continue;
33821da177e4SLinus Torvalds 		*pos = cpu+1;
33831da177e4SLinus Torvalds 		return per_cpu_ptr(tbl->stats, cpu);
33841da177e4SLinus Torvalds 	}
33851da177e4SLinus Torvalds 	return NULL;
33861da177e4SLinus Torvalds }
33871da177e4SLinus Torvalds 
33881da177e4SLinus Torvalds static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
33891da177e4SLinus Torvalds {
3390359745d7SMuchun Song 	struct neigh_table *tbl = pde_data(file_inode(seq->file));
33911da177e4SLinus Torvalds 	int cpu;
33921da177e4SLinus Torvalds 
33930f23174aSRusty Russell 	for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
33941da177e4SLinus Torvalds 		if (!cpu_possible(cpu))
33951da177e4SLinus Torvalds 			continue;
33961da177e4SLinus Torvalds 		*pos = cpu+1;
33971da177e4SLinus Torvalds 		return per_cpu_ptr(tbl->stats, cpu);
33981da177e4SLinus Torvalds 	}
33991e3f9f07SVasily Averin 	(*pos)++;
34001da177e4SLinus Torvalds 	return NULL;
34011da177e4SLinus Torvalds }
34021da177e4SLinus Torvalds 
34031da177e4SLinus Torvalds static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
34041da177e4SLinus Torvalds {
34051da177e4SLinus Torvalds 
34061da177e4SLinus Torvalds }
34071da177e4SLinus Torvalds 
34081da177e4SLinus Torvalds static int neigh_stat_seq_show(struct seq_file *seq, void *v)
34091da177e4SLinus Torvalds {
3410359745d7SMuchun Song 	struct neigh_table *tbl = pde_data(file_inode(seq->file));
34111da177e4SLinus Torvalds 	struct neigh_statistics *st = v;
34121da177e4SLinus Torvalds 
34131da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN) {
34140547ffe6SYajun 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");
34151da177e4SLinus Torvalds 		return 0;
34161da177e4SLinus Torvalds 	}
34171da177e4SLinus Torvalds 
34181da177e4SLinus Torvalds 	seq_printf(seq, "%08x %08lx %08lx %08lx   %08lx %08lx %08lx   "
34190547ffe6SYajun Deng 			"%08lx         %08lx         %08lx         "
34200547ffe6SYajun Deng 			"%08lx       %08lx            %08lx\n",
34211da177e4SLinus Torvalds 		   atomic_read(&tbl->entries),
34221da177e4SLinus Torvalds 
34231da177e4SLinus Torvalds 		   st->allocs,
34241da177e4SLinus Torvalds 		   st->destroys,
34251da177e4SLinus Torvalds 		   st->hash_grows,
34261da177e4SLinus Torvalds 
34271da177e4SLinus Torvalds 		   st->lookups,
34281da177e4SLinus Torvalds 		   st->hits,
34291da177e4SLinus Torvalds 
34301da177e4SLinus Torvalds 		   st->res_failed,
34311da177e4SLinus Torvalds 
34321da177e4SLinus Torvalds 		   st->rcv_probes_mcast,
34331da177e4SLinus Torvalds 		   st->rcv_probes_ucast,
34341da177e4SLinus Torvalds 
34351da177e4SLinus Torvalds 		   st->periodic_gc_runs,
34369a6d276eSNeil Horman 		   st->forced_gc_runs,
3437fb811395SRick Jones 		   st->unres_discards,
3438fb811395SRick Jones 		   st->table_fulls
34391da177e4SLinus Torvalds 		   );
34401da177e4SLinus Torvalds 
34411da177e4SLinus Torvalds 	return 0;
34421da177e4SLinus Torvalds }
34431da177e4SLinus Torvalds 
3444f690808eSStephen Hemminger static const struct seq_operations neigh_stat_seq_ops = {
34451da177e4SLinus Torvalds 	.start	= neigh_stat_seq_start,
34461da177e4SLinus Torvalds 	.next	= neigh_stat_seq_next,
34471da177e4SLinus Torvalds 	.stop	= neigh_stat_seq_stop,
34481da177e4SLinus Torvalds 	.show	= neigh_stat_seq_show,
34491da177e4SLinus Torvalds };
34501da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */
34511da177e4SLinus Torvalds 
34527b8f7a40SRoopa Prabhu static void __neigh_notify(struct neighbour *n, int type, int flags,
34537b8f7a40SRoopa Prabhu 			   u32 pid)
34541da177e4SLinus Torvalds {
3455c346dca1SYOSHIFUJI Hideaki 	struct net *net = dev_net(n->dev);
34568b8aec50SThomas Graf 	struct sk_buff *skb;
3457b8673311SThomas Graf 	int err = -ENOBUFS;
34581da177e4SLinus Torvalds 
3459339bf98fSThomas Graf 	skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
34608b8aec50SThomas Graf 	if (skb == NULL)
3461b8673311SThomas Graf 		goto errout;
34621da177e4SLinus Torvalds 
34637b8f7a40SRoopa Prabhu 	err = neigh_fill_info(skb, n, pid, 0, type, flags);
346426932566SPatrick McHardy 	if (err < 0) {
346526932566SPatrick McHardy 		/* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
346626932566SPatrick McHardy 		WARN_ON(err == -EMSGSIZE);
346726932566SPatrick McHardy 		kfree_skb(skb);
346826932566SPatrick McHardy 		goto errout;
346926932566SPatrick McHardy 	}
34701ce85fe4SPablo Neira Ayuso 	rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
34711ce85fe4SPablo Neira Ayuso 	return;
3472b8673311SThomas Graf errout:
3473b8673311SThomas Graf 	if (err < 0)
3474426b5303SEric W. Biederman 		rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
3475b8673311SThomas Graf }
3476b8673311SThomas Graf 
3477b8673311SThomas Graf void neigh_app_ns(struct neighbour *n)
3478b8673311SThomas Graf {
34797b8f7a40SRoopa Prabhu 	__neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST, 0);
34808b8aec50SThomas Graf }
34810a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_app_ns);
34821da177e4SLinus Torvalds 
34831da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL
3484b93196dcSCong Wang static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
34851da177e4SLinus Torvalds 
3486fe2c6338SJoe Perches static int proc_unres_qlen(struct ctl_table *ctl, int write,
348732927393SChristoph Hellwig 			   void *buffer, size_t *lenp, loff_t *ppos)
34888b5c171bSEric Dumazet {
34898b5c171bSEric Dumazet 	int size, ret;
3490fe2c6338SJoe Perches 	struct ctl_table tmp = *ctl;
34918b5c171bSEric Dumazet 
3492eec4844fSMatteo Croce 	tmp.extra1 = SYSCTL_ZERO;
3493ce46cc64SShan Wei 	tmp.extra2 = &unres_qlen_max;
34948b5c171bSEric Dumazet 	tmp.data = &size;
3495ce46cc64SShan Wei 
3496ce46cc64SShan Wei 	size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN);
3497ce46cc64SShan Wei 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
3498ce46cc64SShan Wei 
34998b5c171bSEric Dumazet 	if (write && !ret)
35008b5c171bSEric Dumazet 		*(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
35018b5c171bSEric Dumazet 	return ret;
35028b5c171bSEric Dumazet }
35038b5c171bSEric Dumazet 
35041d4c8c29SJiri Pirko static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
35051d4c8c29SJiri Pirko 						   int family)
35061d4c8c29SJiri Pirko {
3507bba24896SJiri Pirko 	switch (family) {
3508bba24896SJiri Pirko 	case AF_INET:
35091d4c8c29SJiri Pirko 		return __in_dev_arp_parms_get_rcu(dev);
3510bba24896SJiri Pirko 	case AF_INET6:
3511bba24896SJiri Pirko 		return __in6_dev_nd_parms_get_rcu(dev);
3512bba24896SJiri Pirko 	}
35131d4c8c29SJiri Pirko 	return NULL;
35141d4c8c29SJiri Pirko }
35151d4c8c29SJiri Pirko 
35161d4c8c29SJiri Pirko static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
35171d4c8c29SJiri Pirko 				  int index)
35181d4c8c29SJiri Pirko {
35191d4c8c29SJiri Pirko 	struct net_device *dev;
35201d4c8c29SJiri Pirko 	int family = neigh_parms_family(p);
35211d4c8c29SJiri Pirko 
35221d4c8c29SJiri Pirko 	rcu_read_lock();
35231d4c8c29SJiri Pirko 	for_each_netdev_rcu(net, dev) {
35241d4c8c29SJiri Pirko 		struct neigh_parms *dst_p =
35251d4c8c29SJiri Pirko 				neigh_get_dev_parms_rcu(dev, family);
35261d4c8c29SJiri Pirko 
35271d4c8c29SJiri Pirko 		if (dst_p && !test_bit(index, dst_p->data_state))
35281d4c8c29SJiri Pirko 			dst_p->data[index] = p->data[index];
35291d4c8c29SJiri Pirko 	}
35301d4c8c29SJiri Pirko 	rcu_read_unlock();
35311d4c8c29SJiri Pirko }
35321d4c8c29SJiri Pirko 
35331d4c8c29SJiri Pirko static void neigh_proc_update(struct ctl_table *ctl, int write)
35341d4c8c29SJiri Pirko {
35351d4c8c29SJiri Pirko 	struct net_device *dev = ctl->extra1;
35361d4c8c29SJiri Pirko 	struct neigh_parms *p = ctl->extra2;
353777d47afbSJiri Pirko 	struct net *net = neigh_parms_net(p);
35381d4c8c29SJiri Pirko 	int index = (int *) ctl->data - p->data;
35391d4c8c29SJiri Pirko 
35401d4c8c29SJiri Pirko 	if (!write)
35411d4c8c29SJiri Pirko 		return;
35421d4c8c29SJiri Pirko 
35431d4c8c29SJiri Pirko 	set_bit(index, p->data_state);
35447627ae60SMarcus Huewe 	if (index == NEIGH_VAR_DELAY_PROBE_TIME)
35452a4501aeSIdo Schimmel 		call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
35461d4c8c29SJiri Pirko 	if (!dev) /* NULL dev means this is default value */
35471d4c8c29SJiri Pirko 		neigh_copy_dflt_parms(net, p, index);
35481d4c8c29SJiri Pirko }
35491d4c8c29SJiri Pirko 
35501f9248e5SJiri Pirko static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
355132927393SChristoph Hellwig 					   void *buffer, size_t *lenp,
355232927393SChristoph Hellwig 					   loff_t *ppos)
35531f9248e5SJiri Pirko {
35541f9248e5SJiri Pirko 	struct ctl_table tmp = *ctl;
35551d4c8c29SJiri Pirko 	int ret;
35561f9248e5SJiri Pirko 
3557eec4844fSMatteo Croce 	tmp.extra1 = SYSCTL_ZERO;
3558eec4844fSMatteo Croce 	tmp.extra2 = SYSCTL_INT_MAX;
35591f9248e5SJiri Pirko 
35601d4c8c29SJiri Pirko 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
35611d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
35621d4c8c29SJiri Pirko 	return ret;
35631f9248e5SJiri Pirko }
35641f9248e5SJiri Pirko 
356532927393SChristoph Hellwig int neigh_proc_dointvec(struct ctl_table *ctl, int write, void *buffer,
356632927393SChristoph Hellwig 			size_t *lenp, loff_t *ppos)
3567cb5b09c1SJiri Pirko {
35681d4c8c29SJiri Pirko 	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
35691d4c8c29SJiri Pirko 
35701d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
35711d4c8c29SJiri Pirko 	return ret;
3572cb5b09c1SJiri Pirko }
3573cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec);
3574cb5b09c1SJiri Pirko 
357532927393SChristoph Hellwig int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, void *buffer,
3576cb5b09c1SJiri Pirko 				size_t *lenp, loff_t *ppos)
3577cb5b09c1SJiri Pirko {
35781d4c8c29SJiri Pirko 	int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
35791d4c8c29SJiri Pirko 
35801d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
35811d4c8c29SJiri Pirko 	return ret;
3582cb5b09c1SJiri Pirko }
3583cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
3584cb5b09c1SJiri Pirko 
3585cb5b09c1SJiri Pirko static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write,
358632927393SChristoph Hellwig 					      void *buffer, size_t *lenp,
358732927393SChristoph Hellwig 					      loff_t *ppos)
3588cb5b09c1SJiri Pirko {
35891d4c8c29SJiri Pirko 	int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
35901d4c8c29SJiri Pirko 
35911d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
35921d4c8c29SJiri Pirko 	return ret;
3593cb5b09c1SJiri Pirko }
3594cb5b09c1SJiri Pirko 
3595cb5b09c1SJiri Pirko int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
359632927393SChristoph Hellwig 				   void *buffer, size_t *lenp, loff_t *ppos)
3597cb5b09c1SJiri Pirko {
35981d4c8c29SJiri Pirko 	int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
35991d4c8c29SJiri Pirko 
36001d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36011d4c8c29SJiri Pirko 	return ret;
3602cb5b09c1SJiri Pirko }
3603cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
3604cb5b09c1SJiri Pirko 
3605cb5b09c1SJiri Pirko static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
360632927393SChristoph Hellwig 					  void *buffer, size_t *lenp,
360732927393SChristoph Hellwig 					  loff_t *ppos)
3608cb5b09c1SJiri Pirko {
36091d4c8c29SJiri Pirko 	int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
36101d4c8c29SJiri Pirko 
36111d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
36121d4c8c29SJiri Pirko 	return ret;
3613cb5b09c1SJiri Pirko }
3614cb5b09c1SJiri Pirko 
36154bf6980dSJean-Francois Remy static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write,
361632927393SChristoph Hellwig 					  void *buffer, size_t *lenp,
361732927393SChristoph Hellwig 					  loff_t *ppos)
36184bf6980dSJean-Francois Remy {
36194bf6980dSJean-Francois Remy 	struct neigh_parms *p = ctl->extra2;
36204bf6980dSJean-Francois Remy 	int ret;
36214bf6980dSJean-Francois Remy 
36224bf6980dSJean-Francois Remy 	if (strcmp(ctl->procname, "base_reachable_time") == 0)
36234bf6980dSJean-Francois Remy 		ret = neigh_proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
36244bf6980dSJean-Francois Remy 	else if (strcmp(ctl->procname, "base_reachable_time_ms") == 0)
36254bf6980dSJean-Francois Remy 		ret = neigh_proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
36264bf6980dSJean-Francois Remy 	else
36274bf6980dSJean-Francois Remy 		ret = -1;
36284bf6980dSJean-Francois Remy 
36294bf6980dSJean-Francois Remy 	if (write && ret == 0) {
36304bf6980dSJean-Francois Remy 		/* update reachable_time as well, otherwise, the change will
36314bf6980dSJean-Francois Remy 		 * only be effective after the next time neigh_periodic_work
36324bf6980dSJean-Francois Remy 		 * decides to recompute it
36334bf6980dSJean-Francois Remy 		 */
36344bf6980dSJean-Francois Remy 		p->reachable_time =
36354bf6980dSJean-Francois Remy 			neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
36364bf6980dSJean-Francois Remy 	}
36374bf6980dSJean-Francois Remy 	return ret;
36384bf6980dSJean-Francois Remy }
36394bf6980dSJean-Francois Remy 
36401f9248e5SJiri Pirko #define NEIGH_PARMS_DATA_OFFSET(index)	\
36411f9248e5SJiri Pirko 	(&((struct neigh_parms *) 0)->data[index])
36421f9248e5SJiri Pirko 
36431f9248e5SJiri Pirko #define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \
36441f9248e5SJiri Pirko 	[NEIGH_VAR_ ## attr] = { \
36451f9248e5SJiri Pirko 		.procname	= name, \
36461f9248e5SJiri Pirko 		.data		= NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \
36471f9248e5SJiri Pirko 		.maxlen		= sizeof(int), \
36481f9248e5SJiri Pirko 		.mode		= mval, \
36491f9248e5SJiri Pirko 		.proc_handler	= proc, \
36501f9248e5SJiri Pirko 	}
36511f9248e5SJiri Pirko 
36521f9248e5SJiri Pirko #define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \
36531f9248e5SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax)
36541f9248e5SJiri Pirko 
36551f9248e5SJiri Pirko #define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \
3656cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies)
36571f9248e5SJiri Pirko 
36581f9248e5SJiri Pirko #define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
3659cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)
36601f9248e5SJiri Pirko 
36611f9248e5SJiri Pirko #define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \
3662cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
36631f9248e5SJiri Pirko 
36641f9248e5SJiri Pirko #define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \
3665cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_unres_qlen)
366654716e3bSEric W. Biederman 
36671da177e4SLinus Torvalds static struct neigh_sysctl_table {
36681da177e4SLinus Torvalds 	struct ctl_table_header *sysctl_header;
36698b5c171bSEric Dumazet 	struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
3670ab32ea5dSBrian Haley } neigh_sysctl_template __read_mostly = {
36711da177e4SLinus Torvalds 	.neigh_vars = {
36721f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"),
36731f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"),
36741f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"),
36758da86466SYOSHIFUJI Hideaki/吉藤英明 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_REPROBES, "mcast_resolicit"),
36761f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),
36771f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),
36781f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"),
36791f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"),
36801f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"),
36811f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"),
36821f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"),
36831f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"),
36841f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"),
36851f9248e5SJiri Pirko 		NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"),
36861f9248e5SJiri Pirko 		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"),
36871f9248e5SJiri Pirko 		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"),
36888b5c171bSEric Dumazet 		[NEIGH_VAR_GC_INTERVAL] = {
36891da177e4SLinus Torvalds 			.procname	= "gc_interval",
36901da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
36911da177e4SLinus Torvalds 			.mode		= 0644,
36926d9f239aSAlexey Dobriyan 			.proc_handler	= proc_dointvec_jiffies,
36931da177e4SLinus Torvalds 		},
36948b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH1] = {
36951da177e4SLinus Torvalds 			.procname	= "gc_thresh1",
36961da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
36971da177e4SLinus Torvalds 			.mode		= 0644,
3698eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3699eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3700555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
37011da177e4SLinus Torvalds 		},
37028b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH2] = {
37031da177e4SLinus Torvalds 			.procname	= "gc_thresh2",
37041da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
37051da177e4SLinus Torvalds 			.mode		= 0644,
3706eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3707eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3708555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
37091da177e4SLinus Torvalds 		},
37108b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH3] = {
37111da177e4SLinus Torvalds 			.procname	= "gc_thresh3",
37121da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
37131da177e4SLinus Torvalds 			.mode		= 0644,
3714eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3715eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3716555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
37171da177e4SLinus Torvalds 		},
3718c3bac5a7SPavel Emelyanov 		{},
37191da177e4SLinus Torvalds 	},
37201da177e4SLinus Torvalds };
37211da177e4SLinus Torvalds 
37221da177e4SLinus Torvalds int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
372373af614aSJiri Pirko 			  proc_handler *handler)
37241da177e4SLinus Torvalds {
37251f9248e5SJiri Pirko 	int i;
37263c607bbbSPavel Emelyanov 	struct neigh_sysctl_table *t;
37271f9248e5SJiri Pirko 	const char *dev_name_source;
37288f40a1f9SEric W. Biederman 	char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
372973af614aSJiri Pirko 	char *p_name;
37301da177e4SLinus Torvalds 
3731425b9c7fSVasily Averin 	t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL_ACCOUNT);
37321da177e4SLinus Torvalds 	if (!t)
37333c607bbbSPavel Emelyanov 		goto err;
37343c607bbbSPavel Emelyanov 
3735b194c1f1SJiri Pirko 	for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
37361f9248e5SJiri Pirko 		t->neigh_vars[i].data += (long) p;
3737cb5b09c1SJiri Pirko 		t->neigh_vars[i].extra1 = dev;
37381d4c8c29SJiri Pirko 		t->neigh_vars[i].extra2 = p;
3739cb5b09c1SJiri Pirko 	}
37401da177e4SLinus Torvalds 
37411da177e4SLinus Torvalds 	if (dev) {
37421da177e4SLinus Torvalds 		dev_name_source = dev->name;
3743d12af679SEric W. Biederman 		/* Terminate the table early */
37448b5c171bSEric Dumazet 		memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
37458b5c171bSEric Dumazet 		       sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
37461da177e4SLinus Torvalds 	} else {
37479ecf07a1SMathias Krause 		struct neigh_table *tbl = p->tbl;
37488f40a1f9SEric W. Biederman 		dev_name_source = "default";
37499ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = &tbl->gc_interval;
37509ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = &tbl->gc_thresh1;
37519ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = &tbl->gc_thresh2;
37529ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = &tbl->gc_thresh3;
37531da177e4SLinus Torvalds 	}
37541da177e4SLinus Torvalds 
3755f8572d8fSEric W. Biederman 	if (handler) {
37561da177e4SLinus Torvalds 		/* RetransTime */
37578b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
37581da177e4SLinus Torvalds 		/* ReachableTime */
37598b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
37601da177e4SLinus Torvalds 		/* RetransTime (in milliseconds)*/
37618b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
37621da177e4SLinus Torvalds 		/* ReachableTime (in milliseconds) */
37638b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
37644bf6980dSJean-Francois Remy 	} else {
37654bf6980dSJean-Francois Remy 		/* Those handlers will update p->reachable_time after
37664bf6980dSJean-Francois Remy 		 * base_reachable_time(_ms) is set to ensure the new timer starts being
37674bf6980dSJean-Francois Remy 		 * applied after the next neighbour update instead of waiting for
37684bf6980dSJean-Francois Remy 		 * neigh_periodic_work to update its value (can be multiple minutes)
37694bf6980dSJean-Francois Remy 		 * So any handler that replaces them should do this as well
37704bf6980dSJean-Francois Remy 		 */
37714bf6980dSJean-Francois Remy 		/* ReachableTime */
37724bf6980dSJean-Francois Remy 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler =
37734bf6980dSJean-Francois Remy 			neigh_proc_base_reachable_time;
37744bf6980dSJean-Francois Remy 		/* ReachableTime (in milliseconds) */
37754bf6980dSJean-Francois Remy 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler =
37764bf6980dSJean-Francois Remy 			neigh_proc_base_reachable_time;
37771da177e4SLinus Torvalds 	}
37781da177e4SLinus Torvalds 
377973af614aSJiri Pirko 	switch (neigh_parms_family(p)) {
378073af614aSJiri Pirko 	case AF_INET:
378173af614aSJiri Pirko 	      p_name = "ipv4";
378273af614aSJiri Pirko 	      break;
378373af614aSJiri Pirko 	case AF_INET6:
378473af614aSJiri Pirko 	      p_name = "ipv6";
378573af614aSJiri Pirko 	      break;
378673af614aSJiri Pirko 	default:
378773af614aSJiri Pirko 	      BUG();
378873af614aSJiri Pirko 	}
378973af614aSJiri Pirko 
37908f40a1f9SEric W. Biederman 	snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
37918f40a1f9SEric W. Biederman 		p_name, dev_name_source);
37924ab438fcSDenis V. Lunev 	t->sysctl_header =
37938f40a1f9SEric W. Biederman 		register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
37943c607bbbSPavel Emelyanov 	if (!t->sysctl_header)
37958f40a1f9SEric W. Biederman 		goto free;
37963c607bbbSPavel Emelyanov 
37971da177e4SLinus Torvalds 	p->sysctl_table = t;
37981da177e4SLinus Torvalds 	return 0;
37991da177e4SLinus Torvalds 
38001da177e4SLinus Torvalds free:
38011da177e4SLinus Torvalds 	kfree(t);
38023c607bbbSPavel Emelyanov err:
38033c607bbbSPavel Emelyanov 	return -ENOBUFS;
38041da177e4SLinus Torvalds }
38050a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_sysctl_register);
38061da177e4SLinus Torvalds 
38071da177e4SLinus Torvalds void neigh_sysctl_unregister(struct neigh_parms *p)
38081da177e4SLinus Torvalds {
38091da177e4SLinus Torvalds 	if (p->sysctl_table) {
38101da177e4SLinus Torvalds 		struct neigh_sysctl_table *t = p->sysctl_table;
38111da177e4SLinus Torvalds 		p->sysctl_table = NULL;
38125dd3df10SEric W. Biederman 		unregister_net_sysctl_table(t->sysctl_header);
38131da177e4SLinus Torvalds 		kfree(t);
38141da177e4SLinus Torvalds 	}
38151da177e4SLinus Torvalds }
38160a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_sysctl_unregister);
38171da177e4SLinus Torvalds 
38181da177e4SLinus Torvalds #endif	/* CONFIG_SYSCTL */
38191da177e4SLinus Torvalds 
3820c8822a4eSThomas Graf static int __init neigh_init(void)
3821c8822a4eSThomas Graf {
3822b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0);
3823b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0);
382482cbb5c6SRoopa Prabhu 	rtnl_register(PF_UNSPEC, RTM_GETNEIGH, neigh_get, neigh_dump_info, 0);
3825c8822a4eSThomas Graf 
3826c7ac8679SGreg Rose 	rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
3827b97bac64SFlorian Westphal 		      0);
3828b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, 0);
3829c8822a4eSThomas Graf 
3830c8822a4eSThomas Graf 	return 0;
3831c8822a4eSThomas Graf }
3832c8822a4eSThomas Graf 
3833c8822a4eSThomas Graf subsys_initcall(neigh_init);
3834