xref: /openbmc/linux/net/core/neighbour.c (revision 899426b3)
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 
44d5d427cdSJoe Perches #define DEBUG
451da177e4SLinus Torvalds #define NEIGH_DEBUG 1
46d5d427cdSJoe Perches #define neigh_dbg(level, fmt, ...)		\
47d5d427cdSJoe Perches do {						\
48d5d427cdSJoe Perches 	if (level <= NEIGH_DEBUG)		\
49d5d427cdSJoe Perches 		pr_debug(fmt, ##__VA_ARGS__);	\
50d5d427cdSJoe Perches } while (0)
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds #define PNEIGH_HASHMASK		0xF
531da177e4SLinus Torvalds 
54e99e88a9SKees Cook static void neigh_timer_handler(struct timer_list *t);
557b8f7a40SRoopa Prabhu static void __neigh_notify(struct neighbour *n, int type, int flags,
567b8f7a40SRoopa Prabhu 			   u32 pid);
577b8f7a40SRoopa Prabhu static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid);
5853b76cdfSWolfgang Bumiller static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
5953b76cdfSWolfgang Bumiller 				    struct net_device *dev);
601da177e4SLinus Torvalds 
6145fc3b11SAmos Waterland #ifdef CONFIG_PROC_FS
6271a5053aSChristoph Hellwig static const struct seq_operations neigh_stat_seq_ops;
6345fc3b11SAmos Waterland #endif
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds /*
661da177e4SLinus Torvalds    Neighbour hash table buckets are protected with rwlock tbl->lock.
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds    - All the scans/updates to hash buckets MUST be made under this lock.
691da177e4SLinus Torvalds    - NOTHING clever should be made under this lock: no callbacks
701da177e4SLinus Torvalds      to protocol backends, no attempts to send something to network.
711da177e4SLinus Torvalds      It will result in deadlocks, if backend/driver wants to use neighbour
721da177e4SLinus Torvalds      cache.
731da177e4SLinus Torvalds    - If the entry requires some non-trivial actions, increase
741da177e4SLinus Torvalds      its reference count and release table lock.
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds    Neighbour entries are protected:
771da177e4SLinus Torvalds    - with reference count.
781da177e4SLinus Torvalds    - with rwlock neigh->lock
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds    Reference count prevents destruction.
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds    neigh->lock mainly serializes ll address data and its validity state.
831da177e4SLinus Torvalds    However, the same lock is used to protect another entry fields:
841da177e4SLinus Torvalds     - timer
851da177e4SLinus Torvalds     - resolution queue
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds    Again, nothing clever shall be made under neigh->lock,
881da177e4SLinus Torvalds    the most complicated procedure, which we allow is dev->hard_header.
891da177e4SLinus Torvalds    It is supposed, that dev->hard_header is simplistic and does
901da177e4SLinus Torvalds    not make callbacks to neighbour tables.
911da177e4SLinus Torvalds  */
921da177e4SLinus Torvalds 
938f40b161SDavid S. Miller static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
941da177e4SLinus Torvalds {
951da177e4SLinus Torvalds 	kfree_skb(skb);
961da177e4SLinus Torvalds 	return -ENETDOWN;
971da177e4SLinus Torvalds }
981da177e4SLinus Torvalds 
994f494554SThomas Graf static void neigh_cleanup_and_release(struct neighbour *neigh)
1004f494554SThomas Graf {
10156dd18a4SRoopa Prabhu 	trace_neigh_cleanup_and_release(neigh, 0);
1027b8f7a40SRoopa Prabhu 	__neigh_notify(neigh, RTM_DELNEIGH, 0, 0);
10353f800e3SIdo Schimmel 	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
1044f494554SThomas Graf 	neigh_release(neigh);
1054f494554SThomas Graf }
1064f494554SThomas Graf 
1071da177e4SLinus Torvalds /*
1081da177e4SLinus Torvalds  * It is random distribution in the interval (1/2)*base...(3/2)*base.
1091da177e4SLinus Torvalds  * It corresponds to default IPv6 settings and is not overridable,
1101da177e4SLinus Torvalds  * because it is really reasonable choice.
1111da177e4SLinus Torvalds  */
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds unsigned long neigh_rand_reach_time(unsigned long base)
1141da177e4SLinus Torvalds {
11563862b5bSAruna-Hewapathirane 	return base ? (prandom_u32() % base) + (base >> 1) : 0;
1161da177e4SLinus Torvalds }
1170a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_rand_reach_time);
1181da177e4SLinus Torvalds 
11958956317SDavid Ahern static void neigh_mark_dead(struct neighbour *n)
12058956317SDavid Ahern {
12158956317SDavid Ahern 	n->dead = 1;
12258956317SDavid Ahern 	if (!list_empty(&n->gc_list)) {
12358956317SDavid Ahern 		list_del_init(&n->gc_list);
12458956317SDavid Ahern 		atomic_dec(&n->tbl->gc_entries);
12558956317SDavid Ahern 	}
12658956317SDavid Ahern }
12758956317SDavid Ahern 
1289c29a2f5SDavid Ahern static void neigh_update_gc_list(struct neighbour *n)
12958956317SDavid Ahern {
130e997f8a2SDavid Ahern 	bool on_gc_list, exempt_from_gc;
13158956317SDavid Ahern 
1329c29a2f5SDavid Ahern 	write_lock_bh(&n->tbl->lock);
1339c29a2f5SDavid Ahern 	write_lock(&n->lock);
13458956317SDavid Ahern 
135e997f8a2SDavid Ahern 	/* remove from the gc list if new state is permanent or if neighbor
136e997f8a2SDavid Ahern 	 * is externally learned; otherwise entry should be on the gc list
13758956317SDavid Ahern 	 */
138e997f8a2SDavid Ahern 	exempt_from_gc = n->nud_state & NUD_PERMANENT ||
139e997f8a2SDavid Ahern 			 n->flags & NTF_EXT_LEARNED;
1409c29a2f5SDavid Ahern 	on_gc_list = !list_empty(&n->gc_list);
1418cc196d6SDavid Ahern 
142e997f8a2SDavid Ahern 	if (exempt_from_gc && on_gc_list) {
1439c29a2f5SDavid Ahern 		list_del_init(&n->gc_list);
14458956317SDavid Ahern 		atomic_dec(&n->tbl->gc_entries);
145e997f8a2SDavid Ahern 	} else if (!exempt_from_gc && !on_gc_list) {
14658956317SDavid Ahern 		/* add entries to the tail; cleaning removes from the front */
14758956317SDavid Ahern 		list_add_tail(&n->gc_list, &n->tbl->gc_list);
14858956317SDavid Ahern 		atomic_inc(&n->tbl->gc_entries);
14958956317SDavid Ahern 	}
1509c29a2f5SDavid Ahern 
1519c29a2f5SDavid Ahern 	write_unlock(&n->lock);
1529c29a2f5SDavid Ahern 	write_unlock_bh(&n->tbl->lock);
15358956317SDavid Ahern }
1541da177e4SLinus Torvalds 
155e997f8a2SDavid Ahern static bool neigh_update_ext_learned(struct neighbour *neigh, u32 flags,
156526f1b58SDavid Ahern 				     int *notify)
157526f1b58SDavid Ahern {
158e997f8a2SDavid Ahern 	bool rc = false;
159526f1b58SDavid Ahern 	u8 ndm_flags;
160526f1b58SDavid Ahern 
161526f1b58SDavid Ahern 	if (!(flags & NEIGH_UPDATE_F_ADMIN))
162e997f8a2SDavid Ahern 		return rc;
163526f1b58SDavid Ahern 
164526f1b58SDavid Ahern 	ndm_flags = (flags & NEIGH_UPDATE_F_EXT_LEARNED) ? NTF_EXT_LEARNED : 0;
165526f1b58SDavid Ahern 	if ((neigh->flags ^ ndm_flags) & NTF_EXT_LEARNED) {
166526f1b58SDavid Ahern 		if (ndm_flags & NTF_EXT_LEARNED)
167526f1b58SDavid Ahern 			neigh->flags |= NTF_EXT_LEARNED;
168526f1b58SDavid Ahern 		else
169526f1b58SDavid Ahern 			neigh->flags &= ~NTF_EXT_LEARNED;
170e997f8a2SDavid Ahern 		rc = true;
171526f1b58SDavid Ahern 		*notify = 1;
172526f1b58SDavid Ahern 	}
173e997f8a2SDavid Ahern 
174e997f8a2SDavid Ahern 	return rc;
175526f1b58SDavid Ahern }
176526f1b58SDavid Ahern 
1777e6f182bSDavid Ahern static bool neigh_del(struct neighbour *n, struct neighbour __rcu **np,
1787e6f182bSDavid Ahern 		      struct neigh_table *tbl)
1795071034eSSowmini Varadhan {
1805071034eSSowmini Varadhan 	bool retval = false;
1815071034eSSowmini Varadhan 
1825071034eSSowmini Varadhan 	write_lock(&n->lock);
1837e6f182bSDavid Ahern 	if (refcount_read(&n->refcnt) == 1) {
1845071034eSSowmini Varadhan 		struct neighbour *neigh;
1855071034eSSowmini Varadhan 
1865071034eSSowmini Varadhan 		neigh = rcu_dereference_protected(n->next,
1875071034eSSowmini Varadhan 						  lockdep_is_held(&tbl->lock));
1885071034eSSowmini Varadhan 		rcu_assign_pointer(*np, neigh);
18958956317SDavid Ahern 		neigh_mark_dead(n);
1905071034eSSowmini Varadhan 		retval = true;
1915071034eSSowmini Varadhan 	}
1925071034eSSowmini Varadhan 	write_unlock(&n->lock);
1935071034eSSowmini Varadhan 	if (retval)
1945071034eSSowmini Varadhan 		neigh_cleanup_and_release(n);
1955071034eSSowmini Varadhan 	return retval;
1965071034eSSowmini Varadhan }
1975071034eSSowmini Varadhan 
1985071034eSSowmini Varadhan bool neigh_remove_one(struct neighbour *ndel, struct neigh_table *tbl)
1995071034eSSowmini Varadhan {
2005071034eSSowmini Varadhan 	struct neigh_hash_table *nht;
2015071034eSSowmini Varadhan 	void *pkey = ndel->primary_key;
2025071034eSSowmini Varadhan 	u32 hash_val;
2035071034eSSowmini Varadhan 	struct neighbour *n;
2045071034eSSowmini Varadhan 	struct neighbour __rcu **np;
2055071034eSSowmini Varadhan 
2065071034eSSowmini Varadhan 	nht = rcu_dereference_protected(tbl->nht,
2075071034eSSowmini Varadhan 					lockdep_is_held(&tbl->lock));
2085071034eSSowmini Varadhan 	hash_val = tbl->hash(pkey, ndel->dev, nht->hash_rnd);
2095071034eSSowmini Varadhan 	hash_val = hash_val >> (32 - nht->hash_shift);
2105071034eSSowmini Varadhan 
2115071034eSSowmini Varadhan 	np = &nht->hash_buckets[hash_val];
2125071034eSSowmini Varadhan 	while ((n = rcu_dereference_protected(*np,
2135071034eSSowmini Varadhan 					      lockdep_is_held(&tbl->lock)))) {
2145071034eSSowmini Varadhan 		if (n == ndel)
2157e6f182bSDavid Ahern 			return neigh_del(n, np, tbl);
2165071034eSSowmini Varadhan 		np = &n->next;
2175071034eSSowmini Varadhan 	}
2185071034eSSowmini Varadhan 	return false;
2195071034eSSowmini Varadhan }
2205071034eSSowmini Varadhan 
2211da177e4SLinus Torvalds static int neigh_forced_gc(struct neigh_table *tbl)
2221da177e4SLinus Torvalds {
22358956317SDavid Ahern 	int max_clean = atomic_read(&tbl->gc_entries) - tbl->gc_thresh2;
22458956317SDavid Ahern 	unsigned long tref = jiffies - 5 * HZ;
22558956317SDavid Ahern 	struct neighbour *n, *tmp;
2261da177e4SLinus Torvalds 	int shrunk = 0;
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
2291da177e4SLinus Torvalds 
2301da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
2311da177e4SLinus Torvalds 
23258956317SDavid Ahern 	list_for_each_entry_safe(n, tmp, &tbl->gc_list, gc_list) {
23358956317SDavid Ahern 		if (refcount_read(&n->refcnt) == 1) {
23458956317SDavid Ahern 			bool remove = false;
23558956317SDavid Ahern 
23658956317SDavid Ahern 			write_lock(&n->lock);
237758a7f0bSDavid Ahern 			if ((n->nud_state == NUD_FAILED) ||
238e997f8a2SDavid Ahern 			    time_after(tref, n->updated))
23958956317SDavid Ahern 				remove = true;
24058956317SDavid Ahern 			write_unlock(&n->lock);
24158956317SDavid Ahern 
24258956317SDavid Ahern 			if (remove && neigh_remove_one(n, tbl))
24358956317SDavid Ahern 				shrunk++;
24458956317SDavid Ahern 			if (shrunk >= max_clean)
24558956317SDavid Ahern 				break;
2461da177e4SLinus Torvalds 		}
2471da177e4SLinus Torvalds 	}
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds 	tbl->last_flush = jiffies;
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
2521da177e4SLinus Torvalds 
2531da177e4SLinus Torvalds 	return shrunk;
2541da177e4SLinus Torvalds }
2551da177e4SLinus Torvalds 
256a43d8994SPavel Emelyanov static void neigh_add_timer(struct neighbour *n, unsigned long when)
257a43d8994SPavel Emelyanov {
258a43d8994SPavel Emelyanov 	neigh_hold(n);
259a43d8994SPavel Emelyanov 	if (unlikely(mod_timer(&n->timer, when))) {
260a43d8994SPavel Emelyanov 		printk("NEIGH: BUG, double timer add, state is %x\n",
261a43d8994SPavel Emelyanov 		       n->nud_state);
262a43d8994SPavel Emelyanov 		dump_stack();
263a43d8994SPavel Emelyanov 	}
264a43d8994SPavel Emelyanov }
265a43d8994SPavel Emelyanov 
2661da177e4SLinus Torvalds static int neigh_del_timer(struct neighbour *n)
2671da177e4SLinus Torvalds {
2681da177e4SLinus Torvalds 	if ((n->nud_state & NUD_IN_TIMER) &&
2691da177e4SLinus Torvalds 	    del_timer(&n->timer)) {
2701da177e4SLinus Torvalds 		neigh_release(n);
2711da177e4SLinus Torvalds 		return 1;
2721da177e4SLinus Torvalds 	}
2731da177e4SLinus Torvalds 	return 0;
2741da177e4SLinus Torvalds }
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds static void pneigh_queue_purge(struct sk_buff_head *list)
2771da177e4SLinus Torvalds {
2781da177e4SLinus Torvalds 	struct sk_buff *skb;
2791da177e4SLinus Torvalds 
2801da177e4SLinus Torvalds 	while ((skb = skb_dequeue(list)) != NULL) {
2811da177e4SLinus Torvalds 		dev_put(skb->dev);
2821da177e4SLinus Torvalds 		kfree_skb(skb);
2831da177e4SLinus Torvalds 	}
2841da177e4SLinus Torvalds }
2851da177e4SLinus Torvalds 
286859bd2efSDavid Ahern static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev,
287859bd2efSDavid Ahern 			    bool skip_perm)
2881da177e4SLinus Torvalds {
2891da177e4SLinus Torvalds 	int i;
290d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
2911da177e4SLinus Torvalds 
292d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
293d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
294d6bf7817SEric Dumazet 
295cd089336SDavid S. Miller 	for (i = 0; i < (1 << nht->hash_shift); i++) {
296767e97e1SEric Dumazet 		struct neighbour *n;
297767e97e1SEric Dumazet 		struct neighbour __rcu **np = &nht->hash_buckets[i];
2981da177e4SLinus Torvalds 
299767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
300767e97e1SEric Dumazet 					lockdep_is_held(&tbl->lock))) != NULL) {
3011da177e4SLinus Torvalds 			if (dev && n->dev != dev) {
3021da177e4SLinus Torvalds 				np = &n->next;
3031da177e4SLinus Torvalds 				continue;
3041da177e4SLinus Torvalds 			}
305859bd2efSDavid Ahern 			if (skip_perm && n->nud_state & NUD_PERMANENT) {
306859bd2efSDavid Ahern 				np = &n->next;
307859bd2efSDavid Ahern 				continue;
308859bd2efSDavid Ahern 			}
309767e97e1SEric Dumazet 			rcu_assign_pointer(*np,
310767e97e1SEric Dumazet 				   rcu_dereference_protected(n->next,
311767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
3121da177e4SLinus Torvalds 			write_lock(&n->lock);
3131da177e4SLinus Torvalds 			neigh_del_timer(n);
31458956317SDavid Ahern 			neigh_mark_dead(n);
3159f237430SReshetova, Elena 			if (refcount_read(&n->refcnt) != 1) {
3161da177e4SLinus Torvalds 				/* The most unpleasant situation.
3171da177e4SLinus Torvalds 				   We must destroy neighbour entry,
3181da177e4SLinus Torvalds 				   but someone still uses it.
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds 				   The destroy will be delayed until
3211da177e4SLinus Torvalds 				   the last user releases us, but
3221da177e4SLinus Torvalds 				   we must kill timers etc. and move
3231da177e4SLinus Torvalds 				   it to safe state.
3241da177e4SLinus Torvalds 				 */
325c9ab4d85SEric Dumazet 				__skb_queue_purge(&n->arp_queue);
3268b5c171bSEric Dumazet 				n->arp_queue_len_bytes = 0;
3271da177e4SLinus Torvalds 				n->output = neigh_blackhole;
3281da177e4SLinus Torvalds 				if (n->nud_state & NUD_VALID)
3291da177e4SLinus Torvalds 					n->nud_state = NUD_NOARP;
3301da177e4SLinus Torvalds 				else
3311da177e4SLinus Torvalds 					n->nud_state = NUD_NONE;
332d5d427cdSJoe Perches 				neigh_dbg(2, "neigh %p is stray\n", n);
3331da177e4SLinus Torvalds 			}
3341da177e4SLinus Torvalds 			write_unlock(&n->lock);
3354f494554SThomas Graf 			neigh_cleanup_and_release(n);
3361da177e4SLinus Torvalds 		}
3371da177e4SLinus Torvalds 	}
33849636bb1SHerbert Xu }
3391da177e4SLinus Torvalds 
34049636bb1SHerbert Xu void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
34149636bb1SHerbert Xu {
34249636bb1SHerbert Xu 	write_lock_bh(&tbl->lock);
343859bd2efSDavid Ahern 	neigh_flush_dev(tbl, dev, false);
34449636bb1SHerbert Xu 	write_unlock_bh(&tbl->lock);
34549636bb1SHerbert Xu }
3460a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_changeaddr);
34749636bb1SHerbert Xu 
348859bd2efSDavid Ahern static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
349859bd2efSDavid Ahern 			  bool skip_perm)
35049636bb1SHerbert Xu {
35149636bb1SHerbert Xu 	write_lock_bh(&tbl->lock);
352859bd2efSDavid Ahern 	neigh_flush_dev(tbl, dev, skip_perm);
35353b76cdfSWolfgang Bumiller 	pneigh_ifdown_and_unlock(tbl, dev);
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds 	del_timer_sync(&tbl->proxy_timer);
3561da177e4SLinus Torvalds 	pneigh_queue_purge(&tbl->proxy_queue);
3571da177e4SLinus Torvalds 	return 0;
3581da177e4SLinus Torvalds }
359859bd2efSDavid Ahern 
360859bd2efSDavid Ahern int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev)
361859bd2efSDavid Ahern {
362859bd2efSDavid Ahern 	__neigh_ifdown(tbl, dev, true);
363859bd2efSDavid Ahern 	return 0;
364859bd2efSDavid Ahern }
365859bd2efSDavid Ahern EXPORT_SYMBOL(neigh_carrier_down);
366859bd2efSDavid Ahern 
367859bd2efSDavid Ahern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
368859bd2efSDavid Ahern {
369859bd2efSDavid Ahern 	__neigh_ifdown(tbl, dev, false);
370859bd2efSDavid Ahern 	return 0;
371859bd2efSDavid Ahern }
3720a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_ifdown);
3731da177e4SLinus Torvalds 
37458956317SDavid Ahern static struct neighbour *neigh_alloc(struct neigh_table *tbl,
37558956317SDavid Ahern 				     struct net_device *dev,
376e997f8a2SDavid Ahern 				     bool exempt_from_gc)
3771da177e4SLinus Torvalds {
3781da177e4SLinus Torvalds 	struct neighbour *n = NULL;
3791da177e4SLinus Torvalds 	unsigned long now = jiffies;
3801da177e4SLinus Torvalds 	int entries;
3811da177e4SLinus Torvalds 
382e997f8a2SDavid Ahern 	if (exempt_from_gc)
38358956317SDavid Ahern 		goto do_alloc;
38458956317SDavid Ahern 
38558956317SDavid Ahern 	entries = atomic_inc_return(&tbl->gc_entries) - 1;
3861da177e4SLinus Torvalds 	if (entries >= tbl->gc_thresh3 ||
3871da177e4SLinus Torvalds 	    (entries >= tbl->gc_thresh2 &&
3881da177e4SLinus Torvalds 	     time_after(now, tbl->last_flush + 5 * HZ))) {
3891da177e4SLinus Torvalds 		if (!neigh_forced_gc(tbl) &&
390fb811395SRick Jones 		    entries >= tbl->gc_thresh3) {
391fb811395SRick Jones 			net_info_ratelimited("%s: neighbor table overflow!\n",
392fb811395SRick Jones 					     tbl->id);
393fb811395SRick Jones 			NEIGH_CACHE_STAT_INC(tbl, table_fulls);
3941da177e4SLinus Torvalds 			goto out_entries;
3951da177e4SLinus Torvalds 		}
396fb811395SRick Jones 	}
3971da177e4SLinus Torvalds 
39858956317SDavid Ahern do_alloc:
39908433effSYOSHIFUJI Hideaki / 吉藤英明 	n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
4001da177e4SLinus Torvalds 	if (!n)
4011da177e4SLinus Torvalds 		goto out_entries;
4021da177e4SLinus Torvalds 
403c9ab4d85SEric Dumazet 	__skb_queue_head_init(&n->arp_queue);
4041da177e4SLinus Torvalds 	rwlock_init(&n->lock);
4050ed8ddf4SEric Dumazet 	seqlock_init(&n->ha_lock);
4061da177e4SLinus Torvalds 	n->updated	  = n->used = now;
4071da177e4SLinus Torvalds 	n->nud_state	  = NUD_NONE;
4081da177e4SLinus Torvalds 	n->output	  = neigh_blackhole;
409f6b72b62SDavid S. Miller 	seqlock_init(&n->hh.hh_lock);
4101da177e4SLinus Torvalds 	n->parms	  = neigh_parms_clone(&tbl->parms);
411e99e88a9SKees Cook 	timer_setup(&n->timer, neigh_timer_handler, 0);
4121da177e4SLinus Torvalds 
4131da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, allocs);
4141da177e4SLinus Torvalds 	n->tbl		  = tbl;
4159f237430SReshetova, Elena 	refcount_set(&n->refcnt, 1);
4161da177e4SLinus Torvalds 	n->dead		  = 1;
41758956317SDavid Ahern 	INIT_LIST_HEAD(&n->gc_list);
41858956317SDavid Ahern 
41958956317SDavid Ahern 	atomic_inc(&tbl->entries);
4201da177e4SLinus Torvalds out:
4211da177e4SLinus Torvalds 	return n;
4221da177e4SLinus Torvalds 
4231da177e4SLinus Torvalds out_entries:
424e997f8a2SDavid Ahern 	if (!exempt_from_gc)
42558956317SDavid Ahern 		atomic_dec(&tbl->gc_entries);
4261da177e4SLinus Torvalds 	goto out;
4271da177e4SLinus Torvalds }
4281da177e4SLinus Torvalds 
4292c2aba6cSDavid S. Miller static void neigh_get_hash_rnd(u32 *x)
4302c2aba6cSDavid S. Miller {
431b3d0f789SJason A. Donenfeld 	*x = get_random_u32() | 1;
4322c2aba6cSDavid S. Miller }
4332c2aba6cSDavid S. Miller 
434cd089336SDavid S. Miller static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
4351da177e4SLinus Torvalds {
436cd089336SDavid S. Miller 	size_t size = (1 << shift) * sizeof(struct neighbour *);
437d6bf7817SEric Dumazet 	struct neigh_hash_table *ret;
4386193d2beSEric Dumazet 	struct neighbour __rcu **buckets;
4392c2aba6cSDavid S. Miller 	int i;
4401da177e4SLinus Torvalds 
441d6bf7817SEric Dumazet 	ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
442d6bf7817SEric Dumazet 	if (!ret)
443d6bf7817SEric Dumazet 		return NULL;
44485704cb8SKonstantin Khlebnikov 	if (size <= PAGE_SIZE) {
445d6bf7817SEric Dumazet 		buckets = kzalloc(size, GFP_ATOMIC);
44685704cb8SKonstantin Khlebnikov 	} else {
4476193d2beSEric Dumazet 		buckets = (struct neighbour __rcu **)
448d6bf7817SEric Dumazet 			  __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
449d6bf7817SEric Dumazet 					   get_order(size));
45001b833abSKonstantin Khlebnikov 		kmemleak_alloc(buckets, size, 1, GFP_ATOMIC);
45185704cb8SKonstantin Khlebnikov 	}
452d6bf7817SEric Dumazet 	if (!buckets) {
453d6bf7817SEric Dumazet 		kfree(ret);
454d6bf7817SEric Dumazet 		return NULL;
4551da177e4SLinus Torvalds 	}
4566193d2beSEric Dumazet 	ret->hash_buckets = buckets;
457cd089336SDavid S. Miller 	ret->hash_shift = shift;
4582c2aba6cSDavid S. Miller 	for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
4592c2aba6cSDavid S. Miller 		neigh_get_hash_rnd(&ret->hash_rnd[i]);
4601da177e4SLinus Torvalds 	return ret;
4611da177e4SLinus Torvalds }
4621da177e4SLinus Torvalds 
463d6bf7817SEric Dumazet static void neigh_hash_free_rcu(struct rcu_head *head)
4641da177e4SLinus Torvalds {
465d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = container_of(head,
466d6bf7817SEric Dumazet 						    struct neigh_hash_table,
467d6bf7817SEric Dumazet 						    rcu);
468cd089336SDavid S. Miller 	size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
4696193d2beSEric Dumazet 	struct neighbour __rcu **buckets = nht->hash_buckets;
4701da177e4SLinus Torvalds 
47185704cb8SKonstantin Khlebnikov 	if (size <= PAGE_SIZE) {
472d6bf7817SEric Dumazet 		kfree(buckets);
47385704cb8SKonstantin Khlebnikov 	} else {
47485704cb8SKonstantin Khlebnikov 		kmemleak_free(buckets);
475d6bf7817SEric Dumazet 		free_pages((unsigned long)buckets, get_order(size));
47685704cb8SKonstantin Khlebnikov 	}
477d6bf7817SEric Dumazet 	kfree(nht);
4781da177e4SLinus Torvalds }
4791da177e4SLinus Torvalds 
480d6bf7817SEric Dumazet static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
481cd089336SDavid S. Miller 						unsigned long new_shift)
4821da177e4SLinus Torvalds {
483d6bf7817SEric Dumazet 	unsigned int i, hash;
484d6bf7817SEric Dumazet 	struct neigh_hash_table *new_nht, *old_nht;
4851da177e4SLinus Torvalds 
4861da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, hash_grows);
4871da177e4SLinus Torvalds 
488d6bf7817SEric Dumazet 	old_nht = rcu_dereference_protected(tbl->nht,
489d6bf7817SEric Dumazet 					    lockdep_is_held(&tbl->lock));
490cd089336SDavid S. Miller 	new_nht = neigh_hash_alloc(new_shift);
491d6bf7817SEric Dumazet 	if (!new_nht)
492d6bf7817SEric Dumazet 		return old_nht;
4931da177e4SLinus Torvalds 
494cd089336SDavid S. Miller 	for (i = 0; i < (1 << old_nht->hash_shift); i++) {
4951da177e4SLinus Torvalds 		struct neighbour *n, *next;
4961da177e4SLinus Torvalds 
497767e97e1SEric Dumazet 		for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
498767e97e1SEric Dumazet 						   lockdep_is_held(&tbl->lock));
499d6bf7817SEric Dumazet 		     n != NULL;
500d6bf7817SEric Dumazet 		     n = next) {
501d6bf7817SEric Dumazet 			hash = tbl->hash(n->primary_key, n->dev,
502d6bf7817SEric Dumazet 					 new_nht->hash_rnd);
5031da177e4SLinus Torvalds 
504cd089336SDavid S. Miller 			hash >>= (32 - new_nht->hash_shift);
505767e97e1SEric Dumazet 			next = rcu_dereference_protected(n->next,
506767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock));
5071da177e4SLinus Torvalds 
508767e97e1SEric Dumazet 			rcu_assign_pointer(n->next,
509767e97e1SEric Dumazet 					   rcu_dereference_protected(
510767e97e1SEric Dumazet 						new_nht->hash_buckets[hash],
511767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
512767e97e1SEric Dumazet 			rcu_assign_pointer(new_nht->hash_buckets[hash], n);
5131da177e4SLinus Torvalds 		}
5141da177e4SLinus Torvalds 	}
5151da177e4SLinus Torvalds 
516d6bf7817SEric Dumazet 	rcu_assign_pointer(tbl->nht, new_nht);
517d6bf7817SEric Dumazet 	call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
518d6bf7817SEric Dumazet 	return new_nht;
5191da177e4SLinus Torvalds }
5201da177e4SLinus Torvalds 
5211da177e4SLinus Torvalds struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
5221da177e4SLinus Torvalds 			       struct net_device *dev)
5231da177e4SLinus Torvalds {
5241da177e4SLinus Torvalds 	struct neighbour *n;
5251da177e4SLinus Torvalds 
5261da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, lookups);
5271da177e4SLinus Torvalds 
528d6bf7817SEric Dumazet 	rcu_read_lock_bh();
52960395a20SEric W. Biederman 	n = __neigh_lookup_noref(tbl, pkey, dev);
53060395a20SEric W. Biederman 	if (n) {
5319f237430SReshetova, Elena 		if (!refcount_inc_not_zero(&n->refcnt))
532767e97e1SEric Dumazet 			n = NULL;
5331da177e4SLinus Torvalds 		NEIGH_CACHE_STAT_INC(tbl, hits);
5341da177e4SLinus Torvalds 	}
535767e97e1SEric Dumazet 
536d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
5371da177e4SLinus Torvalds 	return n;
5381da177e4SLinus Torvalds }
5390a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_lookup);
5401da177e4SLinus Torvalds 
541426b5303SEric W. Biederman struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
542426b5303SEric W. Biederman 				     const void *pkey)
5431da177e4SLinus Torvalds {
5441da177e4SLinus Torvalds 	struct neighbour *n;
54501ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
546bc4bf5f3SPavel Emelyanov 	u32 hash_val;
547d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
5481da177e4SLinus Torvalds 
5491da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, lookups);
5501da177e4SLinus Torvalds 
551d6bf7817SEric Dumazet 	rcu_read_lock_bh();
552d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
553cd089336SDavid S. Miller 	hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
554767e97e1SEric Dumazet 
555767e97e1SEric Dumazet 	for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
556767e97e1SEric Dumazet 	     n != NULL;
557767e97e1SEric Dumazet 	     n = rcu_dereference_bh(n->next)) {
558426b5303SEric W. Biederman 		if (!memcmp(n->primary_key, pkey, key_len) &&
559878628fbSYOSHIFUJI Hideaki 		    net_eq(dev_net(n->dev), net)) {
5609f237430SReshetova, Elena 			if (!refcount_inc_not_zero(&n->refcnt))
561767e97e1SEric Dumazet 				n = NULL;
5621da177e4SLinus Torvalds 			NEIGH_CACHE_STAT_INC(tbl, hits);
5631da177e4SLinus Torvalds 			break;
5641da177e4SLinus Torvalds 		}
5651da177e4SLinus Torvalds 	}
566767e97e1SEric Dumazet 
567d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
5681da177e4SLinus Torvalds 	return n;
5691da177e4SLinus Torvalds }
5700a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_lookup_nodev);
5711da177e4SLinus Torvalds 
57258956317SDavid Ahern static struct neighbour *___neigh_create(struct neigh_table *tbl,
57358956317SDavid Ahern 					 const void *pkey,
57458956317SDavid Ahern 					 struct net_device *dev,
575e997f8a2SDavid Ahern 					 bool exempt_from_gc, bool want_ref)
5761da177e4SLinus Torvalds {
577e997f8a2SDavid Ahern 	struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev, exempt_from_gc);
5781da177e4SLinus Torvalds 	u32 hash_val;
57901ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
5801da177e4SLinus Torvalds 	int error;
581d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
5821da177e4SLinus Torvalds 
583fc651001SDavid Ahern 	trace_neigh_create(tbl, dev, pkey, n, exempt_from_gc);
584fc651001SDavid Ahern 
5851da177e4SLinus Torvalds 	if (!n) {
5861da177e4SLinus Torvalds 		rc = ERR_PTR(-ENOBUFS);
5871da177e4SLinus Torvalds 		goto out;
5881da177e4SLinus Torvalds 	}
5891da177e4SLinus Torvalds 
5901da177e4SLinus Torvalds 	memcpy(n->primary_key, pkey, key_len);
5911da177e4SLinus Torvalds 	n->dev = dev;
5921da177e4SLinus Torvalds 	dev_hold(dev);
5931da177e4SLinus Torvalds 
5941da177e4SLinus Torvalds 	/* Protocol specific setup. */
5951da177e4SLinus Torvalds 	if (tbl->constructor &&	(error = tbl->constructor(n)) < 0) {
5961da177e4SLinus Torvalds 		rc = ERR_PTR(error);
5971da177e4SLinus Torvalds 		goto out_neigh_release;
5981da177e4SLinus Torvalds 	}
5991da177e4SLinus Torvalds 
600da6a8fa0SDavid Miller 	if (dev->netdev_ops->ndo_neigh_construct) {
601503eebc2SJiri Pirko 		error = dev->netdev_ops->ndo_neigh_construct(dev, n);
602da6a8fa0SDavid Miller 		if (error < 0) {
603da6a8fa0SDavid Miller 			rc = ERR_PTR(error);
604da6a8fa0SDavid Miller 			goto out_neigh_release;
605da6a8fa0SDavid Miller 		}
606da6a8fa0SDavid Miller 	}
607da6a8fa0SDavid Miller 
608447f2191SDavid S. Miller 	/* Device specific setup. */
609447f2191SDavid S. Miller 	if (n->parms->neigh_setup &&
610447f2191SDavid S. Miller 	    (error = n->parms->neigh_setup(n)) < 0) {
611447f2191SDavid S. Miller 		rc = ERR_PTR(error);
612447f2191SDavid S. Miller 		goto out_neigh_release;
613447f2191SDavid S. Miller 	}
614447f2191SDavid S. Miller 
6151f9248e5SJiri Pirko 	n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1);
6161da177e4SLinus Torvalds 
6171da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
618d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
619d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
6201da177e4SLinus Torvalds 
621cd089336SDavid S. Miller 	if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
622cd089336SDavid S. Miller 		nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
6231da177e4SLinus Torvalds 
624096b9854SJim Westfall 	hash_val = tbl->hash(n->primary_key, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
6251da177e4SLinus Torvalds 
6261da177e4SLinus Torvalds 	if (n->parms->dead) {
6271da177e4SLinus Torvalds 		rc = ERR_PTR(-EINVAL);
6281da177e4SLinus Torvalds 		goto out_tbl_unlock;
6291da177e4SLinus Torvalds 	}
6301da177e4SLinus Torvalds 
631767e97e1SEric Dumazet 	for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
632767e97e1SEric Dumazet 					    lockdep_is_held(&tbl->lock));
633767e97e1SEric Dumazet 	     n1 != NULL;
634767e97e1SEric Dumazet 	     n1 = rcu_dereference_protected(n1->next,
635767e97e1SEric Dumazet 			lockdep_is_held(&tbl->lock))) {
636096b9854SJim Westfall 		if (dev == n1->dev && !memcmp(n1->primary_key, n->primary_key, key_len)) {
637a263b309SDavid S. Miller 			if (want_ref)
6381da177e4SLinus Torvalds 				neigh_hold(n1);
6391da177e4SLinus Torvalds 			rc = n1;
6401da177e4SLinus Torvalds 			goto out_tbl_unlock;
6411da177e4SLinus Torvalds 		}
6421da177e4SLinus Torvalds 	}
6431da177e4SLinus Torvalds 
6441da177e4SLinus Torvalds 	n->dead = 0;
645e997f8a2SDavid Ahern 	if (!exempt_from_gc)
6468cc196d6SDavid Ahern 		list_add_tail(&n->gc_list, &n->tbl->gc_list);
6478cc196d6SDavid Ahern 
648a263b309SDavid S. Miller 	if (want_ref)
6491da177e4SLinus Torvalds 		neigh_hold(n);
650767e97e1SEric Dumazet 	rcu_assign_pointer(n->next,
651767e97e1SEric Dumazet 			   rcu_dereference_protected(nht->hash_buckets[hash_val],
652767e97e1SEric Dumazet 						     lockdep_is_held(&tbl->lock)));
653767e97e1SEric Dumazet 	rcu_assign_pointer(nht->hash_buckets[hash_val], n);
6541da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
655d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is created\n", n);
6561da177e4SLinus Torvalds 	rc = n;
6571da177e4SLinus Torvalds out:
6581da177e4SLinus Torvalds 	return rc;
6591da177e4SLinus Torvalds out_tbl_unlock:
6601da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
6611da177e4SLinus Torvalds out_neigh_release:
66264c6f4bbSDavid Ahern 	if (!exempt_from_gc)
66364c6f4bbSDavid Ahern 		atomic_dec(&tbl->gc_entries);
6641da177e4SLinus Torvalds 	neigh_release(n);
6651da177e4SLinus Torvalds 	goto out;
6661da177e4SLinus Torvalds }
66758956317SDavid Ahern 
66858956317SDavid Ahern struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
66958956317SDavid Ahern 				 struct net_device *dev, bool want_ref)
67058956317SDavid Ahern {
67158956317SDavid Ahern 	return ___neigh_create(tbl, pkey, dev, false, want_ref);
67258956317SDavid Ahern }
673a263b309SDavid S. Miller EXPORT_SYMBOL(__neigh_create);
6741da177e4SLinus Torvalds 
67501ccdf12SAlexey Dobriyan static u32 pneigh_hash(const void *pkey, unsigned int key_len)
676fa86d322SPavel Emelyanov {
677fa86d322SPavel Emelyanov 	u32 hash_val = *(u32 *)(pkey + key_len - 4);
678fa86d322SPavel Emelyanov 	hash_val ^= (hash_val >> 16);
679fa86d322SPavel Emelyanov 	hash_val ^= hash_val >> 8;
680fa86d322SPavel Emelyanov 	hash_val ^= hash_val >> 4;
681fa86d322SPavel Emelyanov 	hash_val &= PNEIGH_HASHMASK;
682be01d655SYOSHIFUJI Hideaki 	return hash_val;
683fa86d322SPavel Emelyanov }
684fa86d322SPavel Emelyanov 
685be01d655SYOSHIFUJI Hideaki static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
686be01d655SYOSHIFUJI Hideaki 					      struct net *net,
687be01d655SYOSHIFUJI Hideaki 					      const void *pkey,
68801ccdf12SAlexey Dobriyan 					      unsigned int key_len,
689be01d655SYOSHIFUJI Hideaki 					      struct net_device *dev)
690be01d655SYOSHIFUJI Hideaki {
691be01d655SYOSHIFUJI Hideaki 	while (n) {
692be01d655SYOSHIFUJI Hideaki 		if (!memcmp(n->key, pkey, key_len) &&
693be01d655SYOSHIFUJI Hideaki 		    net_eq(pneigh_net(n), net) &&
694be01d655SYOSHIFUJI Hideaki 		    (n->dev == dev || !n->dev))
695fa86d322SPavel Emelyanov 			return n;
696be01d655SYOSHIFUJI Hideaki 		n = n->next;
697be01d655SYOSHIFUJI Hideaki 	}
698be01d655SYOSHIFUJI Hideaki 	return NULL;
699be01d655SYOSHIFUJI Hideaki }
700be01d655SYOSHIFUJI Hideaki 
701be01d655SYOSHIFUJI Hideaki struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
702be01d655SYOSHIFUJI Hideaki 		struct net *net, const void *pkey, struct net_device *dev)
703be01d655SYOSHIFUJI Hideaki {
70401ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
705be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
706be01d655SYOSHIFUJI Hideaki 
707be01d655SYOSHIFUJI Hideaki 	return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
708be01d655SYOSHIFUJI Hideaki 				 net, pkey, key_len, dev);
709fa86d322SPavel Emelyanov }
7100a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL_GPL(__pneigh_lookup);
711fa86d322SPavel Emelyanov 
712426b5303SEric W. Biederman struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
713426b5303SEric W. Biederman 				    struct net *net, const void *pkey,
7141da177e4SLinus Torvalds 				    struct net_device *dev, int creat)
7151da177e4SLinus Torvalds {
7161da177e4SLinus Torvalds 	struct pneigh_entry *n;
71701ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
718be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
7191da177e4SLinus Torvalds 
7201da177e4SLinus Torvalds 	read_lock_bh(&tbl->lock);
721be01d655SYOSHIFUJI Hideaki 	n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
722be01d655SYOSHIFUJI Hideaki 			      net, pkey, key_len, dev);
723be01d655SYOSHIFUJI Hideaki 	read_unlock_bh(&tbl->lock);
7241da177e4SLinus Torvalds 
725be01d655SYOSHIFUJI Hideaki 	if (n || !creat)
7261da177e4SLinus Torvalds 		goto out;
7271da177e4SLinus Torvalds 
7284ae28944SPavel Emelyanov 	ASSERT_RTNL();
7294ae28944SPavel Emelyanov 
7301da177e4SLinus Torvalds 	n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
7311da177e4SLinus Torvalds 	if (!n)
7321da177e4SLinus Torvalds 		goto out;
7331da177e4SLinus Torvalds 
734754d5da6SDavid Ahern 	n->protocol = 0;
735efd7ef1cSEric W. Biederman 	write_pnet(&n->net, net);
7361da177e4SLinus Torvalds 	memcpy(n->key, pkey, key_len);
7371da177e4SLinus Torvalds 	n->dev = dev;
7381da177e4SLinus Torvalds 	if (dev)
7391da177e4SLinus Torvalds 		dev_hold(dev);
7401da177e4SLinus Torvalds 
7411da177e4SLinus Torvalds 	if (tbl->pconstructor && tbl->pconstructor(n)) {
7421da177e4SLinus Torvalds 		if (dev)
7431da177e4SLinus Torvalds 			dev_put(dev);
7441da177e4SLinus Torvalds 		kfree(n);
7451da177e4SLinus Torvalds 		n = NULL;
7461da177e4SLinus Torvalds 		goto out;
7471da177e4SLinus Torvalds 	}
7481da177e4SLinus Torvalds 
7491da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
7501da177e4SLinus Torvalds 	n->next = tbl->phash_buckets[hash_val];
7511da177e4SLinus Torvalds 	tbl->phash_buckets[hash_val] = n;
7521da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
7531da177e4SLinus Torvalds out:
7541da177e4SLinus Torvalds 	return n;
7551da177e4SLinus Torvalds }
7560a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(pneigh_lookup);
7571da177e4SLinus Torvalds 
7581da177e4SLinus Torvalds 
759426b5303SEric W. Biederman int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
7601da177e4SLinus Torvalds 		  struct net_device *dev)
7611da177e4SLinus Torvalds {
7621da177e4SLinus Torvalds 	struct pneigh_entry *n, **np;
76301ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
764be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
7651da177e4SLinus Torvalds 
7661da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
7671da177e4SLinus Torvalds 	for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
7681da177e4SLinus Torvalds 	     np = &n->next) {
769426b5303SEric W. Biederman 		if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
770878628fbSYOSHIFUJI Hideaki 		    net_eq(pneigh_net(n), net)) {
7711da177e4SLinus Torvalds 			*np = n->next;
7721da177e4SLinus Torvalds 			write_unlock_bh(&tbl->lock);
7731da177e4SLinus Torvalds 			if (tbl->pdestructor)
7741da177e4SLinus Torvalds 				tbl->pdestructor(n);
7751da177e4SLinus Torvalds 			if (n->dev)
7761da177e4SLinus Torvalds 				dev_put(n->dev);
7771da177e4SLinus Torvalds 			kfree(n);
7781da177e4SLinus Torvalds 			return 0;
7791da177e4SLinus Torvalds 		}
7801da177e4SLinus Torvalds 	}
7811da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
7821da177e4SLinus Torvalds 	return -ENOENT;
7831da177e4SLinus Torvalds }
7841da177e4SLinus Torvalds 
78553b76cdfSWolfgang Bumiller static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
78653b76cdfSWolfgang Bumiller 				    struct net_device *dev)
7871da177e4SLinus Torvalds {
78853b76cdfSWolfgang Bumiller 	struct pneigh_entry *n, **np, *freelist = NULL;
7891da177e4SLinus Torvalds 	u32 h;
7901da177e4SLinus Torvalds 
7911da177e4SLinus Torvalds 	for (h = 0; h <= PNEIGH_HASHMASK; h++) {
7921da177e4SLinus Torvalds 		np = &tbl->phash_buckets[h];
7931da177e4SLinus Torvalds 		while ((n = *np) != NULL) {
7941da177e4SLinus Torvalds 			if (!dev || n->dev == dev) {
7951da177e4SLinus Torvalds 				*np = n->next;
79653b76cdfSWolfgang Bumiller 				n->next = freelist;
79753b76cdfSWolfgang Bumiller 				freelist = n;
79853b76cdfSWolfgang Bumiller 				continue;
79953b76cdfSWolfgang Bumiller 			}
80053b76cdfSWolfgang Bumiller 			np = &n->next;
80153b76cdfSWolfgang Bumiller 		}
80253b76cdfSWolfgang Bumiller 	}
80353b76cdfSWolfgang Bumiller 	write_unlock_bh(&tbl->lock);
80453b76cdfSWolfgang Bumiller 	while ((n = freelist)) {
80553b76cdfSWolfgang Bumiller 		freelist = n->next;
80653b76cdfSWolfgang Bumiller 		n->next = NULL;
8071da177e4SLinus Torvalds 		if (tbl->pdestructor)
8081da177e4SLinus Torvalds 			tbl->pdestructor(n);
8091da177e4SLinus Torvalds 		if (n->dev)
8101da177e4SLinus Torvalds 			dev_put(n->dev);
8111da177e4SLinus Torvalds 		kfree(n);
8121da177e4SLinus Torvalds 	}
8131da177e4SLinus Torvalds 	return -ENOENT;
8141da177e4SLinus Torvalds }
8151da177e4SLinus Torvalds 
81606f0511dSDenis V. Lunev static void neigh_parms_destroy(struct neigh_parms *parms);
81706f0511dSDenis V. Lunev 
81806f0511dSDenis V. Lunev static inline void neigh_parms_put(struct neigh_parms *parms)
81906f0511dSDenis V. Lunev {
8206343944bSReshetova, Elena 	if (refcount_dec_and_test(&parms->refcnt))
82106f0511dSDenis V. Lunev 		neigh_parms_destroy(parms);
82206f0511dSDenis V. Lunev }
8231da177e4SLinus Torvalds 
8241da177e4SLinus Torvalds /*
8251da177e4SLinus Torvalds  *	neighbour must already be out of the table;
8261da177e4SLinus Torvalds  *
8271da177e4SLinus Torvalds  */
8281da177e4SLinus Torvalds void neigh_destroy(struct neighbour *neigh)
8291da177e4SLinus Torvalds {
830da6a8fa0SDavid Miller 	struct net_device *dev = neigh->dev;
831da6a8fa0SDavid Miller 
8321da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
8331da177e4SLinus Torvalds 
8341da177e4SLinus Torvalds 	if (!neigh->dead) {
835e005d193SJoe Perches 		pr_warn("Destroying alive neighbour %p\n", neigh);
8361da177e4SLinus Torvalds 		dump_stack();
8371da177e4SLinus Torvalds 		return;
8381da177e4SLinus Torvalds 	}
8391da177e4SLinus Torvalds 
8401da177e4SLinus Torvalds 	if (neigh_del_timer(neigh))
841e005d193SJoe Perches 		pr_warn("Impossible event\n");
8421da177e4SLinus Torvalds 
843c9ab4d85SEric Dumazet 	write_lock_bh(&neigh->lock);
844c9ab4d85SEric Dumazet 	__skb_queue_purge(&neigh->arp_queue);
845c9ab4d85SEric Dumazet 	write_unlock_bh(&neigh->lock);
8468b5c171bSEric Dumazet 	neigh->arp_queue_len_bytes = 0;
8471da177e4SLinus Torvalds 
848447f2191SDavid S. Miller 	if (dev->netdev_ops->ndo_neigh_destroy)
849503eebc2SJiri Pirko 		dev->netdev_ops->ndo_neigh_destroy(dev, neigh);
850447f2191SDavid S. Miller 
851da6a8fa0SDavid Miller 	dev_put(dev);
8521da177e4SLinus Torvalds 	neigh_parms_put(neigh->parms);
8531da177e4SLinus Torvalds 
854d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is destroyed\n", neigh);
8551da177e4SLinus Torvalds 
8561da177e4SLinus Torvalds 	atomic_dec(&neigh->tbl->entries);
8575b8b0060SDavid Miller 	kfree_rcu(neigh, rcu);
8581da177e4SLinus Torvalds }
8590a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_destroy);
8601da177e4SLinus Torvalds 
8611da177e4SLinus Torvalds /* Neighbour state is suspicious;
8621da177e4SLinus Torvalds    disable fast path.
8631da177e4SLinus Torvalds 
8641da177e4SLinus Torvalds    Called with write_locked neigh.
8651da177e4SLinus Torvalds  */
8661da177e4SLinus Torvalds static void neigh_suspect(struct neighbour *neigh)
8671da177e4SLinus Torvalds {
868d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is suspected\n", neigh);
8691da177e4SLinus Torvalds 
8701da177e4SLinus Torvalds 	neigh->output = neigh->ops->output;
8711da177e4SLinus Torvalds }
8721da177e4SLinus Torvalds 
8731da177e4SLinus Torvalds /* Neighbour state is OK;
8741da177e4SLinus Torvalds    enable fast path.
8751da177e4SLinus Torvalds 
8761da177e4SLinus Torvalds    Called with write_locked neigh.
8771da177e4SLinus Torvalds  */
8781da177e4SLinus Torvalds static void neigh_connect(struct neighbour *neigh)
8791da177e4SLinus Torvalds {
880d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is connected\n", neigh);
8811da177e4SLinus Torvalds 
8821da177e4SLinus Torvalds 	neigh->output = neigh->ops->connected_output;
8831da177e4SLinus Torvalds }
8841da177e4SLinus Torvalds 
885e4c4e448SEric Dumazet static void neigh_periodic_work(struct work_struct *work)
8861da177e4SLinus Torvalds {
887e4c4e448SEric Dumazet 	struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
888767e97e1SEric Dumazet 	struct neighbour *n;
889767e97e1SEric Dumazet 	struct neighbour __rcu **np;
890e4c4e448SEric Dumazet 	unsigned int i;
891d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
8921da177e4SLinus Torvalds 
8931da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
8941da177e4SLinus Torvalds 
895e4c4e448SEric Dumazet 	write_lock_bh(&tbl->lock);
896d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
897d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
8981da177e4SLinus Torvalds 
8991da177e4SLinus Torvalds 	/*
9001da177e4SLinus Torvalds 	 *	periodically recompute ReachableTime from random function
9011da177e4SLinus Torvalds 	 */
9021da177e4SLinus Torvalds 
903e4c4e448SEric Dumazet 	if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
9041da177e4SLinus Torvalds 		struct neigh_parms *p;
905e4c4e448SEric Dumazet 		tbl->last_rand = jiffies;
90675fbfd33SNicolas Dichtel 		list_for_each_entry(p, &tbl->parms_list, list)
9071da177e4SLinus Torvalds 			p->reachable_time =
9081f9248e5SJiri Pirko 				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
9091da177e4SLinus Torvalds 	}
9101da177e4SLinus Torvalds 
911feff9ab2SDuan Jiong 	if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
912feff9ab2SDuan Jiong 		goto out;
913feff9ab2SDuan Jiong 
914cd089336SDavid S. Miller 	for (i = 0 ; i < (1 << nht->hash_shift); i++) {
915d6bf7817SEric Dumazet 		np = &nht->hash_buckets[i];
9161da177e4SLinus Torvalds 
917767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
918767e97e1SEric Dumazet 				lockdep_is_held(&tbl->lock))) != NULL) {
9191da177e4SLinus Torvalds 			unsigned int state;
9201da177e4SLinus Torvalds 
9211da177e4SLinus Torvalds 			write_lock(&n->lock);
9221da177e4SLinus Torvalds 
9231da177e4SLinus Torvalds 			state = n->nud_state;
9249ce33e46SRoopa Prabhu 			if ((state & (NUD_PERMANENT | NUD_IN_TIMER)) ||
9259ce33e46SRoopa Prabhu 			    (n->flags & NTF_EXT_LEARNED)) {
9261da177e4SLinus Torvalds 				write_unlock(&n->lock);
9271da177e4SLinus Torvalds 				goto next_elt;
9281da177e4SLinus Torvalds 			}
9291da177e4SLinus Torvalds 
9301da177e4SLinus Torvalds 			if (time_before(n->used, n->confirmed))
9311da177e4SLinus Torvalds 				n->used = n->confirmed;
9321da177e4SLinus Torvalds 
9339f237430SReshetova, Elena 			if (refcount_read(&n->refcnt) == 1 &&
9341da177e4SLinus Torvalds 			    (state == NUD_FAILED ||
9351f9248e5SJiri Pirko 			     time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
9361da177e4SLinus Torvalds 				*np = n->next;
93758956317SDavid Ahern 				neigh_mark_dead(n);
9381da177e4SLinus Torvalds 				write_unlock(&n->lock);
9394f494554SThomas Graf 				neigh_cleanup_and_release(n);
9401da177e4SLinus Torvalds 				continue;
9411da177e4SLinus Torvalds 			}
9421da177e4SLinus Torvalds 			write_unlock(&n->lock);
9431da177e4SLinus Torvalds 
9441da177e4SLinus Torvalds next_elt:
9451da177e4SLinus Torvalds 			np = &n->next;
9461da177e4SLinus Torvalds 		}
947e4c4e448SEric Dumazet 		/*
948e4c4e448SEric Dumazet 		 * It's fine to release lock here, even if hash table
949e4c4e448SEric Dumazet 		 * grows while we are preempted.
950e4c4e448SEric Dumazet 		 */
951e4c4e448SEric Dumazet 		write_unlock_bh(&tbl->lock);
952e4c4e448SEric Dumazet 		cond_resched();
953e4c4e448SEric Dumazet 		write_lock_bh(&tbl->lock);
95484338a6cSMichel Machado 		nht = rcu_dereference_protected(tbl->nht,
95584338a6cSMichel Machado 						lockdep_is_held(&tbl->lock));
956e4c4e448SEric Dumazet 	}
9572724680bSYOSHIFUJI Hideaki / 吉藤英明 out:
9581f9248e5SJiri Pirko 	/* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks.
9591f9248e5SJiri Pirko 	 * ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2
9601f9248e5SJiri Pirko 	 * BASE_REACHABLE_TIME.
9611da177e4SLinus Torvalds 	 */
962f618002bSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
9631f9248e5SJiri Pirko 			      NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1);
964e4c4e448SEric Dumazet 	write_unlock_bh(&tbl->lock);
9651da177e4SLinus Torvalds }
9661da177e4SLinus Torvalds 
9671da177e4SLinus Torvalds static __inline__ int neigh_max_probes(struct neighbour *n)
9681da177e4SLinus Torvalds {
9691da177e4SLinus Torvalds 	struct neigh_parms *p = n->parms;
9708da86466SYOSHIFUJI Hideaki/吉藤英明 	return NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) +
9718da86466SYOSHIFUJI Hideaki/吉藤英明 	       (n->nud_state & NUD_PROBE ? NEIGH_VAR(p, MCAST_REPROBES) :
9728da86466SYOSHIFUJI Hideaki/吉藤英明 	        NEIGH_VAR(p, MCAST_PROBES));
9731da177e4SLinus Torvalds }
9741da177e4SLinus Torvalds 
9755ef12d98STimo Teras static void neigh_invalidate(struct neighbour *neigh)
9760a141509SEric Dumazet 	__releases(neigh->lock)
9770a141509SEric Dumazet 	__acquires(neigh->lock)
9785ef12d98STimo Teras {
9795ef12d98STimo Teras 	struct sk_buff *skb;
9805ef12d98STimo Teras 
9815ef12d98STimo Teras 	NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
982d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is failed\n", neigh);
9835ef12d98STimo Teras 	neigh->updated = jiffies;
9845ef12d98STimo Teras 
9855ef12d98STimo Teras 	/* It is very thin place. report_unreachable is very complicated
9865ef12d98STimo Teras 	   routine. Particularly, it can hit the same neighbour entry!
9875ef12d98STimo Teras 
9885ef12d98STimo Teras 	   So that, we try to be accurate and avoid dead loop. --ANK
9895ef12d98STimo Teras 	 */
9905ef12d98STimo Teras 	while (neigh->nud_state == NUD_FAILED &&
9915ef12d98STimo Teras 	       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
9925ef12d98STimo Teras 		write_unlock(&neigh->lock);
9935ef12d98STimo Teras 		neigh->ops->error_report(neigh, skb);
9945ef12d98STimo Teras 		write_lock(&neigh->lock);
9955ef12d98STimo Teras 	}
996c9ab4d85SEric Dumazet 	__skb_queue_purge(&neigh->arp_queue);
9978b5c171bSEric Dumazet 	neigh->arp_queue_len_bytes = 0;
9985ef12d98STimo Teras }
9995ef12d98STimo Teras 
1000cd28ca0aSEric Dumazet static void neigh_probe(struct neighbour *neigh)
1001cd28ca0aSEric Dumazet 	__releases(neigh->lock)
1002cd28ca0aSEric Dumazet {
10034ed377e3SHannes Frederic Sowa 	struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);
1004cd28ca0aSEric Dumazet 	/* keep skb alive even if arp_queue overflows */
1005cd28ca0aSEric Dumazet 	if (skb)
100619125c1aSMartin Zhang 		skb = skb_clone(skb, GFP_ATOMIC);
1007cd28ca0aSEric Dumazet 	write_unlock(&neigh->lock);
100848481c8fSEric Dumazet 	if (neigh->ops->solicit)
1009cd28ca0aSEric Dumazet 		neigh->ops->solicit(neigh, skb);
1010cd28ca0aSEric Dumazet 	atomic_inc(&neigh->probes);
101187fff3caSYang Wei 	consume_skb(skb);
1012cd28ca0aSEric Dumazet }
1013cd28ca0aSEric Dumazet 
10141da177e4SLinus Torvalds /* Called when a timer expires for a neighbour entry. */
10151da177e4SLinus Torvalds 
1016e99e88a9SKees Cook static void neigh_timer_handler(struct timer_list *t)
10171da177e4SLinus Torvalds {
10181da177e4SLinus Torvalds 	unsigned long now, next;
1019e99e88a9SKees Cook 	struct neighbour *neigh = from_timer(neigh, t, timer);
102095c96174SEric Dumazet 	unsigned int state;
10211da177e4SLinus Torvalds 	int notify = 0;
10221da177e4SLinus Torvalds 
10231da177e4SLinus Torvalds 	write_lock(&neigh->lock);
10241da177e4SLinus Torvalds 
10251da177e4SLinus Torvalds 	state = neigh->nud_state;
10261da177e4SLinus Torvalds 	now = jiffies;
10271da177e4SLinus Torvalds 	next = now + HZ;
10281da177e4SLinus Torvalds 
1029045f7b3bSDavid S. Miller 	if (!(state & NUD_IN_TIMER))
10301da177e4SLinus Torvalds 		goto out;
10311da177e4SLinus Torvalds 
10321da177e4SLinus Torvalds 	if (state & NUD_REACHABLE) {
10331da177e4SLinus Torvalds 		if (time_before_eq(now,
10341da177e4SLinus Torvalds 				   neigh->confirmed + neigh->parms->reachable_time)) {
1035d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is still alive\n", neigh);
10361da177e4SLinus Torvalds 			next = neigh->confirmed + neigh->parms->reachable_time;
10371da177e4SLinus Torvalds 		} else if (time_before_eq(now,
10381f9248e5SJiri Pirko 					  neigh->used +
10391f9248e5SJiri Pirko 					  NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
1040d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is delayed\n", neigh);
10411da177e4SLinus Torvalds 			neigh->nud_state = NUD_DELAY;
1042955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10431da177e4SLinus Torvalds 			neigh_suspect(neigh);
10441f9248e5SJiri Pirko 			next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME);
10451da177e4SLinus Torvalds 		} else {
1046d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is suspected\n", neigh);
10471da177e4SLinus Torvalds 			neigh->nud_state = NUD_STALE;
1048955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10491da177e4SLinus Torvalds 			neigh_suspect(neigh);
10508d71740cSTom Tucker 			notify = 1;
10511da177e4SLinus Torvalds 		}
10521da177e4SLinus Torvalds 	} else if (state & NUD_DELAY) {
10531da177e4SLinus Torvalds 		if (time_before_eq(now,
10541f9248e5SJiri Pirko 				   neigh->confirmed +
10551f9248e5SJiri Pirko 				   NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
1056d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is now reachable\n", neigh);
10571da177e4SLinus Torvalds 			neigh->nud_state = NUD_REACHABLE;
1058955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10591da177e4SLinus Torvalds 			neigh_connect(neigh);
10608d71740cSTom Tucker 			notify = 1;
10611da177e4SLinus Torvalds 			next = neigh->confirmed + neigh->parms->reachable_time;
10621da177e4SLinus Torvalds 		} else {
1063d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is probed\n", neigh);
10641da177e4SLinus Torvalds 			neigh->nud_state = NUD_PROBE;
1065955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10661da177e4SLinus Torvalds 			atomic_set(&neigh->probes, 0);
1067765c9c63SErik Kline 			notify = 1;
106819e16d22SHangbin Liu 			next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
106919e16d22SHangbin Liu 					 HZ/100);
10701da177e4SLinus Torvalds 		}
10711da177e4SLinus Torvalds 	} else {
10721da177e4SLinus Torvalds 		/* NUD_PROBE|NUD_INCOMPLETE */
107319e16d22SHangbin Liu 		next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME), HZ/100);
10741da177e4SLinus Torvalds 	}
10751da177e4SLinus Torvalds 
10761da177e4SLinus Torvalds 	if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
10771da177e4SLinus Torvalds 	    atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
10781da177e4SLinus Torvalds 		neigh->nud_state = NUD_FAILED;
10791da177e4SLinus Torvalds 		notify = 1;
10805ef12d98STimo Teras 		neigh_invalidate(neigh);
10815e2c21dcSDuan Jiong 		goto out;
10821da177e4SLinus Torvalds 	}
10831da177e4SLinus Torvalds 
10841da177e4SLinus Torvalds 	if (neigh->nud_state & NUD_IN_TIMER) {
108596d10d5bSHangbin Liu 		if (time_before(next, jiffies + HZ/100))
108696d10d5bSHangbin Liu 			next = jiffies + HZ/100;
10876fb9974fSHerbert Xu 		if (!mod_timer(&neigh->timer, next))
10886fb9974fSHerbert Xu 			neigh_hold(neigh);
10891da177e4SLinus Torvalds 	}
10901da177e4SLinus Torvalds 	if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
1091cd28ca0aSEric Dumazet 		neigh_probe(neigh);
10929ff56607SDavid S. Miller 	} else {
10931da177e4SLinus Torvalds out:
10941da177e4SLinus Torvalds 		write_unlock(&neigh->lock);
10959ff56607SDavid S. Miller 	}
10961da177e4SLinus Torvalds 
1097d961db35SThomas Graf 	if (notify)
10987b8f7a40SRoopa Prabhu 		neigh_update_notify(neigh, 0);
1099d961db35SThomas Graf 
110056dd18a4SRoopa Prabhu 	trace_neigh_timer_handler(neigh, 0);
110156dd18a4SRoopa Prabhu 
11021da177e4SLinus Torvalds 	neigh_release(neigh);
11031da177e4SLinus Torvalds }
11041da177e4SLinus Torvalds 
11051da177e4SLinus Torvalds int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
11061da177e4SLinus Torvalds {
11071da177e4SLinus Torvalds 	int rc;
1108cd28ca0aSEric Dumazet 	bool immediate_probe = false;
11091da177e4SLinus Torvalds 
11101da177e4SLinus Torvalds 	write_lock_bh(&neigh->lock);
11111da177e4SLinus Torvalds 
11121da177e4SLinus Torvalds 	rc = 0;
11131da177e4SLinus Torvalds 	if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
11141da177e4SLinus Torvalds 		goto out_unlock_bh;
11152c51a97fSJulian Anastasov 	if (neigh->dead)
11162c51a97fSJulian Anastasov 		goto out_dead;
11171da177e4SLinus Torvalds 
11181da177e4SLinus Torvalds 	if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
11191f9248e5SJiri Pirko 		if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
11201f9248e5SJiri Pirko 		    NEIGH_VAR(neigh->parms, APP_PROBES)) {
1121cd28ca0aSEric Dumazet 			unsigned long next, now = jiffies;
1122cd28ca0aSEric Dumazet 
11231f9248e5SJiri Pirko 			atomic_set(&neigh->probes,
11241f9248e5SJiri Pirko 				   NEIGH_VAR(neigh->parms, UCAST_PROBES));
1125071c3798SLorenzo Bianconi 			neigh_del_timer(neigh);
11261da177e4SLinus Torvalds 			neigh->nud_state     = NUD_INCOMPLETE;
1127cd28ca0aSEric Dumazet 			neigh->updated = now;
11281f9248e5SJiri Pirko 			next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
112919e16d22SHangbin Liu 					 HZ/100);
1130cd28ca0aSEric Dumazet 			neigh_add_timer(neigh, next);
1131cd28ca0aSEric Dumazet 			immediate_probe = true;
11321da177e4SLinus Torvalds 		} else {
11331da177e4SLinus Torvalds 			neigh->nud_state = NUD_FAILED;
1134955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
11351da177e4SLinus Torvalds 			write_unlock_bh(&neigh->lock);
11361da177e4SLinus Torvalds 
11371da177e4SLinus Torvalds 			kfree_skb(skb);
11381da177e4SLinus Torvalds 			return 1;
11391da177e4SLinus Torvalds 		}
11401da177e4SLinus Torvalds 	} else if (neigh->nud_state & NUD_STALE) {
1141d5d427cdSJoe Perches 		neigh_dbg(2, "neigh %p is delayed\n", neigh);
1142071c3798SLorenzo Bianconi 		neigh_del_timer(neigh);
11431da177e4SLinus Torvalds 		neigh->nud_state = NUD_DELAY;
1144955aaa2fSYOSHIFUJI Hideaki 		neigh->updated = jiffies;
11451f9248e5SJiri Pirko 		neigh_add_timer(neigh, jiffies +
11461f9248e5SJiri Pirko 				NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME));
11471da177e4SLinus Torvalds 	}
11481da177e4SLinus Torvalds 
11491da177e4SLinus Torvalds 	if (neigh->nud_state == NUD_INCOMPLETE) {
11501da177e4SLinus Torvalds 		if (skb) {
11518b5c171bSEric Dumazet 			while (neigh->arp_queue_len_bytes + skb->truesize >
11521f9248e5SJiri Pirko 			       NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) {
11531da177e4SLinus Torvalds 				struct sk_buff *buff;
11548b5c171bSEric Dumazet 
1155f72051b0SDavid S. Miller 				buff = __skb_dequeue(&neigh->arp_queue);
11568b5c171bSEric Dumazet 				if (!buff)
11578b5c171bSEric Dumazet 					break;
11588b5c171bSEric Dumazet 				neigh->arp_queue_len_bytes -= buff->truesize;
11591da177e4SLinus Torvalds 				kfree_skb(buff);
11609a6d276eSNeil Horman 				NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
11611da177e4SLinus Torvalds 			}
1162a4731138SEric Dumazet 			skb_dst_force(skb);
11631da177e4SLinus Torvalds 			__skb_queue_tail(&neigh->arp_queue, skb);
11648b5c171bSEric Dumazet 			neigh->arp_queue_len_bytes += skb->truesize;
11651da177e4SLinus Torvalds 		}
11661da177e4SLinus Torvalds 		rc = 1;
11671da177e4SLinus Torvalds 	}
11681da177e4SLinus Torvalds out_unlock_bh:
1169cd28ca0aSEric Dumazet 	if (immediate_probe)
1170cd28ca0aSEric Dumazet 		neigh_probe(neigh);
1171cd28ca0aSEric Dumazet 	else
1172cd28ca0aSEric Dumazet 		write_unlock(&neigh->lock);
1173cd28ca0aSEric Dumazet 	local_bh_enable();
117456dd18a4SRoopa Prabhu 	trace_neigh_event_send_done(neigh, rc);
11751da177e4SLinus Torvalds 	return rc;
11762c51a97fSJulian Anastasov 
11772c51a97fSJulian Anastasov out_dead:
11782c51a97fSJulian Anastasov 	if (neigh->nud_state & NUD_STALE)
11792c51a97fSJulian Anastasov 		goto out_unlock_bh;
11802c51a97fSJulian Anastasov 	write_unlock_bh(&neigh->lock);
11812c51a97fSJulian Anastasov 	kfree_skb(skb);
118256dd18a4SRoopa Prabhu 	trace_neigh_event_send_dead(neigh, 1);
11832c51a97fSJulian Anastasov 	return 1;
11841da177e4SLinus Torvalds }
11850a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(__neigh_event_send);
11861da177e4SLinus Torvalds 
1187f6b72b62SDavid S. Miller static void neigh_update_hhs(struct neighbour *neigh)
11881da177e4SLinus Torvalds {
11891da177e4SLinus Torvalds 	struct hh_cache *hh;
11903b04dddeSStephen Hemminger 	void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
119191a72a70SDoug Kehn 		= NULL;
119291a72a70SDoug Kehn 
119391a72a70SDoug Kehn 	if (neigh->dev->header_ops)
119491a72a70SDoug Kehn 		update = neigh->dev->header_ops->cache_update;
11951da177e4SLinus Torvalds 
11961da177e4SLinus Torvalds 	if (update) {
1197f6b72b62SDavid S. Miller 		hh = &neigh->hh;
1198c305c6aeSEric Dumazet 		if (READ_ONCE(hh->hh_len)) {
11993644f0ceSStephen Hemminger 			write_seqlock_bh(&hh->hh_lock);
12001da177e4SLinus Torvalds 			update(hh, neigh->dev, neigh->ha);
12013644f0ceSStephen Hemminger 			write_sequnlock_bh(&hh->hh_lock);
12021da177e4SLinus Torvalds 		}
12031da177e4SLinus Torvalds 	}
12041da177e4SLinus Torvalds }
12051da177e4SLinus Torvalds 
12061da177e4SLinus Torvalds 
12071da177e4SLinus Torvalds 
12081da177e4SLinus Torvalds /* Generic update routine.
12091da177e4SLinus Torvalds    -- lladdr is new lladdr or NULL, if it is not supplied.
12101da177e4SLinus Torvalds    -- new    is new state.
12111da177e4SLinus Torvalds    -- flags
12121da177e4SLinus Torvalds 	NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
12131da177e4SLinus Torvalds 				if it is different.
12141da177e4SLinus Torvalds 	NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
12151da177e4SLinus Torvalds 				lladdr instead of overriding it
12161da177e4SLinus Torvalds 				if it is different.
12171da177e4SLinus Torvalds 	NEIGH_UPDATE_F_ADMIN	means that the change is administrative.
12181da177e4SLinus Torvalds 
12191da177e4SLinus Torvalds 	NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
12201da177e4SLinus Torvalds 				NTF_ROUTER flag.
12211da177e4SLinus Torvalds 	NEIGH_UPDATE_F_ISROUTER	indicates if the neighbour is known as
12221da177e4SLinus Torvalds 				a router.
12231da177e4SLinus Torvalds 
12241da177e4SLinus Torvalds    Caller MUST hold reference count on the entry.
12251da177e4SLinus Torvalds  */
12261da177e4SLinus Torvalds 
12277a35a50dSDavid Ahern static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
12287a35a50dSDavid Ahern 			  u8 new, u32 flags, u32 nlmsg_pid,
12297a35a50dSDavid Ahern 			  struct netlink_ext_ack *extack)
12301da177e4SLinus Torvalds {
1231e997f8a2SDavid Ahern 	bool ext_learn_change = false;
12321da177e4SLinus Torvalds 	u8 old;
12331da177e4SLinus Torvalds 	int err;
12341da177e4SLinus Torvalds 	int notify = 0;
12351da177e4SLinus Torvalds 	struct net_device *dev;
12361da177e4SLinus Torvalds 	int update_isrouter = 0;
12371da177e4SLinus Torvalds 
123856dd18a4SRoopa Prabhu 	trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid);
123956dd18a4SRoopa Prabhu 
12401da177e4SLinus Torvalds 	write_lock_bh(&neigh->lock);
12411da177e4SLinus Torvalds 
12421da177e4SLinus Torvalds 	dev    = neigh->dev;
12431da177e4SLinus Torvalds 	old    = neigh->nud_state;
12441da177e4SLinus Torvalds 	err    = -EPERM;
12451da177e4SLinus Torvalds 
12461da177e4SLinus Torvalds 	if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
12471da177e4SLinus Torvalds 	    (old & (NUD_NOARP | NUD_PERMANENT)))
12481da177e4SLinus Torvalds 		goto out;
12497a35a50dSDavid Ahern 	if (neigh->dead) {
12507a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Neighbor entry is now dead");
12512c51a97fSJulian Anastasov 		goto out;
12527a35a50dSDavid Ahern 	}
12531da177e4SLinus Torvalds 
1254e997f8a2SDavid Ahern 	ext_learn_change = neigh_update_ext_learned(neigh, flags, &notify);
12559ce33e46SRoopa Prabhu 
12561da177e4SLinus Torvalds 	if (!(new & NUD_VALID)) {
12571da177e4SLinus Torvalds 		neigh_del_timer(neigh);
12581da177e4SLinus Torvalds 		if (old & NUD_CONNECTED)
12591da177e4SLinus Torvalds 			neigh_suspect(neigh);
12609c29a2f5SDavid Ahern 		neigh->nud_state = new;
12611da177e4SLinus Torvalds 		err = 0;
12621da177e4SLinus Torvalds 		notify = old & NUD_VALID;
1263d2fb4fb8SRoopa Prabhu 		if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
12645ef12d98STimo Teras 		    (new & NUD_FAILED)) {
12655ef12d98STimo Teras 			neigh_invalidate(neigh);
12665ef12d98STimo Teras 			notify = 1;
12675ef12d98STimo Teras 		}
12681da177e4SLinus Torvalds 		goto out;
12691da177e4SLinus Torvalds 	}
12701da177e4SLinus Torvalds 
12711da177e4SLinus Torvalds 	/* Compare new lladdr with cached one */
12721da177e4SLinus Torvalds 	if (!dev->addr_len) {
12731da177e4SLinus Torvalds 		/* First case: device needs no address. */
12741da177e4SLinus Torvalds 		lladdr = neigh->ha;
12751da177e4SLinus Torvalds 	} else if (lladdr) {
12761da177e4SLinus Torvalds 		/* The second case: if something is already cached
12771da177e4SLinus Torvalds 		   and a new address is proposed:
12781da177e4SLinus Torvalds 		   - compare new & old
12791da177e4SLinus Torvalds 		   - if they are different, check override flag
12801da177e4SLinus Torvalds 		 */
12811da177e4SLinus Torvalds 		if ((old & NUD_VALID) &&
12821da177e4SLinus Torvalds 		    !memcmp(lladdr, neigh->ha, dev->addr_len))
12831da177e4SLinus Torvalds 			lladdr = neigh->ha;
12841da177e4SLinus Torvalds 	} else {
12851da177e4SLinus Torvalds 		/* No address is supplied; if we know something,
12861da177e4SLinus Torvalds 		   use it, otherwise discard the request.
12871da177e4SLinus Torvalds 		 */
12881da177e4SLinus Torvalds 		err = -EINVAL;
12897a35a50dSDavid Ahern 		if (!(old & NUD_VALID)) {
12907a35a50dSDavid Ahern 			NL_SET_ERR_MSG(extack, "No link layer address given");
12911da177e4SLinus Torvalds 			goto out;
12927a35a50dSDavid Ahern 		}
12931da177e4SLinus Torvalds 		lladdr = neigh->ha;
12941da177e4SLinus Torvalds 	}
12951da177e4SLinus Torvalds 
1296f0e0d044SVasily Khoruzhick 	/* Update confirmed timestamp for neighbour entry after we
1297f0e0d044SVasily Khoruzhick 	 * received ARP packet even if it doesn't change IP to MAC binding.
1298f0e0d044SVasily Khoruzhick 	 */
1299f0e0d044SVasily Khoruzhick 	if (new & NUD_CONNECTED)
1300f0e0d044SVasily Khoruzhick 		neigh->confirmed = jiffies;
1301f0e0d044SVasily Khoruzhick 
13021da177e4SLinus Torvalds 	/* If entry was valid and address is not changed,
13031da177e4SLinus Torvalds 	   do not change entry state, if new one is STALE.
13041da177e4SLinus Torvalds 	 */
13051da177e4SLinus Torvalds 	err = 0;
13061da177e4SLinus Torvalds 	update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
13071da177e4SLinus Torvalds 	if (old & NUD_VALID) {
13081da177e4SLinus Torvalds 		if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
13091da177e4SLinus Torvalds 			update_isrouter = 0;
13101da177e4SLinus Torvalds 			if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
13111da177e4SLinus Torvalds 			    (old & NUD_CONNECTED)) {
13121da177e4SLinus Torvalds 				lladdr = neigh->ha;
13131da177e4SLinus Torvalds 				new = NUD_STALE;
13141da177e4SLinus Torvalds 			} else
13151da177e4SLinus Torvalds 				goto out;
13161da177e4SLinus Torvalds 		} else {
13170e7bbcc1SJulian Anastasov 			if (lladdr == neigh->ha && new == NUD_STALE &&
13180e7bbcc1SJulian Anastasov 			    !(flags & NEIGH_UPDATE_F_ADMIN))
13191da177e4SLinus Torvalds 				new = old;
13201da177e4SLinus Torvalds 		}
13211da177e4SLinus Torvalds 	}
13221da177e4SLinus Torvalds 
1323f0e0d044SVasily Khoruzhick 	/* Update timestamp only once we know we will make a change to the
132477d71233SIhar Hrachyshka 	 * neighbour entry. Otherwise we risk to move the locktime window with
132577d71233SIhar Hrachyshka 	 * noop updates and ignore relevant ARP updates.
132677d71233SIhar Hrachyshka 	 */
1327f0e0d044SVasily Khoruzhick 	if (new != old || lladdr != neigh->ha)
132877d71233SIhar Hrachyshka 		neigh->updated = jiffies;
132977d71233SIhar Hrachyshka 
13301da177e4SLinus Torvalds 	if (new != old) {
13311da177e4SLinus Torvalds 		neigh_del_timer(neigh);
1332765c9c63SErik Kline 		if (new & NUD_PROBE)
1333765c9c63SErik Kline 			atomic_set(&neigh->probes, 0);
1334a43d8994SPavel Emelyanov 		if (new & NUD_IN_TIMER)
1335667347f1SDavid S. Miller 			neigh_add_timer(neigh, (jiffies +
13361da177e4SLinus Torvalds 						((new & NUD_REACHABLE) ?
1337667347f1SDavid S. Miller 						 neigh->parms->reachable_time :
1338667347f1SDavid S. Miller 						 0)));
13399c29a2f5SDavid Ahern 		neigh->nud_state = new;
134053385d2dSBob Gilligan 		notify = 1;
13411da177e4SLinus Torvalds 	}
13421da177e4SLinus Torvalds 
13431da177e4SLinus Torvalds 	if (lladdr != neigh->ha) {
13440ed8ddf4SEric Dumazet 		write_seqlock(&neigh->ha_lock);
13451da177e4SLinus Torvalds 		memcpy(&neigh->ha, lladdr, dev->addr_len);
13460ed8ddf4SEric Dumazet 		write_sequnlock(&neigh->ha_lock);
13471da177e4SLinus Torvalds 		neigh_update_hhs(neigh);
13481da177e4SLinus Torvalds 		if (!(new & NUD_CONNECTED))
13491da177e4SLinus Torvalds 			neigh->confirmed = jiffies -
13501f9248e5SJiri Pirko 				      (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1);
13511da177e4SLinus Torvalds 		notify = 1;
13521da177e4SLinus Torvalds 	}
13531da177e4SLinus Torvalds 	if (new == old)
13541da177e4SLinus Torvalds 		goto out;
13551da177e4SLinus Torvalds 	if (new & NUD_CONNECTED)
13561da177e4SLinus Torvalds 		neigh_connect(neigh);
13571da177e4SLinus Torvalds 	else
13581da177e4SLinus Torvalds 		neigh_suspect(neigh);
13591da177e4SLinus Torvalds 	if (!(old & NUD_VALID)) {
13601da177e4SLinus Torvalds 		struct sk_buff *skb;
13611da177e4SLinus Torvalds 
13621da177e4SLinus Torvalds 		/* Again: avoid dead loop if something went wrong */
13631da177e4SLinus Torvalds 
13641da177e4SLinus Torvalds 		while (neigh->nud_state & NUD_VALID &&
13651da177e4SLinus Torvalds 		       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
136669cce1d1SDavid S. Miller 			struct dst_entry *dst = skb_dst(skb);
136769cce1d1SDavid S. Miller 			struct neighbour *n2, *n1 = neigh;
13681da177e4SLinus Torvalds 			write_unlock_bh(&neigh->lock);
1369e049f288Sroy.qing.li@gmail.com 
1370e049f288Sroy.qing.li@gmail.com 			rcu_read_lock();
137113a43d94SDavid S. Miller 
137213a43d94SDavid S. Miller 			/* Why not just use 'neigh' as-is?  The problem is that
137313a43d94SDavid S. Miller 			 * things such as shaper, eql, and sch_teql can end up
137413a43d94SDavid S. Miller 			 * using alternative, different, neigh objects to output
137513a43d94SDavid S. Miller 			 * the packet in the output path.  So what we need to do
137613a43d94SDavid S. Miller 			 * here is re-lookup the top-level neigh in the path so
137713a43d94SDavid S. Miller 			 * we can reinject the packet there.
137813a43d94SDavid S. Miller 			 */
137913a43d94SDavid S. Miller 			n2 = NULL;
138013a43d94SDavid S. Miller 			if (dst) {
138113a43d94SDavid S. Miller 				n2 = dst_neigh_lookup_skb(dst, skb);
138213a43d94SDavid S. Miller 				if (n2)
138369cce1d1SDavid S. Miller 					n1 = n2;
138413a43d94SDavid S. Miller 			}
13858f40b161SDavid S. Miller 			n1->output(n1, skb);
138613a43d94SDavid S. Miller 			if (n2)
138713a43d94SDavid S. Miller 				neigh_release(n2);
1388e049f288Sroy.qing.li@gmail.com 			rcu_read_unlock();
1389e049f288Sroy.qing.li@gmail.com 
13901da177e4SLinus Torvalds 			write_lock_bh(&neigh->lock);
13911da177e4SLinus Torvalds 		}
1392c9ab4d85SEric Dumazet 		__skb_queue_purge(&neigh->arp_queue);
13938b5c171bSEric Dumazet 		neigh->arp_queue_len_bytes = 0;
13941da177e4SLinus Torvalds 	}
13951da177e4SLinus Torvalds out:
1396fc6e8073SRoopa Prabhu 	if (update_isrouter)
1397fc6e8073SRoopa Prabhu 		neigh_update_is_router(neigh, flags, &notify);
13981da177e4SLinus Torvalds 	write_unlock_bh(&neigh->lock);
13998d71740cSTom Tucker 
1400e997f8a2SDavid Ahern 	if (((new ^ old) & NUD_PERMANENT) || ext_learn_change)
14019c29a2f5SDavid Ahern 		neigh_update_gc_list(neigh);
14029c29a2f5SDavid Ahern 
14038d71740cSTom Tucker 	if (notify)
14047b8f7a40SRoopa Prabhu 		neigh_update_notify(neigh, nlmsg_pid);
1405d961db35SThomas Graf 
140656dd18a4SRoopa Prabhu 	trace_neigh_update_done(neigh, err);
140756dd18a4SRoopa Prabhu 
14081da177e4SLinus Torvalds 	return err;
14091da177e4SLinus Torvalds }
14107a35a50dSDavid Ahern 
14117a35a50dSDavid Ahern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
14127a35a50dSDavid Ahern 		 u32 flags, u32 nlmsg_pid)
14137a35a50dSDavid Ahern {
14147a35a50dSDavid Ahern 	return __neigh_update(neigh, lladdr, new, flags, nlmsg_pid, NULL);
14157a35a50dSDavid Ahern }
14160a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_update);
14171da177e4SLinus Torvalds 
14187e980569SJiri Benc /* Update the neigh to listen temporarily for probe responses, even if it is
14197e980569SJiri Benc  * in a NUD_FAILED state. The caller has to hold neigh->lock for writing.
14207e980569SJiri Benc  */
14217e980569SJiri Benc void __neigh_set_probe_once(struct neighbour *neigh)
14227e980569SJiri Benc {
14232c51a97fSJulian Anastasov 	if (neigh->dead)
14242c51a97fSJulian Anastasov 		return;
14257e980569SJiri Benc 	neigh->updated = jiffies;
14267e980569SJiri Benc 	if (!(neigh->nud_state & NUD_FAILED))
14277e980569SJiri Benc 		return;
14282176d5d4SDuan Jiong 	neigh->nud_state = NUD_INCOMPLETE;
14292176d5d4SDuan Jiong 	atomic_set(&neigh->probes, neigh_max_probes(neigh));
14307e980569SJiri Benc 	neigh_add_timer(neigh,
143119e16d22SHangbin Liu 			jiffies + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
143219e16d22SHangbin Liu 				      HZ/100));
14337e980569SJiri Benc }
14347e980569SJiri Benc EXPORT_SYMBOL(__neigh_set_probe_once);
14357e980569SJiri Benc 
14361da177e4SLinus Torvalds struct neighbour *neigh_event_ns(struct neigh_table *tbl,
14371da177e4SLinus Torvalds 				 u8 *lladdr, void *saddr,
14381da177e4SLinus Torvalds 				 struct net_device *dev)
14391da177e4SLinus Torvalds {
14401da177e4SLinus Torvalds 	struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
14411da177e4SLinus Torvalds 						 lladdr || !dev->addr_len);
14421da177e4SLinus Torvalds 	if (neigh)
14431da177e4SLinus Torvalds 		neigh_update(neigh, lladdr, NUD_STALE,
14447b8f7a40SRoopa Prabhu 			     NEIGH_UPDATE_F_OVERRIDE, 0);
14451da177e4SLinus Torvalds 	return neigh;
14461da177e4SLinus Torvalds }
14470a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_event_ns);
14481da177e4SLinus Torvalds 
144934d101ddSEric Dumazet /* called with read_lock_bh(&n->lock); */
1450bdf53c58SEric W. Biederman static void neigh_hh_init(struct neighbour *n)
14511da177e4SLinus Torvalds {
1452bdf53c58SEric W. Biederman 	struct net_device *dev = n->dev;
1453bdf53c58SEric W. Biederman 	__be16 prot = n->tbl->protocol;
1454f6b72b62SDavid S. Miller 	struct hh_cache	*hh = &n->hh;
14550ed8ddf4SEric Dumazet 
14560ed8ddf4SEric Dumazet 	write_lock_bh(&n->lock);
145734d101ddSEric Dumazet 
1458f6b72b62SDavid S. Miller 	/* Only one thread can come in here and initialize the
1459f6b72b62SDavid S. Miller 	 * hh_cache entry.
1460f6b72b62SDavid S. Miller 	 */
1461b23b5455SDavid S. Miller 	if (!hh->hh_len)
1462b23b5455SDavid S. Miller 		dev->header_ops->cache(n, hh, prot);
1463f6b72b62SDavid S. Miller 
14640ed8ddf4SEric Dumazet 	write_unlock_bh(&n->lock);
14651da177e4SLinus Torvalds }
14661da177e4SLinus Torvalds 
14671da177e4SLinus Torvalds /* Slow and careful. */
14681da177e4SLinus Torvalds 
14698f40b161SDavid S. Miller int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
14701da177e4SLinus Torvalds {
14711da177e4SLinus Torvalds 	int rc = 0;
14721da177e4SLinus Torvalds 
14731da177e4SLinus Torvalds 	if (!neigh_event_send(neigh, skb)) {
14741da177e4SLinus Torvalds 		int err;
14751da177e4SLinus Torvalds 		struct net_device *dev = neigh->dev;
14760ed8ddf4SEric Dumazet 		unsigned int seq;
147734d101ddSEric Dumazet 
1478c305c6aeSEric Dumazet 		if (dev->header_ops->cache && !READ_ONCE(neigh->hh.hh_len))
1479bdf53c58SEric W. Biederman 			neigh_hh_init(neigh);
148034d101ddSEric Dumazet 
14810ed8ddf4SEric Dumazet 		do {
1482e1f16503Sramesh.nagappa@gmail.com 			__skb_pull(skb, skb_network_offset(skb));
14830ed8ddf4SEric Dumazet 			seq = read_seqbegin(&neigh->ha_lock);
14840c4e8581SStephen Hemminger 			err = dev_hard_header(skb, dev, ntohs(skb->protocol),
14851da177e4SLinus Torvalds 					      neigh->ha, NULL, skb->len);
14860ed8ddf4SEric Dumazet 		} while (read_seqretry(&neigh->ha_lock, seq));
148734d101ddSEric Dumazet 
14881da177e4SLinus Torvalds 		if (err >= 0)
1489542d4d68SDavid S. Miller 			rc = dev_queue_xmit(skb);
14901da177e4SLinus Torvalds 		else
14911da177e4SLinus Torvalds 			goto out_kfree_skb;
14921da177e4SLinus Torvalds 	}
14931da177e4SLinus Torvalds out:
14941da177e4SLinus Torvalds 	return rc;
14951da177e4SLinus Torvalds out_kfree_skb:
14961da177e4SLinus Torvalds 	rc = -EINVAL;
14971da177e4SLinus Torvalds 	kfree_skb(skb);
14981da177e4SLinus Torvalds 	goto out;
14991da177e4SLinus Torvalds }
15000a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_resolve_output);
15011da177e4SLinus Torvalds 
15021da177e4SLinus Torvalds /* As fast as possible without hh cache */
15031da177e4SLinus Torvalds 
15048f40b161SDavid S. Miller int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
15051da177e4SLinus Torvalds {
15061da177e4SLinus Torvalds 	struct net_device *dev = neigh->dev;
15070ed8ddf4SEric Dumazet 	unsigned int seq;
15088f40b161SDavid S. Miller 	int err;
15091da177e4SLinus Torvalds 
15100ed8ddf4SEric Dumazet 	do {
1511e1f16503Sramesh.nagappa@gmail.com 		__skb_pull(skb, skb_network_offset(skb));
15120ed8ddf4SEric Dumazet 		seq = read_seqbegin(&neigh->ha_lock);
15130c4e8581SStephen Hemminger 		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
15141da177e4SLinus Torvalds 				      neigh->ha, NULL, skb->len);
15150ed8ddf4SEric Dumazet 	} while (read_seqretry(&neigh->ha_lock, seq));
15160ed8ddf4SEric Dumazet 
15171da177e4SLinus Torvalds 	if (err >= 0)
1518542d4d68SDavid S. Miller 		err = dev_queue_xmit(skb);
15191da177e4SLinus Torvalds 	else {
15201da177e4SLinus Torvalds 		err = -EINVAL;
15211da177e4SLinus Torvalds 		kfree_skb(skb);
15221da177e4SLinus Torvalds 	}
15231da177e4SLinus Torvalds 	return err;
15241da177e4SLinus Torvalds }
15250a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_connected_output);
15261da177e4SLinus Torvalds 
15278f40b161SDavid S. Miller int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
15288f40b161SDavid S. Miller {
15298f40b161SDavid S. Miller 	return dev_queue_xmit(skb);
15308f40b161SDavid S. Miller }
15318f40b161SDavid S. Miller EXPORT_SYMBOL(neigh_direct_output);
15328f40b161SDavid S. Miller 
1533e99e88a9SKees Cook static void neigh_proxy_process(struct timer_list *t)
15341da177e4SLinus Torvalds {
1535e99e88a9SKees Cook 	struct neigh_table *tbl = from_timer(tbl, t, proxy_timer);
15361da177e4SLinus Torvalds 	long sched_next = 0;
15371da177e4SLinus Torvalds 	unsigned long now = jiffies;
1538f72051b0SDavid S. Miller 	struct sk_buff *skb, *n;
15391da177e4SLinus Torvalds 
15401da177e4SLinus Torvalds 	spin_lock(&tbl->proxy_queue.lock);
15411da177e4SLinus Torvalds 
1542f72051b0SDavid S. Miller 	skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1543f72051b0SDavid S. Miller 		long tdif = NEIGH_CB(skb)->sched_next - now;
15441da177e4SLinus Torvalds 
15451da177e4SLinus Torvalds 		if (tdif <= 0) {
1546f72051b0SDavid S. Miller 			struct net_device *dev = skb->dev;
154720e6074eSEric Dumazet 
1548f72051b0SDavid S. Miller 			__skb_unlink(skb, &tbl->proxy_queue);
154920e6074eSEric Dumazet 			if (tbl->proxy_redo && netif_running(dev)) {
155020e6074eSEric Dumazet 				rcu_read_lock();
1551f72051b0SDavid S. Miller 				tbl->proxy_redo(skb);
155220e6074eSEric Dumazet 				rcu_read_unlock();
155320e6074eSEric Dumazet 			} else {
1554f72051b0SDavid S. Miller 				kfree_skb(skb);
155520e6074eSEric Dumazet 			}
15561da177e4SLinus Torvalds 
15571da177e4SLinus Torvalds 			dev_put(dev);
15581da177e4SLinus Torvalds 		} else if (!sched_next || tdif < sched_next)
15591da177e4SLinus Torvalds 			sched_next = tdif;
15601da177e4SLinus Torvalds 	}
15611da177e4SLinus Torvalds 	del_timer(&tbl->proxy_timer);
15621da177e4SLinus Torvalds 	if (sched_next)
15631da177e4SLinus Torvalds 		mod_timer(&tbl->proxy_timer, jiffies + sched_next);
15641da177e4SLinus Torvalds 	spin_unlock(&tbl->proxy_queue.lock);
15651da177e4SLinus Torvalds }
15661da177e4SLinus Torvalds 
15671da177e4SLinus Torvalds void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
15681da177e4SLinus Torvalds 		    struct sk_buff *skb)
15691da177e4SLinus Torvalds {
15701da177e4SLinus Torvalds 	unsigned long now = jiffies;
157163862b5bSAruna-Hewapathirane 
157263862b5bSAruna-Hewapathirane 	unsigned long sched_next = now + (prandom_u32() %
15731f9248e5SJiri Pirko 					  NEIGH_VAR(p, PROXY_DELAY));
15741da177e4SLinus Torvalds 
15751f9248e5SJiri Pirko 	if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) {
15761da177e4SLinus Torvalds 		kfree_skb(skb);
15771da177e4SLinus Torvalds 		return;
15781da177e4SLinus Torvalds 	}
1579a61bbcf2SPatrick McHardy 
1580a61bbcf2SPatrick McHardy 	NEIGH_CB(skb)->sched_next = sched_next;
1581a61bbcf2SPatrick McHardy 	NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
15821da177e4SLinus Torvalds 
15831da177e4SLinus Torvalds 	spin_lock(&tbl->proxy_queue.lock);
15841da177e4SLinus Torvalds 	if (del_timer(&tbl->proxy_timer)) {
15851da177e4SLinus Torvalds 		if (time_before(tbl->proxy_timer.expires, sched_next))
15861da177e4SLinus Torvalds 			sched_next = tbl->proxy_timer.expires;
15871da177e4SLinus Torvalds 	}
1588adf30907SEric Dumazet 	skb_dst_drop(skb);
15891da177e4SLinus Torvalds 	dev_hold(skb->dev);
15901da177e4SLinus Torvalds 	__skb_queue_tail(&tbl->proxy_queue, skb);
15911da177e4SLinus Torvalds 	mod_timer(&tbl->proxy_timer, sched_next);
15921da177e4SLinus Torvalds 	spin_unlock(&tbl->proxy_queue.lock);
15931da177e4SLinus Torvalds }
15940a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(pneigh_enqueue);
15951da177e4SLinus Torvalds 
159697fd5bc7STobias Klauser static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
1597426b5303SEric W. Biederman 						      struct net *net, int ifindex)
1598426b5303SEric W. Biederman {
1599426b5303SEric W. Biederman 	struct neigh_parms *p;
1600426b5303SEric W. Biederman 
160175fbfd33SNicolas Dichtel 	list_for_each_entry(p, &tbl->parms_list, list) {
1602878628fbSYOSHIFUJI Hideaki 		if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
1603170d6f99SGao feng 		    (!p->dev && !ifindex && net_eq(net, &init_net)))
1604426b5303SEric W. Biederman 			return p;
1605426b5303SEric W. Biederman 	}
1606426b5303SEric W. Biederman 
1607426b5303SEric W. Biederman 	return NULL;
1608426b5303SEric W. Biederman }
16091da177e4SLinus Torvalds 
16101da177e4SLinus Torvalds struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
16111da177e4SLinus Torvalds 				      struct neigh_table *tbl)
16121da177e4SLinus Torvalds {
1613cf89d6b2SGao feng 	struct neigh_parms *p;
161400829823SStephen Hemminger 	struct net *net = dev_net(dev);
161500829823SStephen Hemminger 	const struct net_device_ops *ops = dev->netdev_ops;
16161da177e4SLinus Torvalds 
1617cf89d6b2SGao feng 	p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL);
16181da177e4SLinus Torvalds 	if (p) {
16191da177e4SLinus Torvalds 		p->tbl		  = tbl;
16206343944bSReshetova, Elena 		refcount_set(&p->refcnt, 1);
16211da177e4SLinus Torvalds 		p->reachable_time =
16221f9248e5SJiri Pirko 				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
1623c7fb64dbSThomas Graf 		dev_hold(dev);
1624c7fb64dbSThomas Graf 		p->dev = dev;
1625efd7ef1cSEric W. Biederman 		write_pnet(&p->net, net);
16261da177e4SLinus Torvalds 		p->sysctl_table = NULL;
162763134803SVeaceslav Falico 
162863134803SVeaceslav Falico 		if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
162963134803SVeaceslav Falico 			dev_put(dev);
163063134803SVeaceslav Falico 			kfree(p);
163163134803SVeaceslav Falico 			return NULL;
163263134803SVeaceslav Falico 		}
163363134803SVeaceslav Falico 
16341da177e4SLinus Torvalds 		write_lock_bh(&tbl->lock);
163575fbfd33SNicolas Dichtel 		list_add(&p->list, &tbl->parms.list);
16361da177e4SLinus Torvalds 		write_unlock_bh(&tbl->lock);
16371d4c8c29SJiri Pirko 
16381d4c8c29SJiri Pirko 		neigh_parms_data_state_cleanall(p);
16391da177e4SLinus Torvalds 	}
16401da177e4SLinus Torvalds 	return p;
16411da177e4SLinus Torvalds }
16420a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_parms_alloc);
16431da177e4SLinus Torvalds 
16441da177e4SLinus Torvalds static void neigh_rcu_free_parms(struct rcu_head *head)
16451da177e4SLinus Torvalds {
16461da177e4SLinus Torvalds 	struct neigh_parms *parms =
16471da177e4SLinus Torvalds 		container_of(head, struct neigh_parms, rcu_head);
16481da177e4SLinus Torvalds 
16491da177e4SLinus Torvalds 	neigh_parms_put(parms);
16501da177e4SLinus Torvalds }
16511da177e4SLinus Torvalds 
16521da177e4SLinus Torvalds void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
16531da177e4SLinus Torvalds {
16541da177e4SLinus Torvalds 	if (!parms || parms == &tbl->parms)
16551da177e4SLinus Torvalds 		return;
16561da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
165775fbfd33SNicolas Dichtel 	list_del(&parms->list);
16581da177e4SLinus Torvalds 	parms->dead = 1;
16591da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
1660cecbb639SDavid S. Miller 	if (parms->dev)
1661cecbb639SDavid S. Miller 		dev_put(parms->dev);
16621da177e4SLinus Torvalds 	call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
16631da177e4SLinus Torvalds }
16640a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_parms_release);
16651da177e4SLinus Torvalds 
166606f0511dSDenis V. Lunev static void neigh_parms_destroy(struct neigh_parms *parms)
16671da177e4SLinus Torvalds {
16681da177e4SLinus Torvalds 	kfree(parms);
16691da177e4SLinus Torvalds }
16701da177e4SLinus Torvalds 
1671c2ecba71SPavel Emelianov static struct lock_class_key neigh_table_proxy_queue_class;
1672c2ecba71SPavel Emelianov 
1673d7480fd3SWANG Cong static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly;
1674d7480fd3SWANG Cong 
1675d7480fd3SWANG Cong void neigh_table_init(int index, struct neigh_table *tbl)
16761da177e4SLinus Torvalds {
16771da177e4SLinus Torvalds 	unsigned long now = jiffies;
16781da177e4SLinus Torvalds 	unsigned long phsize;
16791da177e4SLinus Torvalds 
168075fbfd33SNicolas Dichtel 	INIT_LIST_HEAD(&tbl->parms_list);
168158956317SDavid Ahern 	INIT_LIST_HEAD(&tbl->gc_list);
168275fbfd33SNicolas Dichtel 	list_add(&tbl->parms.list, &tbl->parms_list);
1683e42ea986SEric Dumazet 	write_pnet(&tbl->parms.net, &init_net);
16846343944bSReshetova, Elena 	refcount_set(&tbl->parms.refcnt, 1);
16851da177e4SLinus Torvalds 	tbl->parms.reachable_time =
16861f9248e5SJiri Pirko 			  neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME));
16871da177e4SLinus Torvalds 
16881da177e4SLinus Torvalds 	tbl->stats = alloc_percpu(struct neigh_statistics);
16891da177e4SLinus Torvalds 	if (!tbl->stats)
16901da177e4SLinus Torvalds 		panic("cannot create neighbour cache statistics");
16911da177e4SLinus Torvalds 
16921da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
169371a5053aSChristoph Hellwig 	if (!proc_create_seq_data(tbl->id, 0, init_net.proc_net_stat,
169471a5053aSChristoph Hellwig 			      &neigh_stat_seq_ops, tbl))
16951da177e4SLinus Torvalds 		panic("cannot create neighbour proc dir entry");
16961da177e4SLinus Torvalds #endif
16971da177e4SLinus Torvalds 
1698cd089336SDavid S. Miller 	RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
16991da177e4SLinus Torvalds 
17001da177e4SLinus Torvalds 	phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
170177d04bd9SAndrew Morton 	tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
17021da177e4SLinus Torvalds 
1703d6bf7817SEric Dumazet 	if (!tbl->nht || !tbl->phash_buckets)
17041da177e4SLinus Torvalds 		panic("cannot allocate neighbour cache hashes");
17051da177e4SLinus Torvalds 
170608433effSYOSHIFUJI Hideaki / 吉藤英明 	if (!tbl->entry_size)
170708433effSYOSHIFUJI Hideaki / 吉藤英明 		tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
170808433effSYOSHIFUJI Hideaki / 吉藤英明 					tbl->key_len, NEIGH_PRIV_ALIGN);
170908433effSYOSHIFUJI Hideaki / 吉藤英明 	else
171008433effSYOSHIFUJI Hideaki / 吉藤英明 		WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
171108433effSYOSHIFUJI Hideaki / 吉藤英明 
17121da177e4SLinus Torvalds 	rwlock_init(&tbl->lock);
1713203b42f7STejun Heo 	INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
1714f618002bSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
1715f618002bSviresh kumar 			tbl->parms.reachable_time);
1716e99e88a9SKees Cook 	timer_setup(&tbl->proxy_timer, neigh_proxy_process, 0);
1717c2ecba71SPavel Emelianov 	skb_queue_head_init_class(&tbl->proxy_queue,
1718c2ecba71SPavel Emelianov 			&neigh_table_proxy_queue_class);
17191da177e4SLinus Torvalds 
17201da177e4SLinus Torvalds 	tbl->last_flush = now;
17211da177e4SLinus Torvalds 	tbl->last_rand	= now + tbl->parms.reachable_time * 20;
1722bd89efc5SSimon Kelley 
1723d7480fd3SWANG Cong 	neigh_tables[index] = tbl;
17241da177e4SLinus Torvalds }
17250a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_table_init);
17261da177e4SLinus Torvalds 
1727d7480fd3SWANG Cong int neigh_table_clear(int index, struct neigh_table *tbl)
17281da177e4SLinus Torvalds {
1729d7480fd3SWANG Cong 	neigh_tables[index] = NULL;
17301da177e4SLinus Torvalds 	/* It is not clean... Fix it to unload IPv6 module safely */
1731a5c30b34STejun Heo 	cancel_delayed_work_sync(&tbl->gc_work);
17321da177e4SLinus Torvalds 	del_timer_sync(&tbl->proxy_timer);
17331da177e4SLinus Torvalds 	pneigh_queue_purge(&tbl->proxy_queue);
17341da177e4SLinus Torvalds 	neigh_ifdown(tbl, NULL);
17351da177e4SLinus Torvalds 	if (atomic_read(&tbl->entries))
1736e005d193SJoe Perches 		pr_crit("neighbour leakage\n");
17371da177e4SLinus Torvalds 
17386193d2beSEric Dumazet 	call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
17396193d2beSEric Dumazet 		 neigh_hash_free_rcu);
1740d6bf7817SEric Dumazet 	tbl->nht = NULL;
17411da177e4SLinus Torvalds 
17421da177e4SLinus Torvalds 	kfree(tbl->phash_buckets);
17431da177e4SLinus Torvalds 	tbl->phash_buckets = NULL;
17441da177e4SLinus Torvalds 
17453f192b5cSAlexey Dobriyan 	remove_proc_entry(tbl->id, init_net.proc_net_stat);
17463f192b5cSAlexey Dobriyan 
17473fcde74bSKirill Korotaev 	free_percpu(tbl->stats);
17483fcde74bSKirill Korotaev 	tbl->stats = NULL;
17493fcde74bSKirill Korotaev 
17501da177e4SLinus Torvalds 	return 0;
17511da177e4SLinus Torvalds }
17520a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_table_clear);
17531da177e4SLinus Torvalds 
1754d7480fd3SWANG Cong static struct neigh_table *neigh_find_table(int family)
1755d7480fd3SWANG Cong {
1756d7480fd3SWANG Cong 	struct neigh_table *tbl = NULL;
1757d7480fd3SWANG Cong 
1758d7480fd3SWANG Cong 	switch (family) {
1759d7480fd3SWANG Cong 	case AF_INET:
1760d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_ARP_TABLE];
1761d7480fd3SWANG Cong 		break;
1762d7480fd3SWANG Cong 	case AF_INET6:
1763d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_ND_TABLE];
1764d7480fd3SWANG Cong 		break;
1765d7480fd3SWANG Cong 	case AF_DECnet:
1766d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_DN_TABLE];
1767d7480fd3SWANG Cong 		break;
1768d7480fd3SWANG Cong 	}
1769d7480fd3SWANG Cong 
1770d7480fd3SWANG Cong 	return tbl;
1771d7480fd3SWANG Cong }
1772d7480fd3SWANG Cong 
177382cbb5c6SRoopa Prabhu const struct nla_policy nda_policy[NDA_MAX+1] = {
17741274e1ccSRoopa Prabhu 	[NDA_UNSPEC]		= { .strict_start_type = NDA_NH_ID },
177582cbb5c6SRoopa Prabhu 	[NDA_DST]		= { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
177682cbb5c6SRoopa Prabhu 	[NDA_LLADDR]		= { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
177782cbb5c6SRoopa Prabhu 	[NDA_CACHEINFO]		= { .len = sizeof(struct nda_cacheinfo) },
177882cbb5c6SRoopa Prabhu 	[NDA_PROBES]		= { .type = NLA_U32 },
177982cbb5c6SRoopa Prabhu 	[NDA_VLAN]		= { .type = NLA_U16 },
178082cbb5c6SRoopa Prabhu 	[NDA_PORT]		= { .type = NLA_U16 },
178182cbb5c6SRoopa Prabhu 	[NDA_VNI]		= { .type = NLA_U32 },
178282cbb5c6SRoopa Prabhu 	[NDA_IFINDEX]		= { .type = NLA_U32 },
178382cbb5c6SRoopa Prabhu 	[NDA_MASTER]		= { .type = NLA_U32 },
1784a9cd3439SDavid Ahern 	[NDA_PROTOCOL]		= { .type = NLA_U8 },
17851274e1ccSRoopa Prabhu 	[NDA_NH_ID]		= { .type = NLA_U32 },
1786899426b3SNikolay Aleksandrov 	[NDA_FDB_EXT_ATTRS]	= { .type = NLA_NESTED },
178782cbb5c6SRoopa Prabhu };
178882cbb5c6SRoopa Prabhu 
1789c21ef3e3SDavid Ahern static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
1790c21ef3e3SDavid Ahern 			struct netlink_ext_ack *extack)
17911da177e4SLinus Torvalds {
17923b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
1793a14a49d2SThomas Graf 	struct ndmsg *ndm;
1794a14a49d2SThomas Graf 	struct nlattr *dst_attr;
17951da177e4SLinus Torvalds 	struct neigh_table *tbl;
1796d7480fd3SWANG Cong 	struct neighbour *neigh;
17971da177e4SLinus Torvalds 	struct net_device *dev = NULL;
1798a14a49d2SThomas Graf 	int err = -EINVAL;
17991da177e4SLinus Torvalds 
1800110b2499SEric Dumazet 	ASSERT_RTNL();
1801a14a49d2SThomas Graf 	if (nlmsg_len(nlh) < sizeof(*ndm))
18021da177e4SLinus Torvalds 		goto out;
18031da177e4SLinus Torvalds 
1804a14a49d2SThomas Graf 	dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
18057a35a50dSDavid Ahern 	if (!dst_attr) {
18067a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Network address not specified");
1807a14a49d2SThomas Graf 		goto out;
18087a35a50dSDavid Ahern 	}
1809a14a49d2SThomas Graf 
1810a14a49d2SThomas Graf 	ndm = nlmsg_data(nlh);
1811a14a49d2SThomas Graf 	if (ndm->ndm_ifindex) {
1812110b2499SEric Dumazet 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
1813a14a49d2SThomas Graf 		if (dev == NULL) {
1814a14a49d2SThomas Graf 			err = -ENODEV;
1815a14a49d2SThomas Graf 			goto out;
1816a14a49d2SThomas Graf 		}
1817a14a49d2SThomas Graf 	}
1818a14a49d2SThomas Graf 
1819d7480fd3SWANG Cong 	tbl = neigh_find_table(ndm->ndm_family);
1820d7480fd3SWANG Cong 	if (tbl == NULL)
1821d7480fd3SWANG Cong 		return -EAFNOSUPPORT;
18221da177e4SLinus Torvalds 
18237a35a50dSDavid Ahern 	if (nla_len(dst_attr) < (int)tbl->key_len) {
18247a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid network address");
1825110b2499SEric Dumazet 		goto out;
18267a35a50dSDavid Ahern 	}
18271da177e4SLinus Torvalds 
18281da177e4SLinus Torvalds 	if (ndm->ndm_flags & NTF_PROXY) {
1829426b5303SEric W. Biederman 		err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
1830110b2499SEric Dumazet 		goto out;
18311da177e4SLinus Torvalds 	}
18321da177e4SLinus Torvalds 
1833a14a49d2SThomas Graf 	if (dev == NULL)
1834110b2499SEric Dumazet 		goto out;
18351da177e4SLinus Torvalds 
1836a14a49d2SThomas Graf 	neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1837a14a49d2SThomas Graf 	if (neigh == NULL) {
1838a14a49d2SThomas Graf 		err = -ENOENT;
1839110b2499SEric Dumazet 		goto out;
1840a14a49d2SThomas Graf 	}
1841a14a49d2SThomas Graf 
18427a35a50dSDavid Ahern 	err = __neigh_update(neigh, NULL, NUD_FAILED,
18437a35a50dSDavid Ahern 			     NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN,
18447a35a50dSDavid Ahern 			     NETLINK_CB(skb).portid, extack);
18455071034eSSowmini Varadhan 	write_lock_bh(&tbl->lock);
1846a14a49d2SThomas Graf 	neigh_release(neigh);
18475071034eSSowmini Varadhan 	neigh_remove_one(neigh, tbl);
18485071034eSSowmini Varadhan 	write_unlock_bh(&tbl->lock);
1849a14a49d2SThomas Graf 
18501da177e4SLinus Torvalds out:
18511da177e4SLinus Torvalds 	return err;
18521da177e4SLinus Torvalds }
18531da177e4SLinus Torvalds 
1854c21ef3e3SDavid Ahern static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
1855c21ef3e3SDavid Ahern 		     struct netlink_ext_ack *extack)
18561da177e4SLinus Torvalds {
1857f7aa74e4SRoopa Prabhu 	int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE |
1858f7aa74e4SRoopa Prabhu 		NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
18593b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
18605208debdSThomas Graf 	struct ndmsg *ndm;
18615208debdSThomas Graf 	struct nlattr *tb[NDA_MAX+1];
18621da177e4SLinus Torvalds 	struct neigh_table *tbl;
18631da177e4SLinus Torvalds 	struct net_device *dev = NULL;
1864d7480fd3SWANG Cong 	struct neighbour *neigh;
1865d7480fd3SWANG Cong 	void *dst, *lladdr;
1866df9b0e30SDavid Ahern 	u8 protocol = 0;
18675208debdSThomas Graf 	int err;
18681da177e4SLinus Torvalds 
1869110b2499SEric Dumazet 	ASSERT_RTNL();
18708cb08174SJohannes Berg 	err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX,
18718cb08174SJohannes Berg 				     nda_policy, extack);
18725208debdSThomas Graf 	if (err < 0)
18731da177e4SLinus Torvalds 		goto out;
18741da177e4SLinus Torvalds 
18755208debdSThomas Graf 	err = -EINVAL;
18767a35a50dSDavid Ahern 	if (!tb[NDA_DST]) {
18777a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Network address not specified");
18785208debdSThomas Graf 		goto out;
18797a35a50dSDavid Ahern 	}
18805208debdSThomas Graf 
18815208debdSThomas Graf 	ndm = nlmsg_data(nlh);
18825208debdSThomas Graf 	if (ndm->ndm_ifindex) {
1883110b2499SEric Dumazet 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
18845208debdSThomas Graf 		if (dev == NULL) {
18855208debdSThomas Graf 			err = -ENODEV;
18865208debdSThomas Graf 			goto out;
18875208debdSThomas Graf 		}
18885208debdSThomas Graf 
18897a35a50dSDavid Ahern 		if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) {
18907a35a50dSDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid link address");
1891110b2499SEric Dumazet 			goto out;
18925208debdSThomas Graf 		}
18937a35a50dSDavid Ahern 	}
18945208debdSThomas Graf 
1895d7480fd3SWANG Cong 	tbl = neigh_find_table(ndm->ndm_family);
1896d7480fd3SWANG Cong 	if (tbl == NULL)
1897d7480fd3SWANG Cong 		return -EAFNOSUPPORT;
18981da177e4SLinus Torvalds 
18997a35a50dSDavid Ahern 	if (nla_len(tb[NDA_DST]) < (int)tbl->key_len) {
19007a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid network address");
1901110b2499SEric Dumazet 		goto out;
19027a35a50dSDavid Ahern 	}
19037a35a50dSDavid Ahern 
19045208debdSThomas Graf 	dst = nla_data(tb[NDA_DST]);
19055208debdSThomas Graf 	lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
19061da177e4SLinus Torvalds 
1907a9cd3439SDavid Ahern 	if (tb[NDA_PROTOCOL])
1908df9b0e30SDavid Ahern 		protocol = nla_get_u8(tb[NDA_PROTOCOL]);
1909df9b0e30SDavid Ahern 
19101da177e4SLinus Torvalds 	if (ndm->ndm_flags & NTF_PROXY) {
191162dd9318SVille Nuorvala 		struct pneigh_entry *pn;
191262dd9318SVille Nuorvala 
19135208debdSThomas Graf 		err = -ENOBUFS;
1914426b5303SEric W. Biederman 		pn = pneigh_lookup(tbl, net, dst, dev, 1);
191562dd9318SVille Nuorvala 		if (pn) {
191662dd9318SVille Nuorvala 			pn->flags = ndm->ndm_flags;
1917df9b0e30SDavid Ahern 			if (protocol)
1918df9b0e30SDavid Ahern 				pn->protocol = protocol;
191962dd9318SVille Nuorvala 			err = 0;
192062dd9318SVille Nuorvala 		}
1921110b2499SEric Dumazet 		goto out;
19221da177e4SLinus Torvalds 	}
19231da177e4SLinus Torvalds 
19247a35a50dSDavid Ahern 	if (!dev) {
19257a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Device not specified");
1926110b2499SEric Dumazet 		goto out;
19277a35a50dSDavid Ahern 	}
19281da177e4SLinus Torvalds 
1929b8fb1ab4SDavid Ahern 	if (tbl->allow_add && !tbl->allow_add(dev, extack)) {
1930b8fb1ab4SDavid Ahern 		err = -EINVAL;
1931b8fb1ab4SDavid Ahern 		goto out;
1932b8fb1ab4SDavid Ahern 	}
1933b8fb1ab4SDavid Ahern 
19345208debdSThomas Graf 	neigh = neigh_lookup(tbl, dst, dev);
19355208debdSThomas Graf 	if (neigh == NULL) {
1936e997f8a2SDavid Ahern 		bool exempt_from_gc;
1937e997f8a2SDavid Ahern 
19385208debdSThomas Graf 		if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
19391da177e4SLinus Torvalds 			err = -ENOENT;
1940110b2499SEric Dumazet 			goto out;
19415208debdSThomas Graf 		}
19425208debdSThomas Graf 
1943e997f8a2SDavid Ahern 		exempt_from_gc = ndm->ndm_state & NUD_PERMANENT ||
1944e997f8a2SDavid Ahern 				 ndm->ndm_flags & NTF_EXT_LEARNED;
1945e997f8a2SDavid Ahern 		neigh = ___neigh_create(tbl, dst, dev, exempt_from_gc, true);
19465208debdSThomas Graf 		if (IS_ERR(neigh)) {
19475208debdSThomas Graf 			err = PTR_ERR(neigh);
1948110b2499SEric Dumazet 			goto out;
19491da177e4SLinus Torvalds 		}
19505208debdSThomas Graf 	} else {
19515208debdSThomas Graf 		if (nlh->nlmsg_flags & NLM_F_EXCL) {
19525208debdSThomas Graf 			err = -EEXIST;
19535208debdSThomas Graf 			neigh_release(neigh);
1954110b2499SEric Dumazet 			goto out;
19551da177e4SLinus Torvalds 		}
19561da177e4SLinus Torvalds 
19575208debdSThomas Graf 		if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
1958f7aa74e4SRoopa Prabhu 			flags &= ~(NEIGH_UPDATE_F_OVERRIDE |
1959f7aa74e4SRoopa Prabhu 				   NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
19605208debdSThomas Graf 	}
19611da177e4SLinus Torvalds 
196238212bb3SRoman Mashak 	if (protocol)
196338212bb3SRoman Mashak 		neigh->protocol = protocol;
196438212bb3SRoman Mashak 
19659ce33e46SRoopa Prabhu 	if (ndm->ndm_flags & NTF_EXT_LEARNED)
19669ce33e46SRoopa Prabhu 		flags |= NEIGH_UPDATE_F_EXT_LEARNED;
19679ce33e46SRoopa Prabhu 
1968f7aa74e4SRoopa Prabhu 	if (ndm->ndm_flags & NTF_ROUTER)
1969f7aa74e4SRoopa Prabhu 		flags |= NEIGH_UPDATE_F_ISROUTER;
1970f7aa74e4SRoopa Prabhu 
19710c5c2d30SEric Biederman 	if (ndm->ndm_flags & NTF_USE) {
19720c5c2d30SEric Biederman 		neigh_event_send(neigh, NULL);
19730c5c2d30SEric Biederman 		err = 0;
19740c5c2d30SEric Biederman 	} else
19757a35a50dSDavid Ahern 		err = __neigh_update(neigh, lladdr, ndm->ndm_state, flags,
19767a35a50dSDavid Ahern 				     NETLINK_CB(skb).portid, extack);
1977df9b0e30SDavid Ahern 
19785208debdSThomas Graf 	neigh_release(neigh);
19791da177e4SLinus Torvalds 
19801da177e4SLinus Torvalds out:
19811da177e4SLinus Torvalds 	return err;
19821da177e4SLinus Torvalds }
19831da177e4SLinus Torvalds 
1984c7fb64dbSThomas Graf static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
1985c7fb64dbSThomas Graf {
1986ca860fb3SThomas Graf 	struct nlattr *nest;
1987e386c6ebSThomas Graf 
1988ae0be8deSMichal Kubecek 	nest = nla_nest_start_noflag(skb, NDTA_PARMS);
1989ca860fb3SThomas Graf 	if (nest == NULL)
1990ca860fb3SThomas Graf 		return -ENOBUFS;
1991c7fb64dbSThomas Graf 
19929a6308d7SDavid S. Miller 	if ((parms->dev &&
19939a6308d7SDavid S. Miller 	     nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
19946343944bSReshetova, Elena 	    nla_put_u32(skb, NDTPA_REFCNT, refcount_read(&parms->refcnt)) ||
19951f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_QUEUE_LENBYTES,
19961f9248e5SJiri Pirko 			NEIGH_VAR(parms, QUEUE_LEN_BYTES)) ||
19978b5c171bSEric Dumazet 	    /* approximative value for deprecated QUEUE_LEN (in packets) */
19989a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTPA_QUEUE_LEN,
19991f9248e5SJiri Pirko 			NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) ||
20001f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) ||
20011f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) ||
20021f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_UCAST_PROBES,
20031f9248e5SJiri Pirko 			NEIGH_VAR(parms, UCAST_PROBES)) ||
20041f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_MCAST_PROBES,
20051f9248e5SJiri Pirko 			NEIGH_VAR(parms, MCAST_PROBES)) ||
20068da86466SYOSHIFUJI Hideaki/吉藤英明 	    nla_put_u32(skb, NDTPA_MCAST_REPROBES,
20078da86466SYOSHIFUJI Hideaki/吉藤英明 			NEIGH_VAR(parms, MCAST_REPROBES)) ||
20082175d87cSNicolas Dichtel 	    nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time,
20092175d87cSNicolas Dichtel 			  NDTPA_PAD) ||
20109a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
20112175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, BASE_REACHABLE_TIME), NDTPA_PAD) ||
20121f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_GC_STALETIME,
20132175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, GC_STALETIME), NDTPA_PAD) ||
20149a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
20152175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, DELAY_PROBE_TIME), NDTPA_PAD) ||
20161f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_RETRANS_TIME,
20172175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, RETRANS_TIME), NDTPA_PAD) ||
20181f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_ANYCAST_DELAY,
20192175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, ANYCAST_DELAY), NDTPA_PAD) ||
20201f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_PROXY_DELAY,
20212175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, PROXY_DELAY), NDTPA_PAD) ||
20221f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_LOCKTIME,
20232175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, LOCKTIME), NDTPA_PAD))
20249a6308d7SDavid S. Miller 		goto nla_put_failure;
2025ca860fb3SThomas Graf 	return nla_nest_end(skb, nest);
2026c7fb64dbSThomas Graf 
2027ca860fb3SThomas Graf nla_put_failure:
2028bc3ed28cSThomas Graf 	nla_nest_cancel(skb, nest);
2029bc3ed28cSThomas Graf 	return -EMSGSIZE;
2030c7fb64dbSThomas Graf }
2031c7fb64dbSThomas Graf 
2032ca860fb3SThomas Graf static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
2033ca860fb3SThomas Graf 			      u32 pid, u32 seq, int type, int flags)
2034c7fb64dbSThomas Graf {
2035c7fb64dbSThomas Graf 	struct nlmsghdr *nlh;
2036c7fb64dbSThomas Graf 	struct ndtmsg *ndtmsg;
2037c7fb64dbSThomas Graf 
2038ca860fb3SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2039ca860fb3SThomas Graf 	if (nlh == NULL)
204026932566SPatrick McHardy 		return -EMSGSIZE;
2041c7fb64dbSThomas Graf 
2042ca860fb3SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2043c7fb64dbSThomas Graf 
2044c7fb64dbSThomas Graf 	read_lock_bh(&tbl->lock);
2045c7fb64dbSThomas Graf 	ndtmsg->ndtm_family = tbl->family;
20469ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad1   = 0;
20479ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad2   = 0;
2048c7fb64dbSThomas Graf 
20499a6308d7SDavid S. Miller 	if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
20502175d87cSNicolas Dichtel 	    nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval, NDTA_PAD) ||
20519a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
20529a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
20539a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
20549a6308d7SDavid S. Miller 		goto nla_put_failure;
2055c7fb64dbSThomas Graf 	{
2056c7fb64dbSThomas Graf 		unsigned long now = jiffies;
20579d027e3aSEric Dumazet 		long flush_delta = now - tbl->last_flush;
20589d027e3aSEric Dumazet 		long rand_delta = now - tbl->last_rand;
2059d6bf7817SEric Dumazet 		struct neigh_hash_table *nht;
2060c7fb64dbSThomas Graf 		struct ndt_config ndc = {
2061c7fb64dbSThomas Graf 			.ndtc_key_len		= tbl->key_len,
2062c7fb64dbSThomas Graf 			.ndtc_entry_size	= tbl->entry_size,
2063c7fb64dbSThomas Graf 			.ndtc_entries		= atomic_read(&tbl->entries),
2064c7fb64dbSThomas Graf 			.ndtc_last_flush	= jiffies_to_msecs(flush_delta),
2065c7fb64dbSThomas Graf 			.ndtc_last_rand		= jiffies_to_msecs(rand_delta),
2066c7fb64dbSThomas Graf 			.ndtc_proxy_qlen	= tbl->proxy_queue.qlen,
2067c7fb64dbSThomas Graf 		};
2068c7fb64dbSThomas Graf 
2069d6bf7817SEric Dumazet 		rcu_read_lock_bh();
2070d6bf7817SEric Dumazet 		nht = rcu_dereference_bh(tbl->nht);
20712c2aba6cSDavid S. Miller 		ndc.ndtc_hash_rnd = nht->hash_rnd[0];
2072cd089336SDavid S. Miller 		ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
2073d6bf7817SEric Dumazet 		rcu_read_unlock_bh();
2074d6bf7817SEric Dumazet 
20759a6308d7SDavid S. Miller 		if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
20769a6308d7SDavid S. Miller 			goto nla_put_failure;
2077c7fb64dbSThomas Graf 	}
2078c7fb64dbSThomas Graf 
2079c7fb64dbSThomas Graf 	{
2080c7fb64dbSThomas Graf 		int cpu;
2081c7fb64dbSThomas Graf 		struct ndt_stats ndst;
2082c7fb64dbSThomas Graf 
2083c7fb64dbSThomas Graf 		memset(&ndst, 0, sizeof(ndst));
2084c7fb64dbSThomas Graf 
20856f912042SKAMEZAWA Hiroyuki 		for_each_possible_cpu(cpu) {
2086c7fb64dbSThomas Graf 			struct neigh_statistics	*st;
2087c7fb64dbSThomas Graf 
2088c7fb64dbSThomas Graf 			st = per_cpu_ptr(tbl->stats, cpu);
2089c7fb64dbSThomas Graf 			ndst.ndts_allocs		+= st->allocs;
2090c7fb64dbSThomas Graf 			ndst.ndts_destroys		+= st->destroys;
2091c7fb64dbSThomas Graf 			ndst.ndts_hash_grows		+= st->hash_grows;
2092c7fb64dbSThomas Graf 			ndst.ndts_res_failed		+= st->res_failed;
2093c7fb64dbSThomas Graf 			ndst.ndts_lookups		+= st->lookups;
2094c7fb64dbSThomas Graf 			ndst.ndts_hits			+= st->hits;
2095c7fb64dbSThomas Graf 			ndst.ndts_rcv_probes_mcast	+= st->rcv_probes_mcast;
2096c7fb64dbSThomas Graf 			ndst.ndts_rcv_probes_ucast	+= st->rcv_probes_ucast;
2097c7fb64dbSThomas Graf 			ndst.ndts_periodic_gc_runs	+= st->periodic_gc_runs;
2098c7fb64dbSThomas Graf 			ndst.ndts_forced_gc_runs	+= st->forced_gc_runs;
2099fb811395SRick Jones 			ndst.ndts_table_fulls		+= st->table_fulls;
2100c7fb64dbSThomas Graf 		}
2101c7fb64dbSThomas Graf 
2102b676338fSNicolas Dichtel 		if (nla_put_64bit(skb, NDTA_STATS, sizeof(ndst), &ndst,
2103b676338fSNicolas Dichtel 				  NDTA_PAD))
21049a6308d7SDavid S. Miller 			goto nla_put_failure;
2105c7fb64dbSThomas Graf 	}
2106c7fb64dbSThomas Graf 
2107c7fb64dbSThomas Graf 	BUG_ON(tbl->parms.dev);
2108c7fb64dbSThomas Graf 	if (neightbl_fill_parms(skb, &tbl->parms) < 0)
2109ca860fb3SThomas Graf 		goto nla_put_failure;
2110c7fb64dbSThomas Graf 
2111c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
2112053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2113053c095aSJohannes Berg 	return 0;
2114c7fb64dbSThomas Graf 
2115ca860fb3SThomas Graf nla_put_failure:
2116c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
211726932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
211826932566SPatrick McHardy 	return -EMSGSIZE;
2119c7fb64dbSThomas Graf }
2120c7fb64dbSThomas Graf 
2121ca860fb3SThomas Graf static int neightbl_fill_param_info(struct sk_buff *skb,
2122ca860fb3SThomas Graf 				    struct neigh_table *tbl,
2123c7fb64dbSThomas Graf 				    struct neigh_parms *parms,
2124ca860fb3SThomas Graf 				    u32 pid, u32 seq, int type,
2125ca860fb3SThomas Graf 				    unsigned int flags)
2126c7fb64dbSThomas Graf {
2127c7fb64dbSThomas Graf 	struct ndtmsg *ndtmsg;
2128c7fb64dbSThomas Graf 	struct nlmsghdr *nlh;
2129c7fb64dbSThomas Graf 
2130ca860fb3SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2131ca860fb3SThomas Graf 	if (nlh == NULL)
213226932566SPatrick McHardy 		return -EMSGSIZE;
2133c7fb64dbSThomas Graf 
2134ca860fb3SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2135c7fb64dbSThomas Graf 
2136c7fb64dbSThomas Graf 	read_lock_bh(&tbl->lock);
2137c7fb64dbSThomas Graf 	ndtmsg->ndtm_family = tbl->family;
21389ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad1   = 0;
21399ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad2   = 0;
2140c7fb64dbSThomas Graf 
2141ca860fb3SThomas Graf 	if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
2142ca860fb3SThomas Graf 	    neightbl_fill_parms(skb, parms) < 0)
2143ca860fb3SThomas Graf 		goto errout;
2144c7fb64dbSThomas Graf 
2145c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
2146053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2147053c095aSJohannes Berg 	return 0;
2148ca860fb3SThomas Graf errout:
2149c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
215026932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
215126932566SPatrick McHardy 	return -EMSGSIZE;
2152c7fb64dbSThomas Graf }
2153c7fb64dbSThomas Graf 
2154ef7c79edSPatrick McHardy static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
21556b3f8674SThomas Graf 	[NDTA_NAME]		= { .type = NLA_STRING },
21566b3f8674SThomas Graf 	[NDTA_THRESH1]		= { .type = NLA_U32 },
21576b3f8674SThomas Graf 	[NDTA_THRESH2]		= { .type = NLA_U32 },
21586b3f8674SThomas Graf 	[NDTA_THRESH3]		= { .type = NLA_U32 },
21596b3f8674SThomas Graf 	[NDTA_GC_INTERVAL]	= { .type = NLA_U64 },
21606b3f8674SThomas Graf 	[NDTA_PARMS]		= { .type = NLA_NESTED },
21616b3f8674SThomas Graf };
21626b3f8674SThomas Graf 
2163ef7c79edSPatrick McHardy static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
21646b3f8674SThomas Graf 	[NDTPA_IFINDEX]			= { .type = NLA_U32 },
21656b3f8674SThomas Graf 	[NDTPA_QUEUE_LEN]		= { .type = NLA_U32 },
21666b3f8674SThomas Graf 	[NDTPA_PROXY_QLEN]		= { .type = NLA_U32 },
21676b3f8674SThomas Graf 	[NDTPA_APP_PROBES]		= { .type = NLA_U32 },
21686b3f8674SThomas Graf 	[NDTPA_UCAST_PROBES]		= { .type = NLA_U32 },
21696b3f8674SThomas Graf 	[NDTPA_MCAST_PROBES]		= { .type = NLA_U32 },
21708da86466SYOSHIFUJI Hideaki/吉藤英明 	[NDTPA_MCAST_REPROBES]		= { .type = NLA_U32 },
21716b3f8674SThomas Graf 	[NDTPA_BASE_REACHABLE_TIME]	= { .type = NLA_U64 },
21726b3f8674SThomas Graf 	[NDTPA_GC_STALETIME]		= { .type = NLA_U64 },
21736b3f8674SThomas Graf 	[NDTPA_DELAY_PROBE_TIME]	= { .type = NLA_U64 },
21746b3f8674SThomas Graf 	[NDTPA_RETRANS_TIME]		= { .type = NLA_U64 },
21756b3f8674SThomas Graf 	[NDTPA_ANYCAST_DELAY]		= { .type = NLA_U64 },
21766b3f8674SThomas Graf 	[NDTPA_PROXY_DELAY]		= { .type = NLA_U64 },
21776b3f8674SThomas Graf 	[NDTPA_LOCKTIME]		= { .type = NLA_U64 },
21786b3f8674SThomas Graf };
21796b3f8674SThomas Graf 
2180c21ef3e3SDavid Ahern static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
2181c21ef3e3SDavid Ahern 			struct netlink_ext_ack *extack)
2182c7fb64dbSThomas Graf {
21833b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
2184c7fb64dbSThomas Graf 	struct neigh_table *tbl;
21856b3f8674SThomas Graf 	struct ndtmsg *ndtmsg;
21866b3f8674SThomas Graf 	struct nlattr *tb[NDTA_MAX+1];
2187d7480fd3SWANG Cong 	bool found = false;
2188d7480fd3SWANG Cong 	int err, tidx;
2189c7fb64dbSThomas Graf 
21908cb08174SJohannes Berg 	err = nlmsg_parse_deprecated(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
2191c21ef3e3SDavid Ahern 				     nl_neightbl_policy, extack);
21926b3f8674SThomas Graf 	if (err < 0)
21936b3f8674SThomas Graf 		goto errout;
2194c7fb64dbSThomas Graf 
21956b3f8674SThomas Graf 	if (tb[NDTA_NAME] == NULL) {
21966b3f8674SThomas Graf 		err = -EINVAL;
21976b3f8674SThomas Graf 		goto errout;
21986b3f8674SThomas Graf 	}
21996b3f8674SThomas Graf 
22006b3f8674SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2201d7480fd3SWANG Cong 
2202d7480fd3SWANG Cong 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2203d7480fd3SWANG Cong 		tbl = neigh_tables[tidx];
2204d7480fd3SWANG Cong 		if (!tbl)
2205d7480fd3SWANG Cong 			continue;
2206c7fb64dbSThomas Graf 		if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
2207c7fb64dbSThomas Graf 			continue;
2208d7480fd3SWANG Cong 		if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) {
2209d7480fd3SWANG Cong 			found = true;
2210c7fb64dbSThomas Graf 			break;
2211c7fb64dbSThomas Graf 		}
2212c7fb64dbSThomas Graf 	}
2213c7fb64dbSThomas Graf 
2214d7480fd3SWANG Cong 	if (!found)
2215d7480fd3SWANG Cong 		return -ENOENT;
2216d7480fd3SWANG Cong 
2217c7fb64dbSThomas Graf 	/*
2218c7fb64dbSThomas Graf 	 * We acquire tbl->lock to be nice to the periodic timers and
2219c7fb64dbSThomas Graf 	 * make sure they always see a consistent set of values.
2220c7fb64dbSThomas Graf 	 */
2221c7fb64dbSThomas Graf 	write_lock_bh(&tbl->lock);
2222c7fb64dbSThomas Graf 
22236b3f8674SThomas Graf 	if (tb[NDTA_PARMS]) {
22246b3f8674SThomas Graf 		struct nlattr *tbp[NDTPA_MAX+1];
2225c7fb64dbSThomas Graf 		struct neigh_parms *p;
22266b3f8674SThomas Graf 		int i, ifindex = 0;
2227c7fb64dbSThomas Graf 
22288cb08174SJohannes Berg 		err = nla_parse_nested_deprecated(tbp, NDTPA_MAX,
22298cb08174SJohannes Berg 						  tb[NDTA_PARMS],
2230c21ef3e3SDavid Ahern 						  nl_ntbl_parm_policy, extack);
22316b3f8674SThomas Graf 		if (err < 0)
22326b3f8674SThomas Graf 			goto errout_tbl_lock;
2233c7fb64dbSThomas Graf 
22346b3f8674SThomas Graf 		if (tbp[NDTPA_IFINDEX])
22356b3f8674SThomas Graf 			ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
2236c7fb64dbSThomas Graf 
223797fd5bc7STobias Klauser 		p = lookup_neigh_parms(tbl, net, ifindex);
2238c7fb64dbSThomas Graf 		if (p == NULL) {
2239c7fb64dbSThomas Graf 			err = -ENOENT;
22406b3f8674SThomas Graf 			goto errout_tbl_lock;
2241c7fb64dbSThomas Graf 		}
2242c7fb64dbSThomas Graf 
22436b3f8674SThomas Graf 		for (i = 1; i <= NDTPA_MAX; i++) {
22446b3f8674SThomas Graf 			if (tbp[i] == NULL)
22456b3f8674SThomas Graf 				continue;
2246c7fb64dbSThomas Graf 
22476b3f8674SThomas Graf 			switch (i) {
22486b3f8674SThomas Graf 			case NDTPA_QUEUE_LEN:
22491f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
22501f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]) *
22511f9248e5SJiri Pirko 					      SKB_TRUESIZE(ETH_FRAME_LEN));
22528b5c171bSEric Dumazet 				break;
22538b5c171bSEric Dumazet 			case NDTPA_QUEUE_LENBYTES:
22541f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
22551f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
22566b3f8674SThomas Graf 				break;
22576b3f8674SThomas Graf 			case NDTPA_PROXY_QLEN:
22581f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, PROXY_QLEN,
22591f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
22606b3f8674SThomas Graf 				break;
22616b3f8674SThomas Graf 			case NDTPA_APP_PROBES:
22621f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, APP_PROBES,
22631f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
22646b3f8674SThomas Graf 				break;
22656b3f8674SThomas Graf 			case NDTPA_UCAST_PROBES:
22661f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, UCAST_PROBES,
22671f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
22686b3f8674SThomas Graf 				break;
22696b3f8674SThomas Graf 			case NDTPA_MCAST_PROBES:
22701f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, MCAST_PROBES,
22711f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
22726b3f8674SThomas Graf 				break;
22738da86466SYOSHIFUJI Hideaki/吉藤英明 			case NDTPA_MCAST_REPROBES:
22748da86466SYOSHIFUJI Hideaki/吉藤英明 				NEIGH_VAR_SET(p, MCAST_REPROBES,
22758da86466SYOSHIFUJI Hideaki/吉藤英明 					      nla_get_u32(tbp[i]));
22768da86466SYOSHIFUJI Hideaki/吉藤英明 				break;
22776b3f8674SThomas Graf 			case NDTPA_BASE_REACHABLE_TIME:
22781f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,
22791f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
22804bf6980dSJean-Francois Remy 				/* update reachable_time as well, otherwise, the change will
22814bf6980dSJean-Francois Remy 				 * only be effective after the next time neigh_periodic_work
22824bf6980dSJean-Francois Remy 				 * decides to recompute it (can be multiple minutes)
22834bf6980dSJean-Francois Remy 				 */
22844bf6980dSJean-Francois Remy 				p->reachable_time =
22854bf6980dSJean-Francois Remy 					neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
22866b3f8674SThomas Graf 				break;
22876b3f8674SThomas Graf 			case NDTPA_GC_STALETIME:
22881f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, GC_STALETIME,
22891f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
22906b3f8674SThomas Graf 				break;
22916b3f8674SThomas Graf 			case NDTPA_DELAY_PROBE_TIME:
22921f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, DELAY_PROBE_TIME,
22931f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
22942a4501aeSIdo Schimmel 				call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
22956b3f8674SThomas Graf 				break;
22966b3f8674SThomas Graf 			case NDTPA_RETRANS_TIME:
22971f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, RETRANS_TIME,
22981f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
22996b3f8674SThomas Graf 				break;
23006b3f8674SThomas Graf 			case NDTPA_ANYCAST_DELAY:
23013977458cSJiri Pirko 				NEIGH_VAR_SET(p, ANYCAST_DELAY,
23023977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
23036b3f8674SThomas Graf 				break;
23046b3f8674SThomas Graf 			case NDTPA_PROXY_DELAY:
23053977458cSJiri Pirko 				NEIGH_VAR_SET(p, PROXY_DELAY,
23063977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
23076b3f8674SThomas Graf 				break;
23086b3f8674SThomas Graf 			case NDTPA_LOCKTIME:
23093977458cSJiri Pirko 				NEIGH_VAR_SET(p, LOCKTIME,
23103977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
23116b3f8674SThomas Graf 				break;
2312c7fb64dbSThomas Graf 			}
23136b3f8674SThomas Graf 		}
23146b3f8674SThomas Graf 	}
23156b3f8674SThomas Graf 
2316dc25c676SGao feng 	err = -ENOENT;
2317dc25c676SGao feng 	if ((tb[NDTA_THRESH1] || tb[NDTA_THRESH2] ||
2318dc25c676SGao feng 	     tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]) &&
2319dc25c676SGao feng 	    !net_eq(net, &init_net))
2320dc25c676SGao feng 		goto errout_tbl_lock;
2321dc25c676SGao feng 
23226b3f8674SThomas Graf 	if (tb[NDTA_THRESH1])
23236b3f8674SThomas Graf 		tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
23246b3f8674SThomas Graf 
23256b3f8674SThomas Graf 	if (tb[NDTA_THRESH2])
23266b3f8674SThomas Graf 		tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
23276b3f8674SThomas Graf 
23286b3f8674SThomas Graf 	if (tb[NDTA_THRESH3])
23296b3f8674SThomas Graf 		tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
23306b3f8674SThomas Graf 
23316b3f8674SThomas Graf 	if (tb[NDTA_GC_INTERVAL])
23326b3f8674SThomas Graf 		tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2333c7fb64dbSThomas Graf 
2334c7fb64dbSThomas Graf 	err = 0;
2335c7fb64dbSThomas Graf 
23366b3f8674SThomas Graf errout_tbl_lock:
2337c7fb64dbSThomas Graf 	write_unlock_bh(&tbl->lock);
23386b3f8674SThomas Graf errout:
2339c7fb64dbSThomas Graf 	return err;
2340c7fb64dbSThomas Graf }
2341c7fb64dbSThomas Graf 
23429632d47fSDavid Ahern static int neightbl_valid_dump_info(const struct nlmsghdr *nlh,
23439632d47fSDavid Ahern 				    struct netlink_ext_ack *extack)
23449632d47fSDavid Ahern {
23459632d47fSDavid Ahern 	struct ndtmsg *ndtm;
23469632d47fSDavid Ahern 
23479632d47fSDavid Ahern 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndtm))) {
23489632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid header for neighbor table dump request");
23499632d47fSDavid Ahern 		return -EINVAL;
23509632d47fSDavid Ahern 	}
23519632d47fSDavid Ahern 
23529632d47fSDavid Ahern 	ndtm = nlmsg_data(nlh);
23539632d47fSDavid Ahern 	if (ndtm->ndtm_pad1  || ndtm->ndtm_pad2) {
23549632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor table dump request");
23559632d47fSDavid Ahern 		return -EINVAL;
23569632d47fSDavid Ahern 	}
23579632d47fSDavid Ahern 
23589632d47fSDavid Ahern 	if (nlmsg_attrlen(nlh, sizeof(*ndtm))) {
23599632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid data after header in neighbor table dump request");
23609632d47fSDavid Ahern 		return -EINVAL;
23619632d47fSDavid Ahern 	}
23629632d47fSDavid Ahern 
23639632d47fSDavid Ahern 	return 0;
23649632d47fSDavid Ahern }
23659632d47fSDavid Ahern 
2366c8822a4eSThomas Graf static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
2367c7fb64dbSThomas Graf {
23689632d47fSDavid Ahern 	const struct nlmsghdr *nlh = cb->nlh;
23693b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
2370ca860fb3SThomas Graf 	int family, tidx, nidx = 0;
2371ca860fb3SThomas Graf 	int tbl_skip = cb->args[0];
2372ca860fb3SThomas Graf 	int neigh_skip = cb->args[1];
2373c7fb64dbSThomas Graf 	struct neigh_table *tbl;
2374c7fb64dbSThomas Graf 
23759632d47fSDavid Ahern 	if (cb->strict_check) {
23769632d47fSDavid Ahern 		int err = neightbl_valid_dump_info(nlh, cb->extack);
23779632d47fSDavid Ahern 
23789632d47fSDavid Ahern 		if (err < 0)
23799632d47fSDavid Ahern 			return err;
23809632d47fSDavid Ahern 	}
23819632d47fSDavid Ahern 
23829632d47fSDavid Ahern 	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
2383c7fb64dbSThomas Graf 
2384d7480fd3SWANG Cong 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2385c7fb64dbSThomas Graf 		struct neigh_parms *p;
2386c7fb64dbSThomas Graf 
2387d7480fd3SWANG Cong 		tbl = neigh_tables[tidx];
2388d7480fd3SWANG Cong 		if (!tbl)
2389d7480fd3SWANG Cong 			continue;
2390d7480fd3SWANG Cong 
2391ca860fb3SThomas Graf 		if (tidx < tbl_skip || (family && tbl->family != family))
2392c7fb64dbSThomas Graf 			continue;
2393c7fb64dbSThomas Graf 
239415e47304SEric W. Biederman 		if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
23959632d47fSDavid Ahern 				       nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
23967b46a644SDavid S. Miller 				       NLM_F_MULTI) < 0)
2397c7fb64dbSThomas Graf 			break;
2398c7fb64dbSThomas Graf 
239975fbfd33SNicolas Dichtel 		nidx = 0;
240075fbfd33SNicolas Dichtel 		p = list_next_entry(&tbl->parms, list);
240175fbfd33SNicolas Dichtel 		list_for_each_entry_from(p, &tbl->parms_list, list) {
2402878628fbSYOSHIFUJI Hideaki 			if (!net_eq(neigh_parms_net(p), net))
2403426b5303SEric W. Biederman 				continue;
2404426b5303SEric W. Biederman 
2405efc683fcSGautam Kachroo 			if (nidx < neigh_skip)
2406efc683fcSGautam Kachroo 				goto next;
2407c7fb64dbSThomas Graf 
2408ca860fb3SThomas Graf 			if (neightbl_fill_param_info(skb, tbl, p,
240915e47304SEric W. Biederman 						     NETLINK_CB(cb->skb).portid,
24109632d47fSDavid Ahern 						     nlh->nlmsg_seq,
2411ca860fb3SThomas Graf 						     RTM_NEWNEIGHTBL,
24127b46a644SDavid S. Miller 						     NLM_F_MULTI) < 0)
2413c7fb64dbSThomas Graf 				goto out;
2414efc683fcSGautam Kachroo 		next:
2415efc683fcSGautam Kachroo 			nidx++;
2416c7fb64dbSThomas Graf 		}
2417c7fb64dbSThomas Graf 
2418ca860fb3SThomas Graf 		neigh_skip = 0;
2419c7fb64dbSThomas Graf 	}
2420c7fb64dbSThomas Graf out:
2421ca860fb3SThomas Graf 	cb->args[0] = tidx;
2422ca860fb3SThomas Graf 	cb->args[1] = nidx;
2423c7fb64dbSThomas Graf 
2424c7fb64dbSThomas Graf 	return skb->len;
2425c7fb64dbSThomas Graf }
24261da177e4SLinus Torvalds 
24278b8aec50SThomas Graf static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
24288b8aec50SThomas Graf 			   u32 pid, u32 seq, int type, unsigned int flags)
24291da177e4SLinus Torvalds {
24301da177e4SLinus Torvalds 	unsigned long now = jiffies;
24311da177e4SLinus Torvalds 	struct nda_cacheinfo ci;
24328b8aec50SThomas Graf 	struct nlmsghdr *nlh;
24338b8aec50SThomas Graf 	struct ndmsg *ndm;
24341da177e4SLinus Torvalds 
24358b8aec50SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
24368b8aec50SThomas Graf 	if (nlh == NULL)
243726932566SPatrick McHardy 		return -EMSGSIZE;
24388b8aec50SThomas Graf 
24398b8aec50SThomas Graf 	ndm = nlmsg_data(nlh);
24408b8aec50SThomas Graf 	ndm->ndm_family	 = neigh->ops->family;
24419ef1d4c7SPatrick McHardy 	ndm->ndm_pad1    = 0;
24429ef1d4c7SPatrick McHardy 	ndm->ndm_pad2    = 0;
24438b8aec50SThomas Graf 	ndm->ndm_flags	 = neigh->flags;
24448b8aec50SThomas Graf 	ndm->ndm_type	 = neigh->type;
24458b8aec50SThomas Graf 	ndm->ndm_ifindex = neigh->dev->ifindex;
24461da177e4SLinus Torvalds 
24479a6308d7SDavid S. Miller 	if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
24489a6308d7SDavid S. Miller 		goto nla_put_failure;
24498b8aec50SThomas Graf 
24508b8aec50SThomas Graf 	read_lock_bh(&neigh->lock);
24518b8aec50SThomas Graf 	ndm->ndm_state	 = neigh->nud_state;
24520ed8ddf4SEric Dumazet 	if (neigh->nud_state & NUD_VALID) {
24530ed8ddf4SEric Dumazet 		char haddr[MAX_ADDR_LEN];
24540ed8ddf4SEric Dumazet 
24550ed8ddf4SEric Dumazet 		neigh_ha_snapshot(haddr, neigh, neigh->dev);
24560ed8ddf4SEric Dumazet 		if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
24578b8aec50SThomas Graf 			read_unlock_bh(&neigh->lock);
24588b8aec50SThomas Graf 			goto nla_put_failure;
24598b8aec50SThomas Graf 		}
24600ed8ddf4SEric Dumazet 	}
24618b8aec50SThomas Graf 
2462b9f5f52cSStephen Hemminger 	ci.ndm_used	 = jiffies_to_clock_t(now - neigh->used);
2463b9f5f52cSStephen Hemminger 	ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2464b9f5f52cSStephen Hemminger 	ci.ndm_updated	 = jiffies_to_clock_t(now - neigh->updated);
24659f237430SReshetova, Elena 	ci.ndm_refcnt	 = refcount_read(&neigh->refcnt) - 1;
24668b8aec50SThomas Graf 	read_unlock_bh(&neigh->lock);
24678b8aec50SThomas Graf 
24689a6308d7SDavid S. Miller 	if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
24699a6308d7SDavid S. Miller 	    nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
24709a6308d7SDavid S. Miller 		goto nla_put_failure;
24718b8aec50SThomas Graf 
2472df9b0e30SDavid Ahern 	if (neigh->protocol && nla_put_u8(skb, NDA_PROTOCOL, neigh->protocol))
2473df9b0e30SDavid Ahern 		goto nla_put_failure;
2474df9b0e30SDavid Ahern 
2475053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2476053c095aSJohannes Berg 	return 0;
24778b8aec50SThomas Graf 
24788b8aec50SThomas Graf nla_put_failure:
247926932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
248026932566SPatrick McHardy 	return -EMSGSIZE;
24811da177e4SLinus Torvalds }
24821da177e4SLinus Torvalds 
248384920c14STony Zelenoff static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
248484920c14STony Zelenoff 			    u32 pid, u32 seq, int type, unsigned int flags,
248584920c14STony Zelenoff 			    struct neigh_table *tbl)
248684920c14STony Zelenoff {
248784920c14STony Zelenoff 	struct nlmsghdr *nlh;
248884920c14STony Zelenoff 	struct ndmsg *ndm;
248984920c14STony Zelenoff 
249084920c14STony Zelenoff 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
249184920c14STony Zelenoff 	if (nlh == NULL)
249284920c14STony Zelenoff 		return -EMSGSIZE;
249384920c14STony Zelenoff 
249484920c14STony Zelenoff 	ndm = nlmsg_data(nlh);
249584920c14STony Zelenoff 	ndm->ndm_family	 = tbl->family;
249684920c14STony Zelenoff 	ndm->ndm_pad1    = 0;
249784920c14STony Zelenoff 	ndm->ndm_pad2    = 0;
249884920c14STony Zelenoff 	ndm->ndm_flags	 = pn->flags | NTF_PROXY;
2499545469f7SJun Zhao 	ndm->ndm_type	 = RTN_UNICAST;
25006adc5fd6SKonstantin Khlebnikov 	ndm->ndm_ifindex = pn->dev ? pn->dev->ifindex : 0;
250184920c14STony Zelenoff 	ndm->ndm_state	 = NUD_NONE;
250284920c14STony Zelenoff 
25039a6308d7SDavid S. Miller 	if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
25049a6308d7SDavid S. Miller 		goto nla_put_failure;
250584920c14STony Zelenoff 
2506df9b0e30SDavid Ahern 	if (pn->protocol && nla_put_u8(skb, NDA_PROTOCOL, pn->protocol))
2507df9b0e30SDavid Ahern 		goto nla_put_failure;
2508df9b0e30SDavid Ahern 
2509053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2510053c095aSJohannes Berg 	return 0;
251184920c14STony Zelenoff 
251284920c14STony Zelenoff nla_put_failure:
251384920c14STony Zelenoff 	nlmsg_cancel(skb, nlh);
251484920c14STony Zelenoff 	return -EMSGSIZE;
251584920c14STony Zelenoff }
251684920c14STony Zelenoff 
25177b8f7a40SRoopa Prabhu static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid)
2518d961db35SThomas Graf {
2519d961db35SThomas Graf 	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
25207b8f7a40SRoopa Prabhu 	__neigh_notify(neigh, RTM_NEWNEIGH, 0, nlmsg_pid);
2521d961db35SThomas Graf }
25221da177e4SLinus Torvalds 
252321fdd092SDavid Ahern static bool neigh_master_filtered(struct net_device *dev, int master_idx)
252421fdd092SDavid Ahern {
252521fdd092SDavid Ahern 	struct net_device *master;
252621fdd092SDavid Ahern 
252721fdd092SDavid Ahern 	if (!master_idx)
252821fdd092SDavid Ahern 		return false;
252921fdd092SDavid Ahern 
2530aab456dfSEric Dumazet 	master = dev ? netdev_master_upper_dev_get(dev) : NULL;
253121fdd092SDavid Ahern 	if (!master || master->ifindex != master_idx)
253221fdd092SDavid Ahern 		return true;
253321fdd092SDavid Ahern 
253421fdd092SDavid Ahern 	return false;
253521fdd092SDavid Ahern }
253621fdd092SDavid Ahern 
253716660f0bSDavid Ahern static bool neigh_ifindex_filtered(struct net_device *dev, int filter_idx)
253816660f0bSDavid Ahern {
2539aab456dfSEric Dumazet 	if (filter_idx && (!dev || dev->ifindex != filter_idx))
254016660f0bSDavid Ahern 		return true;
254116660f0bSDavid Ahern 
254216660f0bSDavid Ahern 	return false;
254316660f0bSDavid Ahern }
254416660f0bSDavid Ahern 
25456f52f80eSDavid Ahern struct neigh_dump_filter {
25466f52f80eSDavid Ahern 	int master_idx;
25476f52f80eSDavid Ahern 	int dev_idx;
25486f52f80eSDavid Ahern };
25496f52f80eSDavid Ahern 
25501da177e4SLinus Torvalds static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
25516f52f80eSDavid Ahern 			    struct netlink_callback *cb,
25526f52f80eSDavid Ahern 			    struct neigh_dump_filter *filter)
25531da177e4SLinus Torvalds {
25543b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
25551da177e4SLinus Torvalds 	struct neighbour *n;
25561da177e4SLinus Torvalds 	int rc, h, s_h = cb->args[1];
25571da177e4SLinus Torvalds 	int idx, s_idx = idx = cb->args[2];
2558d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
255921fdd092SDavid Ahern 	unsigned int flags = NLM_F_MULTI;
256021fdd092SDavid Ahern 
25616f52f80eSDavid Ahern 	if (filter->dev_idx || filter->master_idx)
256221fdd092SDavid Ahern 		flags |= NLM_F_DUMP_FILTERED;
25631da177e4SLinus Torvalds 
2564d6bf7817SEric Dumazet 	rcu_read_lock_bh();
2565d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
2566d6bf7817SEric Dumazet 
25674bd6683bSEric Dumazet 	for (h = s_h; h < (1 << nht->hash_shift); h++) {
25681da177e4SLinus Torvalds 		if (h > s_h)
25691da177e4SLinus Torvalds 			s_idx = 0;
2570767e97e1SEric Dumazet 		for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2571767e97e1SEric Dumazet 		     n != NULL;
2572767e97e1SEric Dumazet 		     n = rcu_dereference_bh(n->next)) {
257318502acdSZhang Shengju 			if (idx < s_idx || !net_eq(dev_net(n->dev), net))
257418502acdSZhang Shengju 				goto next;
25756f52f80eSDavid Ahern 			if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
25766f52f80eSDavid Ahern 			    neigh_master_filtered(n->dev, filter->master_idx))
2577efc683fcSGautam Kachroo 				goto next;
257815e47304SEric W. Biederman 			if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
25791da177e4SLinus Torvalds 					    cb->nlh->nlmsg_seq,
2580b6544c0bSJamal Hadi Salim 					    RTM_NEWNEIGH,
258121fdd092SDavid Ahern 					    flags) < 0) {
25821da177e4SLinus Torvalds 				rc = -1;
25831da177e4SLinus Torvalds 				goto out;
25841da177e4SLinus Torvalds 			}
2585efc683fcSGautam Kachroo next:
2586efc683fcSGautam Kachroo 			idx++;
25871da177e4SLinus Torvalds 		}
25881da177e4SLinus Torvalds 	}
25891da177e4SLinus Torvalds 	rc = skb->len;
25901da177e4SLinus Torvalds out:
2591d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
25921da177e4SLinus Torvalds 	cb->args[1] = h;
25931da177e4SLinus Torvalds 	cb->args[2] = idx;
25941da177e4SLinus Torvalds 	return rc;
25951da177e4SLinus Torvalds }
25961da177e4SLinus Torvalds 
259784920c14STony Zelenoff static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
25986f52f80eSDavid Ahern 			     struct netlink_callback *cb,
25996f52f80eSDavid Ahern 			     struct neigh_dump_filter *filter)
260084920c14STony Zelenoff {
260184920c14STony Zelenoff 	struct pneigh_entry *n;
260284920c14STony Zelenoff 	struct net *net = sock_net(skb->sk);
260384920c14STony Zelenoff 	int rc, h, s_h = cb->args[3];
260484920c14STony Zelenoff 	int idx, s_idx = idx = cb->args[4];
26056f52f80eSDavid Ahern 	unsigned int flags = NLM_F_MULTI;
26066f52f80eSDavid Ahern 
26076f52f80eSDavid Ahern 	if (filter->dev_idx || filter->master_idx)
26086f52f80eSDavid Ahern 		flags |= NLM_F_DUMP_FILTERED;
260984920c14STony Zelenoff 
261084920c14STony Zelenoff 	read_lock_bh(&tbl->lock);
261184920c14STony Zelenoff 
26124bd6683bSEric Dumazet 	for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
261384920c14STony Zelenoff 		if (h > s_h)
261484920c14STony Zelenoff 			s_idx = 0;
261584920c14STony Zelenoff 		for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
261618502acdSZhang Shengju 			if (idx < s_idx || pneigh_net(n) != net)
261784920c14STony Zelenoff 				goto next;
26186f52f80eSDavid Ahern 			if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
26196f52f80eSDavid Ahern 			    neigh_master_filtered(n->dev, filter->master_idx))
26206f52f80eSDavid Ahern 				goto next;
262115e47304SEric W. Biederman 			if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
262284920c14STony Zelenoff 					    cb->nlh->nlmsg_seq,
26236f52f80eSDavid Ahern 					    RTM_NEWNEIGH, flags, tbl) < 0) {
262484920c14STony Zelenoff 				read_unlock_bh(&tbl->lock);
262584920c14STony Zelenoff 				rc = -1;
262684920c14STony Zelenoff 				goto out;
262784920c14STony Zelenoff 			}
262884920c14STony Zelenoff 		next:
262984920c14STony Zelenoff 			idx++;
263084920c14STony Zelenoff 		}
263184920c14STony Zelenoff 	}
263284920c14STony Zelenoff 
263384920c14STony Zelenoff 	read_unlock_bh(&tbl->lock);
263484920c14STony Zelenoff 	rc = skb->len;
263584920c14STony Zelenoff out:
263684920c14STony Zelenoff 	cb->args[3] = h;
263784920c14STony Zelenoff 	cb->args[4] = idx;
263884920c14STony Zelenoff 	return rc;
263984920c14STony Zelenoff 
264084920c14STony Zelenoff }
264184920c14STony Zelenoff 
264251183d23SDavid Ahern static int neigh_valid_dump_req(const struct nlmsghdr *nlh,
264351183d23SDavid Ahern 				bool strict_check,
264451183d23SDavid Ahern 				struct neigh_dump_filter *filter,
264551183d23SDavid Ahern 				struct netlink_ext_ack *extack)
264651183d23SDavid Ahern {
264751183d23SDavid Ahern 	struct nlattr *tb[NDA_MAX + 1];
264851183d23SDavid Ahern 	int err, i;
264951183d23SDavid Ahern 
265051183d23SDavid Ahern 	if (strict_check) {
265151183d23SDavid Ahern 		struct ndmsg *ndm;
265251183d23SDavid Ahern 
265351183d23SDavid Ahern 		if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
265451183d23SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid header for neighbor dump request");
265551183d23SDavid Ahern 			return -EINVAL;
265651183d23SDavid Ahern 		}
265751183d23SDavid Ahern 
265851183d23SDavid Ahern 		ndm = nlmsg_data(nlh);
265951183d23SDavid Ahern 		if (ndm->ndm_pad1  || ndm->ndm_pad2  || ndm->ndm_ifindex ||
2660c0fde870SDavid Ahern 		    ndm->ndm_state || ndm->ndm_type) {
266151183d23SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor dump request");
266251183d23SDavid Ahern 			return -EINVAL;
266351183d23SDavid Ahern 		}
266451183d23SDavid Ahern 
2665c0fde870SDavid Ahern 		if (ndm->ndm_flags & ~NTF_PROXY) {
2666c0fde870SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor dump request");
2667c0fde870SDavid Ahern 			return -EINVAL;
2668c0fde870SDavid Ahern 		}
2669c0fde870SDavid Ahern 
26708cb08174SJohannes Berg 		err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg),
26718cb08174SJohannes Berg 						    tb, NDA_MAX, nda_policy,
26728cb08174SJohannes Berg 						    extack);
267351183d23SDavid Ahern 	} else {
26748cb08174SJohannes Berg 		err = nlmsg_parse_deprecated(nlh, sizeof(struct ndmsg), tb,
26758cb08174SJohannes Berg 					     NDA_MAX, nda_policy, extack);
267651183d23SDavid Ahern 	}
267751183d23SDavid Ahern 	if (err < 0)
267851183d23SDavid Ahern 		return err;
267951183d23SDavid Ahern 
268051183d23SDavid Ahern 	for (i = 0; i <= NDA_MAX; ++i) {
268151183d23SDavid Ahern 		if (!tb[i])
268251183d23SDavid Ahern 			continue;
268351183d23SDavid Ahern 
268451183d23SDavid Ahern 		/* all new attributes should require strict_check */
268551183d23SDavid Ahern 		switch (i) {
268651183d23SDavid Ahern 		case NDA_IFINDEX:
268751183d23SDavid Ahern 			filter->dev_idx = nla_get_u32(tb[i]);
268851183d23SDavid Ahern 			break;
268951183d23SDavid Ahern 		case NDA_MASTER:
269051183d23SDavid Ahern 			filter->master_idx = nla_get_u32(tb[i]);
269151183d23SDavid Ahern 			break;
269251183d23SDavid Ahern 		default:
269351183d23SDavid Ahern 			if (strict_check) {
269451183d23SDavid Ahern 				NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor dump request");
269551183d23SDavid Ahern 				return -EINVAL;
269651183d23SDavid Ahern 			}
269751183d23SDavid Ahern 		}
269851183d23SDavid Ahern 	}
269951183d23SDavid Ahern 
270051183d23SDavid Ahern 	return 0;
270151183d23SDavid Ahern }
270251183d23SDavid Ahern 
2703c8822a4eSThomas Graf static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
27041da177e4SLinus Torvalds {
27056f52f80eSDavid Ahern 	const struct nlmsghdr *nlh = cb->nlh;
27066f52f80eSDavid Ahern 	struct neigh_dump_filter filter = {};
27071da177e4SLinus Torvalds 	struct neigh_table *tbl;
27081da177e4SLinus Torvalds 	int t, family, s_t;
270984920c14STony Zelenoff 	int proxy = 0;
27104bd6683bSEric Dumazet 	int err;
27111da177e4SLinus Torvalds 
27126f52f80eSDavid Ahern 	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
271384920c14STony Zelenoff 
271484920c14STony Zelenoff 	/* check for full ndmsg structure presence, family member is
271584920c14STony Zelenoff 	 * the same for both structures
271684920c14STony Zelenoff 	 */
27176f52f80eSDavid Ahern 	if (nlmsg_len(nlh) >= sizeof(struct ndmsg) &&
27186f52f80eSDavid Ahern 	    ((struct ndmsg *)nlmsg_data(nlh))->ndm_flags == NTF_PROXY)
271984920c14STony Zelenoff 		proxy = 1;
272084920c14STony Zelenoff 
272151183d23SDavid Ahern 	err = neigh_valid_dump_req(nlh, cb->strict_check, &filter, cb->extack);
272251183d23SDavid Ahern 	if (err < 0 && cb->strict_check)
272351183d23SDavid Ahern 		return err;
272451183d23SDavid Ahern 
27251da177e4SLinus Torvalds 	s_t = cb->args[0];
27261da177e4SLinus Torvalds 
2727d7480fd3SWANG Cong 	for (t = 0; t < NEIGH_NR_TABLES; t++) {
2728d7480fd3SWANG Cong 		tbl = neigh_tables[t];
2729d7480fd3SWANG Cong 
2730d7480fd3SWANG Cong 		if (!tbl)
2731d7480fd3SWANG Cong 			continue;
27321da177e4SLinus Torvalds 		if (t < s_t || (family && tbl->family != family))
27331da177e4SLinus Torvalds 			continue;
27341da177e4SLinus Torvalds 		if (t > s_t)
27351da177e4SLinus Torvalds 			memset(&cb->args[1], 0, sizeof(cb->args) -
27361da177e4SLinus Torvalds 						sizeof(cb->args[0]));
273784920c14STony Zelenoff 		if (proxy)
27386f52f80eSDavid Ahern 			err = pneigh_dump_table(tbl, skb, cb, &filter);
273984920c14STony Zelenoff 		else
27406f52f80eSDavid Ahern 			err = neigh_dump_table(tbl, skb, cb, &filter);
27414bd6683bSEric Dumazet 		if (err < 0)
27424bd6683bSEric Dumazet 			break;
27431da177e4SLinus Torvalds 	}
27441da177e4SLinus Torvalds 
27451da177e4SLinus Torvalds 	cb->args[0] = t;
27461da177e4SLinus Torvalds 	return skb->len;
27471da177e4SLinus Torvalds }
27481da177e4SLinus Torvalds 
274982cbb5c6SRoopa Prabhu static int neigh_valid_get_req(const struct nlmsghdr *nlh,
275082cbb5c6SRoopa Prabhu 			       struct neigh_table **tbl,
275182cbb5c6SRoopa Prabhu 			       void **dst, int *dev_idx, u8 *ndm_flags,
275282cbb5c6SRoopa Prabhu 			       struct netlink_ext_ack *extack)
275382cbb5c6SRoopa Prabhu {
275482cbb5c6SRoopa Prabhu 	struct nlattr *tb[NDA_MAX + 1];
275582cbb5c6SRoopa Prabhu 	struct ndmsg *ndm;
275682cbb5c6SRoopa Prabhu 	int err, i;
275782cbb5c6SRoopa Prabhu 
275882cbb5c6SRoopa Prabhu 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
275982cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid header for neighbor get request");
276082cbb5c6SRoopa Prabhu 		return -EINVAL;
276182cbb5c6SRoopa Prabhu 	}
276282cbb5c6SRoopa Prabhu 
276382cbb5c6SRoopa Prabhu 	ndm = nlmsg_data(nlh);
276482cbb5c6SRoopa Prabhu 	if (ndm->ndm_pad1  || ndm->ndm_pad2  || ndm->ndm_state ||
276582cbb5c6SRoopa Prabhu 	    ndm->ndm_type) {
276682cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor get request");
276782cbb5c6SRoopa Prabhu 		return -EINVAL;
276882cbb5c6SRoopa Prabhu 	}
276982cbb5c6SRoopa Prabhu 
277082cbb5c6SRoopa Prabhu 	if (ndm->ndm_flags & ~NTF_PROXY) {
277182cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor get request");
277282cbb5c6SRoopa Prabhu 		return -EINVAL;
277382cbb5c6SRoopa Prabhu 	}
277482cbb5c6SRoopa Prabhu 
27758cb08174SJohannes Berg 	err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb,
27768cb08174SJohannes Berg 					    NDA_MAX, nda_policy, extack);
277782cbb5c6SRoopa Prabhu 	if (err < 0)
277882cbb5c6SRoopa Prabhu 		return err;
277982cbb5c6SRoopa Prabhu 
278082cbb5c6SRoopa Prabhu 	*ndm_flags = ndm->ndm_flags;
278182cbb5c6SRoopa Prabhu 	*dev_idx = ndm->ndm_ifindex;
278282cbb5c6SRoopa Prabhu 	*tbl = neigh_find_table(ndm->ndm_family);
278382cbb5c6SRoopa Prabhu 	if (*tbl == NULL) {
278482cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
278582cbb5c6SRoopa Prabhu 		return -EAFNOSUPPORT;
278682cbb5c6SRoopa Prabhu 	}
278782cbb5c6SRoopa Prabhu 
278882cbb5c6SRoopa Prabhu 	for (i = 0; i <= NDA_MAX; ++i) {
278982cbb5c6SRoopa Prabhu 		if (!tb[i])
279082cbb5c6SRoopa Prabhu 			continue;
279182cbb5c6SRoopa Prabhu 
279282cbb5c6SRoopa Prabhu 		switch (i) {
279382cbb5c6SRoopa Prabhu 		case NDA_DST:
279482cbb5c6SRoopa Prabhu 			if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
279582cbb5c6SRoopa Prabhu 				NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
279682cbb5c6SRoopa Prabhu 				return -EINVAL;
279782cbb5c6SRoopa Prabhu 			}
279882cbb5c6SRoopa Prabhu 			*dst = nla_data(tb[i]);
279982cbb5c6SRoopa Prabhu 			break;
280082cbb5c6SRoopa Prabhu 		default:
280182cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request");
280282cbb5c6SRoopa Prabhu 			return -EINVAL;
280382cbb5c6SRoopa Prabhu 		}
280482cbb5c6SRoopa Prabhu 	}
280582cbb5c6SRoopa Prabhu 
280682cbb5c6SRoopa Prabhu 	return 0;
280782cbb5c6SRoopa Prabhu }
280882cbb5c6SRoopa Prabhu 
280982cbb5c6SRoopa Prabhu static inline size_t neigh_nlmsg_size(void)
281082cbb5c6SRoopa Prabhu {
281182cbb5c6SRoopa Prabhu 	return NLMSG_ALIGN(sizeof(struct ndmsg))
281282cbb5c6SRoopa Prabhu 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
281382cbb5c6SRoopa Prabhu 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
281482cbb5c6SRoopa Prabhu 	       + nla_total_size(sizeof(struct nda_cacheinfo))
281582cbb5c6SRoopa Prabhu 	       + nla_total_size(4)  /* NDA_PROBES */
281682cbb5c6SRoopa Prabhu 	       + nla_total_size(1); /* NDA_PROTOCOL */
281782cbb5c6SRoopa Prabhu }
281882cbb5c6SRoopa Prabhu 
281982cbb5c6SRoopa Prabhu static int neigh_get_reply(struct net *net, struct neighbour *neigh,
282082cbb5c6SRoopa Prabhu 			   u32 pid, u32 seq)
282182cbb5c6SRoopa Prabhu {
282282cbb5c6SRoopa Prabhu 	struct sk_buff *skb;
282382cbb5c6SRoopa Prabhu 	int err = 0;
282482cbb5c6SRoopa Prabhu 
282582cbb5c6SRoopa Prabhu 	skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL);
282682cbb5c6SRoopa Prabhu 	if (!skb)
282782cbb5c6SRoopa Prabhu 		return -ENOBUFS;
282882cbb5c6SRoopa Prabhu 
282982cbb5c6SRoopa Prabhu 	err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0);
283082cbb5c6SRoopa Prabhu 	if (err) {
283182cbb5c6SRoopa Prabhu 		kfree_skb(skb);
283282cbb5c6SRoopa Prabhu 		goto errout;
283382cbb5c6SRoopa Prabhu 	}
283482cbb5c6SRoopa Prabhu 
283582cbb5c6SRoopa Prabhu 	err = rtnl_unicast(skb, net, pid);
283682cbb5c6SRoopa Prabhu errout:
283782cbb5c6SRoopa Prabhu 	return err;
283882cbb5c6SRoopa Prabhu }
283982cbb5c6SRoopa Prabhu 
284082cbb5c6SRoopa Prabhu static inline size_t pneigh_nlmsg_size(void)
284182cbb5c6SRoopa Prabhu {
284282cbb5c6SRoopa Prabhu 	return NLMSG_ALIGN(sizeof(struct ndmsg))
2843463561e6SColin Ian King 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
284482cbb5c6SRoopa Prabhu 	       + nla_total_size(1); /* NDA_PROTOCOL */
284582cbb5c6SRoopa Prabhu }
284682cbb5c6SRoopa Prabhu 
284782cbb5c6SRoopa Prabhu static int pneigh_get_reply(struct net *net, struct pneigh_entry *neigh,
284882cbb5c6SRoopa Prabhu 			    u32 pid, u32 seq, struct neigh_table *tbl)
284982cbb5c6SRoopa Prabhu {
285082cbb5c6SRoopa Prabhu 	struct sk_buff *skb;
285182cbb5c6SRoopa Prabhu 	int err = 0;
285282cbb5c6SRoopa Prabhu 
285382cbb5c6SRoopa Prabhu 	skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL);
285482cbb5c6SRoopa Prabhu 	if (!skb)
285582cbb5c6SRoopa Prabhu 		return -ENOBUFS;
285682cbb5c6SRoopa Prabhu 
285782cbb5c6SRoopa Prabhu 	err = pneigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0, tbl);
285882cbb5c6SRoopa Prabhu 	if (err) {
285982cbb5c6SRoopa Prabhu 		kfree_skb(skb);
286082cbb5c6SRoopa Prabhu 		goto errout;
286182cbb5c6SRoopa Prabhu 	}
286282cbb5c6SRoopa Prabhu 
286382cbb5c6SRoopa Prabhu 	err = rtnl_unicast(skb, net, pid);
286482cbb5c6SRoopa Prabhu errout:
286582cbb5c6SRoopa Prabhu 	return err;
286682cbb5c6SRoopa Prabhu }
286782cbb5c6SRoopa Prabhu 
286882cbb5c6SRoopa Prabhu static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
286982cbb5c6SRoopa Prabhu 		     struct netlink_ext_ack *extack)
287082cbb5c6SRoopa Prabhu {
287182cbb5c6SRoopa Prabhu 	struct net *net = sock_net(in_skb->sk);
287282cbb5c6SRoopa Prabhu 	struct net_device *dev = NULL;
287382cbb5c6SRoopa Prabhu 	struct neigh_table *tbl = NULL;
287482cbb5c6SRoopa Prabhu 	struct neighbour *neigh;
287582cbb5c6SRoopa Prabhu 	void *dst = NULL;
287682cbb5c6SRoopa Prabhu 	u8 ndm_flags = 0;
287782cbb5c6SRoopa Prabhu 	int dev_idx = 0;
287882cbb5c6SRoopa Prabhu 	int err;
287982cbb5c6SRoopa Prabhu 
288082cbb5c6SRoopa Prabhu 	err = neigh_valid_get_req(nlh, &tbl, &dst, &dev_idx, &ndm_flags,
288182cbb5c6SRoopa Prabhu 				  extack);
288282cbb5c6SRoopa Prabhu 	if (err < 0)
288382cbb5c6SRoopa Prabhu 		return err;
288482cbb5c6SRoopa Prabhu 
288582cbb5c6SRoopa Prabhu 	if (dev_idx) {
288682cbb5c6SRoopa Prabhu 		dev = __dev_get_by_index(net, dev_idx);
288782cbb5c6SRoopa Prabhu 		if (!dev) {
288882cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Unknown device ifindex");
288982cbb5c6SRoopa Prabhu 			return -ENODEV;
289082cbb5c6SRoopa Prabhu 		}
289182cbb5c6SRoopa Prabhu 	}
289282cbb5c6SRoopa Prabhu 
289382cbb5c6SRoopa Prabhu 	if (!dst) {
289482cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Network address not specified");
289582cbb5c6SRoopa Prabhu 		return -EINVAL;
289682cbb5c6SRoopa Prabhu 	}
289782cbb5c6SRoopa Prabhu 
289882cbb5c6SRoopa Prabhu 	if (ndm_flags & NTF_PROXY) {
289982cbb5c6SRoopa Prabhu 		struct pneigh_entry *pn;
290082cbb5c6SRoopa Prabhu 
290182cbb5c6SRoopa Prabhu 		pn = pneigh_lookup(tbl, net, dst, dev, 0);
290282cbb5c6SRoopa Prabhu 		if (!pn) {
290382cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Proxy neighbour entry not found");
290482cbb5c6SRoopa Prabhu 			return -ENOENT;
290582cbb5c6SRoopa Prabhu 		}
290682cbb5c6SRoopa Prabhu 		return pneigh_get_reply(net, pn, NETLINK_CB(in_skb).portid,
290782cbb5c6SRoopa Prabhu 					nlh->nlmsg_seq, tbl);
290882cbb5c6SRoopa Prabhu 	}
290982cbb5c6SRoopa Prabhu 
291082cbb5c6SRoopa Prabhu 	if (!dev) {
291182cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "No device specified");
291282cbb5c6SRoopa Prabhu 		return -EINVAL;
291382cbb5c6SRoopa Prabhu 	}
291482cbb5c6SRoopa Prabhu 
291582cbb5c6SRoopa Prabhu 	neigh = neigh_lookup(tbl, dst, dev);
291682cbb5c6SRoopa Prabhu 	if (!neigh) {
291782cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Neighbour entry not found");
291882cbb5c6SRoopa Prabhu 		return -ENOENT;
291982cbb5c6SRoopa Prabhu 	}
292082cbb5c6SRoopa Prabhu 
292182cbb5c6SRoopa Prabhu 	err = neigh_get_reply(net, neigh, NETLINK_CB(in_skb).portid,
292282cbb5c6SRoopa Prabhu 			      nlh->nlmsg_seq);
292382cbb5c6SRoopa Prabhu 
292482cbb5c6SRoopa Prabhu 	neigh_release(neigh);
292582cbb5c6SRoopa Prabhu 
292682cbb5c6SRoopa Prabhu 	return err;
292782cbb5c6SRoopa Prabhu }
292882cbb5c6SRoopa Prabhu 
29291da177e4SLinus Torvalds void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
29301da177e4SLinus Torvalds {
29311da177e4SLinus Torvalds 	int chain;
2932d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
29331da177e4SLinus Torvalds 
2934d6bf7817SEric Dumazet 	rcu_read_lock_bh();
2935d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
2936d6bf7817SEric Dumazet 
2937767e97e1SEric Dumazet 	read_lock(&tbl->lock); /* avoid resizes */
2938cd089336SDavid S. Miller 	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
29391da177e4SLinus Torvalds 		struct neighbour *n;
29401da177e4SLinus Torvalds 
2941767e97e1SEric Dumazet 		for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
2942767e97e1SEric Dumazet 		     n != NULL;
2943767e97e1SEric Dumazet 		     n = rcu_dereference_bh(n->next))
29441da177e4SLinus Torvalds 			cb(n, cookie);
29451da177e4SLinus Torvalds 	}
2946d6bf7817SEric Dumazet 	read_unlock(&tbl->lock);
2947d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
29481da177e4SLinus Torvalds }
29491da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_for_each);
29501da177e4SLinus Torvalds 
29511da177e4SLinus Torvalds /* The tbl->lock must be held as a writer and BH disabled. */
29521da177e4SLinus Torvalds void __neigh_for_each_release(struct neigh_table *tbl,
29531da177e4SLinus Torvalds 			      int (*cb)(struct neighbour *))
29541da177e4SLinus Torvalds {
29551da177e4SLinus Torvalds 	int chain;
2956d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
29571da177e4SLinus Torvalds 
2958d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
2959d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
2960cd089336SDavid S. Miller 	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
2961767e97e1SEric Dumazet 		struct neighbour *n;
2962767e97e1SEric Dumazet 		struct neighbour __rcu **np;
29631da177e4SLinus Torvalds 
2964d6bf7817SEric Dumazet 		np = &nht->hash_buckets[chain];
2965767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
2966767e97e1SEric Dumazet 					lockdep_is_held(&tbl->lock))) != NULL) {
29671da177e4SLinus Torvalds 			int release;
29681da177e4SLinus Torvalds 
29691da177e4SLinus Torvalds 			write_lock(&n->lock);
29701da177e4SLinus Torvalds 			release = cb(n);
29711da177e4SLinus Torvalds 			if (release) {
2972767e97e1SEric Dumazet 				rcu_assign_pointer(*np,
2973767e97e1SEric Dumazet 					rcu_dereference_protected(n->next,
2974767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
297558956317SDavid Ahern 				neigh_mark_dead(n);
29761da177e4SLinus Torvalds 			} else
29771da177e4SLinus Torvalds 				np = &n->next;
29781da177e4SLinus Torvalds 			write_unlock(&n->lock);
29794f494554SThomas Graf 			if (release)
29804f494554SThomas Graf 				neigh_cleanup_and_release(n);
29811da177e4SLinus Torvalds 		}
29821da177e4SLinus Torvalds 	}
2983ecbb4169SAlexey Kuznetsov }
29841da177e4SLinus Torvalds EXPORT_SYMBOL(__neigh_for_each_release);
29851da177e4SLinus Torvalds 
2986b79bda3dSEric W. Biederman int neigh_xmit(int index, struct net_device *dev,
29874fd3d7d9SEric W. Biederman 	       const void *addr, struct sk_buff *skb)
29884fd3d7d9SEric W. Biederman {
2989b79bda3dSEric W. Biederman 	int err = -EAFNOSUPPORT;
2990b79bda3dSEric W. Biederman 	if (likely(index < NEIGH_NR_TABLES)) {
29914fd3d7d9SEric W. Biederman 		struct neigh_table *tbl;
29924fd3d7d9SEric W. Biederman 		struct neighbour *neigh;
29934fd3d7d9SEric W. Biederman 
2994b79bda3dSEric W. Biederman 		tbl = neigh_tables[index];
29954fd3d7d9SEric W. Biederman 		if (!tbl)
29964fd3d7d9SEric W. Biederman 			goto out;
2997b560f03dSDavid Barroso 		rcu_read_lock_bh();
29984b2a2bfeSDavid Ahern 		if (index == NEIGH_ARP_TABLE) {
29994b2a2bfeSDavid Ahern 			u32 key = *((u32 *)addr);
30004b2a2bfeSDavid Ahern 
30014b2a2bfeSDavid Ahern 			neigh = __ipv4_neigh_lookup_noref(dev, key);
30024b2a2bfeSDavid Ahern 		} else {
30034fd3d7d9SEric W. Biederman 			neigh = __neigh_lookup_noref(tbl, addr, dev);
30044b2a2bfeSDavid Ahern 		}
30054fd3d7d9SEric W. Biederman 		if (!neigh)
30064fd3d7d9SEric W. Biederman 			neigh = __neigh_create(tbl, addr, dev, false);
30074fd3d7d9SEric W. Biederman 		err = PTR_ERR(neigh);
3008b560f03dSDavid Barroso 		if (IS_ERR(neigh)) {
3009b560f03dSDavid Barroso 			rcu_read_unlock_bh();
30104fd3d7d9SEric W. Biederman 			goto out_kfree_skb;
3011b560f03dSDavid Barroso 		}
30124fd3d7d9SEric W. Biederman 		err = neigh->output(neigh, skb);
3013b560f03dSDavid Barroso 		rcu_read_unlock_bh();
30144fd3d7d9SEric W. Biederman 	}
3015b79bda3dSEric W. Biederman 	else if (index == NEIGH_LINK_TABLE) {
3016b79bda3dSEric W. Biederman 		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
3017b79bda3dSEric W. Biederman 				      addr, NULL, skb->len);
3018b79bda3dSEric W. Biederman 		if (err < 0)
3019b79bda3dSEric W. Biederman 			goto out_kfree_skb;
3020b79bda3dSEric W. Biederman 		err = dev_queue_xmit(skb);
3021b79bda3dSEric W. Biederman 	}
30224fd3d7d9SEric W. Biederman out:
30234fd3d7d9SEric W. Biederman 	return err;
30244fd3d7d9SEric W. Biederman out_kfree_skb:
30254fd3d7d9SEric W. Biederman 	kfree_skb(skb);
30264fd3d7d9SEric W. Biederman 	goto out;
30274fd3d7d9SEric W. Biederman }
30284fd3d7d9SEric W. Biederman EXPORT_SYMBOL(neigh_xmit);
30294fd3d7d9SEric W. Biederman 
30301da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
30311da177e4SLinus Torvalds 
30321da177e4SLinus Torvalds static struct neighbour *neigh_get_first(struct seq_file *seq)
30331da177e4SLinus Torvalds {
30341da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
30351218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
3036d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = state->nht;
30371da177e4SLinus Torvalds 	struct neighbour *n = NULL;
3038f530eed6SColin Ian King 	int bucket;
30391da177e4SLinus Torvalds 
30401da177e4SLinus Torvalds 	state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
3041cd089336SDavid S. Miller 	for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
3042767e97e1SEric Dumazet 		n = rcu_dereference_bh(nht->hash_buckets[bucket]);
30431da177e4SLinus Torvalds 
30441da177e4SLinus Torvalds 		while (n) {
3045878628fbSYOSHIFUJI Hideaki 			if (!net_eq(dev_net(n->dev), net))
3046426b5303SEric W. Biederman 				goto next;
30471da177e4SLinus Torvalds 			if (state->neigh_sub_iter) {
30481da177e4SLinus Torvalds 				loff_t fakep = 0;
30491da177e4SLinus Torvalds 				void *v;
30501da177e4SLinus Torvalds 
30511da177e4SLinus Torvalds 				v = state->neigh_sub_iter(state, n, &fakep);
30521da177e4SLinus Torvalds 				if (!v)
30531da177e4SLinus Torvalds 					goto next;
30541da177e4SLinus Torvalds 			}
30551da177e4SLinus Torvalds 			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
30561da177e4SLinus Torvalds 				break;
30571da177e4SLinus Torvalds 			if (n->nud_state & ~NUD_NOARP)
30581da177e4SLinus Torvalds 				break;
30591da177e4SLinus Torvalds next:
3060767e97e1SEric Dumazet 			n = rcu_dereference_bh(n->next);
30611da177e4SLinus Torvalds 		}
30621da177e4SLinus Torvalds 
30631da177e4SLinus Torvalds 		if (n)
30641da177e4SLinus Torvalds 			break;
30651da177e4SLinus Torvalds 	}
30661da177e4SLinus Torvalds 	state->bucket = bucket;
30671da177e4SLinus Torvalds 
30681da177e4SLinus Torvalds 	return n;
30691da177e4SLinus Torvalds }
30701da177e4SLinus Torvalds 
30711da177e4SLinus Torvalds static struct neighbour *neigh_get_next(struct seq_file *seq,
30721da177e4SLinus Torvalds 					struct neighbour *n,
30731da177e4SLinus Torvalds 					loff_t *pos)
30741da177e4SLinus Torvalds {
30751da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
30761218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
3077d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = state->nht;
30781da177e4SLinus Torvalds 
30791da177e4SLinus Torvalds 	if (state->neigh_sub_iter) {
30801da177e4SLinus Torvalds 		void *v = state->neigh_sub_iter(state, n, pos);
30811da177e4SLinus Torvalds 		if (v)
30821da177e4SLinus Torvalds 			return n;
30831da177e4SLinus Torvalds 	}
3084767e97e1SEric Dumazet 	n = rcu_dereference_bh(n->next);
30851da177e4SLinus Torvalds 
30861da177e4SLinus Torvalds 	while (1) {
30871da177e4SLinus Torvalds 		while (n) {
3088878628fbSYOSHIFUJI Hideaki 			if (!net_eq(dev_net(n->dev), net))
3089426b5303SEric W. Biederman 				goto next;
30901da177e4SLinus Torvalds 			if (state->neigh_sub_iter) {
30911da177e4SLinus Torvalds 				void *v = state->neigh_sub_iter(state, n, pos);
30921da177e4SLinus Torvalds 				if (v)
30931da177e4SLinus Torvalds 					return n;
30941da177e4SLinus Torvalds 				goto next;
30951da177e4SLinus Torvalds 			}
30961da177e4SLinus Torvalds 			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
30971da177e4SLinus Torvalds 				break;
30981da177e4SLinus Torvalds 
30991da177e4SLinus Torvalds 			if (n->nud_state & ~NUD_NOARP)
31001da177e4SLinus Torvalds 				break;
31011da177e4SLinus Torvalds next:
3102767e97e1SEric Dumazet 			n = rcu_dereference_bh(n->next);
31031da177e4SLinus Torvalds 		}
31041da177e4SLinus Torvalds 
31051da177e4SLinus Torvalds 		if (n)
31061da177e4SLinus Torvalds 			break;
31071da177e4SLinus Torvalds 
3108cd089336SDavid S. Miller 		if (++state->bucket >= (1 << nht->hash_shift))
31091da177e4SLinus Torvalds 			break;
31101da177e4SLinus Torvalds 
3111767e97e1SEric Dumazet 		n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
31121da177e4SLinus Torvalds 	}
31131da177e4SLinus Torvalds 
31141da177e4SLinus Torvalds 	if (n && pos)
31151da177e4SLinus Torvalds 		--(*pos);
31161da177e4SLinus Torvalds 	return n;
31171da177e4SLinus Torvalds }
31181da177e4SLinus Torvalds 
31191da177e4SLinus Torvalds static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
31201da177e4SLinus Torvalds {
31211da177e4SLinus Torvalds 	struct neighbour *n = neigh_get_first(seq);
31221da177e4SLinus Torvalds 
31231da177e4SLinus Torvalds 	if (n) {
3124745e2031SChris Larson 		--(*pos);
31251da177e4SLinus Torvalds 		while (*pos) {
31261da177e4SLinus Torvalds 			n = neigh_get_next(seq, n, pos);
31271da177e4SLinus Torvalds 			if (!n)
31281da177e4SLinus Torvalds 				break;
31291da177e4SLinus Torvalds 		}
31301da177e4SLinus Torvalds 	}
31311da177e4SLinus Torvalds 	return *pos ? NULL : n;
31321da177e4SLinus Torvalds }
31331da177e4SLinus Torvalds 
31341da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
31351da177e4SLinus Torvalds {
31361da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
31371218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
31381da177e4SLinus Torvalds 	struct neigh_table *tbl = state->tbl;
31391da177e4SLinus Torvalds 	struct pneigh_entry *pn = NULL;
31401da177e4SLinus Torvalds 	int bucket = state->bucket;
31411da177e4SLinus Torvalds 
31421da177e4SLinus Torvalds 	state->flags |= NEIGH_SEQ_IS_PNEIGH;
31431da177e4SLinus Torvalds 	for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
31441da177e4SLinus Torvalds 		pn = tbl->phash_buckets[bucket];
3145878628fbSYOSHIFUJI Hideaki 		while (pn && !net_eq(pneigh_net(pn), net))
3146426b5303SEric W. Biederman 			pn = pn->next;
31471da177e4SLinus Torvalds 		if (pn)
31481da177e4SLinus Torvalds 			break;
31491da177e4SLinus Torvalds 	}
31501da177e4SLinus Torvalds 	state->bucket = bucket;
31511da177e4SLinus Torvalds 
31521da177e4SLinus Torvalds 	return pn;
31531da177e4SLinus Torvalds }
31541da177e4SLinus Torvalds 
31551da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
31561da177e4SLinus Torvalds 					    struct pneigh_entry *pn,
31571da177e4SLinus Torvalds 					    loff_t *pos)
31581da177e4SLinus Torvalds {
31591da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
31601218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
31611da177e4SLinus Torvalds 	struct neigh_table *tbl = state->tbl;
31621da177e4SLinus Torvalds 
3163df07a94cSJorge Boncompte [DTI2] 	do {
31641da177e4SLinus Torvalds 		pn = pn->next;
3165df07a94cSJorge Boncompte [DTI2] 	} while (pn && !net_eq(pneigh_net(pn), net));
3166df07a94cSJorge Boncompte [DTI2] 
31671da177e4SLinus Torvalds 	while (!pn) {
31681da177e4SLinus Torvalds 		if (++state->bucket > PNEIGH_HASHMASK)
31691da177e4SLinus Torvalds 			break;
31701da177e4SLinus Torvalds 		pn = tbl->phash_buckets[state->bucket];
3171878628fbSYOSHIFUJI Hideaki 		while (pn && !net_eq(pneigh_net(pn), net))
3172426b5303SEric W. Biederman 			pn = pn->next;
31731da177e4SLinus Torvalds 		if (pn)
31741da177e4SLinus Torvalds 			break;
31751da177e4SLinus Torvalds 	}
31761da177e4SLinus Torvalds 
31771da177e4SLinus Torvalds 	if (pn && pos)
31781da177e4SLinus Torvalds 		--(*pos);
31791da177e4SLinus Torvalds 
31801da177e4SLinus Torvalds 	return pn;
31811da177e4SLinus Torvalds }
31821da177e4SLinus Torvalds 
31831da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
31841da177e4SLinus Torvalds {
31851da177e4SLinus Torvalds 	struct pneigh_entry *pn = pneigh_get_first(seq);
31861da177e4SLinus Torvalds 
31871da177e4SLinus Torvalds 	if (pn) {
3188745e2031SChris Larson 		--(*pos);
31891da177e4SLinus Torvalds 		while (*pos) {
31901da177e4SLinus Torvalds 			pn = pneigh_get_next(seq, pn, pos);
31911da177e4SLinus Torvalds 			if (!pn)
31921da177e4SLinus Torvalds 				break;
31931da177e4SLinus Torvalds 		}
31941da177e4SLinus Torvalds 	}
31951da177e4SLinus Torvalds 	return *pos ? NULL : pn;
31961da177e4SLinus Torvalds }
31971da177e4SLinus Torvalds 
31981da177e4SLinus Torvalds static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
31991da177e4SLinus Torvalds {
32001da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
32011da177e4SLinus Torvalds 	void *rc;
3202745e2031SChris Larson 	loff_t idxpos = *pos;
32031da177e4SLinus Torvalds 
3204745e2031SChris Larson 	rc = neigh_get_idx(seq, &idxpos);
32051da177e4SLinus Torvalds 	if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
3206745e2031SChris Larson 		rc = pneigh_get_idx(seq, &idxpos);
32071da177e4SLinus Torvalds 
32081da177e4SLinus Torvalds 	return rc;
32091da177e4SLinus Torvalds }
32101da177e4SLinus Torvalds 
32111da177e4SLinus Torvalds void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags)
3212f3e92cb8SEric Dumazet 	__acquires(tbl->lock)
3213d6bf7817SEric Dumazet 	__acquires(rcu_bh)
32141da177e4SLinus Torvalds {
32151da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
32161da177e4SLinus Torvalds 
32171da177e4SLinus Torvalds 	state->tbl = tbl;
32181da177e4SLinus Torvalds 	state->bucket = 0;
32191da177e4SLinus Torvalds 	state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
32201da177e4SLinus Torvalds 
3221d6bf7817SEric Dumazet 	rcu_read_lock_bh();
3222d6bf7817SEric Dumazet 	state->nht = rcu_dereference_bh(tbl->nht);
3223f3e92cb8SEric Dumazet 	read_lock(&tbl->lock);
3224767e97e1SEric Dumazet 
3225745e2031SChris Larson 	return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
32261da177e4SLinus Torvalds }
32271da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_start);
32281da177e4SLinus Torvalds 
32291da177e4SLinus Torvalds void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
32301da177e4SLinus Torvalds {
32311da177e4SLinus Torvalds 	struct neigh_seq_state *state;
32321da177e4SLinus Torvalds 	void *rc;
32331da177e4SLinus Torvalds 
32341da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN) {
3235bff69732SChris Larson 		rc = neigh_get_first(seq);
32361da177e4SLinus Torvalds 		goto out;
32371da177e4SLinus Torvalds 	}
32381da177e4SLinus Torvalds 
32391da177e4SLinus Torvalds 	state = seq->private;
32401da177e4SLinus Torvalds 	if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
32411da177e4SLinus Torvalds 		rc = neigh_get_next(seq, v, NULL);
32421da177e4SLinus Torvalds 		if (rc)
32431da177e4SLinus Torvalds 			goto out;
32441da177e4SLinus Torvalds 		if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
32451da177e4SLinus Torvalds 			rc = pneigh_get_first(seq);
32461da177e4SLinus Torvalds 	} else {
32471da177e4SLinus Torvalds 		BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
32481da177e4SLinus Torvalds 		rc = pneigh_get_next(seq, v, NULL);
32491da177e4SLinus Torvalds 	}
32501da177e4SLinus Torvalds out:
32511da177e4SLinus Torvalds 	++(*pos);
32521da177e4SLinus Torvalds 	return rc;
32531da177e4SLinus Torvalds }
32541da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_next);
32551da177e4SLinus Torvalds 
32561da177e4SLinus Torvalds void neigh_seq_stop(struct seq_file *seq, void *v)
3257f3e92cb8SEric Dumazet 	__releases(tbl->lock)
3258d6bf7817SEric Dumazet 	__releases(rcu_bh)
32591da177e4SLinus Torvalds {
3260f3e92cb8SEric Dumazet 	struct neigh_seq_state *state = seq->private;
3261f3e92cb8SEric Dumazet 	struct neigh_table *tbl = state->tbl;
3262f3e92cb8SEric Dumazet 
3263f3e92cb8SEric Dumazet 	read_unlock(&tbl->lock);
3264d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
32651da177e4SLinus Torvalds }
32661da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_stop);
32671da177e4SLinus Torvalds 
32681da177e4SLinus Torvalds /* statistics via seq_file */
32691da177e4SLinus Torvalds 
32701da177e4SLinus Torvalds static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
32711da177e4SLinus Torvalds {
327271a5053aSChristoph Hellwig 	struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
32731da177e4SLinus Torvalds 	int cpu;
32741da177e4SLinus Torvalds 
32751da177e4SLinus Torvalds 	if (*pos == 0)
32761da177e4SLinus Torvalds 		return SEQ_START_TOKEN;
32771da177e4SLinus Torvalds 
32780f23174aSRusty Russell 	for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
32791da177e4SLinus Torvalds 		if (!cpu_possible(cpu))
32801da177e4SLinus Torvalds 			continue;
32811da177e4SLinus Torvalds 		*pos = cpu+1;
32821da177e4SLinus Torvalds 		return per_cpu_ptr(tbl->stats, cpu);
32831da177e4SLinus Torvalds 	}
32841da177e4SLinus Torvalds 	return NULL;
32851da177e4SLinus Torvalds }
32861da177e4SLinus Torvalds 
32871da177e4SLinus Torvalds static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
32881da177e4SLinus Torvalds {
328971a5053aSChristoph Hellwig 	struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
32901da177e4SLinus Torvalds 	int cpu;
32911da177e4SLinus Torvalds 
32920f23174aSRusty Russell 	for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
32931da177e4SLinus Torvalds 		if (!cpu_possible(cpu))
32941da177e4SLinus Torvalds 			continue;
32951da177e4SLinus Torvalds 		*pos = cpu+1;
32961da177e4SLinus Torvalds 		return per_cpu_ptr(tbl->stats, cpu);
32971da177e4SLinus Torvalds 	}
32981e3f9f07SVasily Averin 	(*pos)++;
32991da177e4SLinus Torvalds 	return NULL;
33001da177e4SLinus Torvalds }
33011da177e4SLinus Torvalds 
33021da177e4SLinus Torvalds static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
33031da177e4SLinus Torvalds {
33041da177e4SLinus Torvalds 
33051da177e4SLinus Torvalds }
33061da177e4SLinus Torvalds 
33071da177e4SLinus Torvalds static int neigh_stat_seq_show(struct seq_file *seq, void *v)
33081da177e4SLinus Torvalds {
330971a5053aSChristoph Hellwig 	struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
33101da177e4SLinus Torvalds 	struct neigh_statistics *st = v;
33111da177e4SLinus Torvalds 
33121da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN) {
3313fb811395SRick Jones 		seq_printf(seq, "entries  allocs destroys hash_grows  lookups hits  res_failed  rcv_probes_mcast rcv_probes_ucast  periodic_gc_runs forced_gc_runs unresolved_discards table_fulls\n");
33141da177e4SLinus Torvalds 		return 0;
33151da177e4SLinus Torvalds 	}
33161da177e4SLinus Torvalds 
33171da177e4SLinus Torvalds 	seq_printf(seq, "%08x  %08lx %08lx %08lx  %08lx %08lx  %08lx  "
3318fb811395SRick Jones 			"%08lx %08lx  %08lx %08lx %08lx %08lx\n",
33191da177e4SLinus Torvalds 		   atomic_read(&tbl->entries),
33201da177e4SLinus Torvalds 
33211da177e4SLinus Torvalds 		   st->allocs,
33221da177e4SLinus Torvalds 		   st->destroys,
33231da177e4SLinus Torvalds 		   st->hash_grows,
33241da177e4SLinus Torvalds 
33251da177e4SLinus Torvalds 		   st->lookups,
33261da177e4SLinus Torvalds 		   st->hits,
33271da177e4SLinus Torvalds 
33281da177e4SLinus Torvalds 		   st->res_failed,
33291da177e4SLinus Torvalds 
33301da177e4SLinus Torvalds 		   st->rcv_probes_mcast,
33311da177e4SLinus Torvalds 		   st->rcv_probes_ucast,
33321da177e4SLinus Torvalds 
33331da177e4SLinus Torvalds 		   st->periodic_gc_runs,
33349a6d276eSNeil Horman 		   st->forced_gc_runs,
3335fb811395SRick Jones 		   st->unres_discards,
3336fb811395SRick Jones 		   st->table_fulls
33371da177e4SLinus Torvalds 		   );
33381da177e4SLinus Torvalds 
33391da177e4SLinus Torvalds 	return 0;
33401da177e4SLinus Torvalds }
33411da177e4SLinus Torvalds 
3342f690808eSStephen Hemminger static const struct seq_operations neigh_stat_seq_ops = {
33431da177e4SLinus Torvalds 	.start	= neigh_stat_seq_start,
33441da177e4SLinus Torvalds 	.next	= neigh_stat_seq_next,
33451da177e4SLinus Torvalds 	.stop	= neigh_stat_seq_stop,
33461da177e4SLinus Torvalds 	.show	= neigh_stat_seq_show,
33471da177e4SLinus Torvalds };
33481da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */
33491da177e4SLinus Torvalds 
33507b8f7a40SRoopa Prabhu static void __neigh_notify(struct neighbour *n, int type, int flags,
33517b8f7a40SRoopa Prabhu 			   u32 pid)
33521da177e4SLinus Torvalds {
3353c346dca1SYOSHIFUJI Hideaki 	struct net *net = dev_net(n->dev);
33548b8aec50SThomas Graf 	struct sk_buff *skb;
3355b8673311SThomas Graf 	int err = -ENOBUFS;
33561da177e4SLinus Torvalds 
3357339bf98fSThomas Graf 	skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
33588b8aec50SThomas Graf 	if (skb == NULL)
3359b8673311SThomas Graf 		goto errout;
33601da177e4SLinus Torvalds 
33617b8f7a40SRoopa Prabhu 	err = neigh_fill_info(skb, n, pid, 0, type, flags);
336226932566SPatrick McHardy 	if (err < 0) {
336326932566SPatrick McHardy 		/* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
336426932566SPatrick McHardy 		WARN_ON(err == -EMSGSIZE);
336526932566SPatrick McHardy 		kfree_skb(skb);
336626932566SPatrick McHardy 		goto errout;
336726932566SPatrick McHardy 	}
33681ce85fe4SPablo Neira Ayuso 	rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
33691ce85fe4SPablo Neira Ayuso 	return;
3370b8673311SThomas Graf errout:
3371b8673311SThomas Graf 	if (err < 0)
3372426b5303SEric W. Biederman 		rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
3373b8673311SThomas Graf }
3374b8673311SThomas Graf 
3375b8673311SThomas Graf void neigh_app_ns(struct neighbour *n)
3376b8673311SThomas Graf {
33777b8f7a40SRoopa Prabhu 	__neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST, 0);
33788b8aec50SThomas Graf }
33790a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_app_ns);
33801da177e4SLinus Torvalds 
33811da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL
3382b93196dcSCong Wang static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
33831da177e4SLinus Torvalds 
3384fe2c6338SJoe Perches static int proc_unres_qlen(struct ctl_table *ctl, int write,
338532927393SChristoph Hellwig 			   void *buffer, size_t *lenp, loff_t *ppos)
33868b5c171bSEric Dumazet {
33878b5c171bSEric Dumazet 	int size, ret;
3388fe2c6338SJoe Perches 	struct ctl_table tmp = *ctl;
33898b5c171bSEric Dumazet 
3390eec4844fSMatteo Croce 	tmp.extra1 = SYSCTL_ZERO;
3391ce46cc64SShan Wei 	tmp.extra2 = &unres_qlen_max;
33928b5c171bSEric Dumazet 	tmp.data = &size;
3393ce46cc64SShan Wei 
3394ce46cc64SShan Wei 	size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN);
3395ce46cc64SShan Wei 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
3396ce46cc64SShan Wei 
33978b5c171bSEric Dumazet 	if (write && !ret)
33988b5c171bSEric Dumazet 		*(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
33998b5c171bSEric Dumazet 	return ret;
34008b5c171bSEric Dumazet }
34018b5c171bSEric Dumazet 
34021d4c8c29SJiri Pirko static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
34031d4c8c29SJiri Pirko 						   int family)
34041d4c8c29SJiri Pirko {
3405bba24896SJiri Pirko 	switch (family) {
3406bba24896SJiri Pirko 	case AF_INET:
34071d4c8c29SJiri Pirko 		return __in_dev_arp_parms_get_rcu(dev);
3408bba24896SJiri Pirko 	case AF_INET6:
3409bba24896SJiri Pirko 		return __in6_dev_nd_parms_get_rcu(dev);
3410bba24896SJiri Pirko 	}
34111d4c8c29SJiri Pirko 	return NULL;
34121d4c8c29SJiri Pirko }
34131d4c8c29SJiri Pirko 
34141d4c8c29SJiri Pirko static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
34151d4c8c29SJiri Pirko 				  int index)
34161d4c8c29SJiri Pirko {
34171d4c8c29SJiri Pirko 	struct net_device *dev;
34181d4c8c29SJiri Pirko 	int family = neigh_parms_family(p);
34191d4c8c29SJiri Pirko 
34201d4c8c29SJiri Pirko 	rcu_read_lock();
34211d4c8c29SJiri Pirko 	for_each_netdev_rcu(net, dev) {
34221d4c8c29SJiri Pirko 		struct neigh_parms *dst_p =
34231d4c8c29SJiri Pirko 				neigh_get_dev_parms_rcu(dev, family);
34241d4c8c29SJiri Pirko 
34251d4c8c29SJiri Pirko 		if (dst_p && !test_bit(index, dst_p->data_state))
34261d4c8c29SJiri Pirko 			dst_p->data[index] = p->data[index];
34271d4c8c29SJiri Pirko 	}
34281d4c8c29SJiri Pirko 	rcu_read_unlock();
34291d4c8c29SJiri Pirko }
34301d4c8c29SJiri Pirko 
34311d4c8c29SJiri Pirko static void neigh_proc_update(struct ctl_table *ctl, int write)
34321d4c8c29SJiri Pirko {
34331d4c8c29SJiri Pirko 	struct net_device *dev = ctl->extra1;
34341d4c8c29SJiri Pirko 	struct neigh_parms *p = ctl->extra2;
343577d47afbSJiri Pirko 	struct net *net = neigh_parms_net(p);
34361d4c8c29SJiri Pirko 	int index = (int *) ctl->data - p->data;
34371d4c8c29SJiri Pirko 
34381d4c8c29SJiri Pirko 	if (!write)
34391d4c8c29SJiri Pirko 		return;
34401d4c8c29SJiri Pirko 
34411d4c8c29SJiri Pirko 	set_bit(index, p->data_state);
34427627ae60SMarcus Huewe 	if (index == NEIGH_VAR_DELAY_PROBE_TIME)
34432a4501aeSIdo Schimmel 		call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
34441d4c8c29SJiri Pirko 	if (!dev) /* NULL dev means this is default value */
34451d4c8c29SJiri Pirko 		neigh_copy_dflt_parms(net, p, index);
34461d4c8c29SJiri Pirko }
34471d4c8c29SJiri Pirko 
34481f9248e5SJiri Pirko static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
344932927393SChristoph Hellwig 					   void *buffer, size_t *lenp,
345032927393SChristoph Hellwig 					   loff_t *ppos)
34511f9248e5SJiri Pirko {
34521f9248e5SJiri Pirko 	struct ctl_table tmp = *ctl;
34531d4c8c29SJiri Pirko 	int ret;
34541f9248e5SJiri Pirko 
3455eec4844fSMatteo Croce 	tmp.extra1 = SYSCTL_ZERO;
3456eec4844fSMatteo Croce 	tmp.extra2 = SYSCTL_INT_MAX;
34571f9248e5SJiri Pirko 
34581d4c8c29SJiri Pirko 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
34591d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
34601d4c8c29SJiri Pirko 	return ret;
34611f9248e5SJiri Pirko }
34621f9248e5SJiri Pirko 
346332927393SChristoph Hellwig int neigh_proc_dointvec(struct ctl_table *ctl, int write, void *buffer,
346432927393SChristoph Hellwig 			size_t *lenp, loff_t *ppos)
3465cb5b09c1SJiri Pirko {
34661d4c8c29SJiri Pirko 	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
34671d4c8c29SJiri Pirko 
34681d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
34691d4c8c29SJiri Pirko 	return ret;
3470cb5b09c1SJiri Pirko }
3471cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec);
3472cb5b09c1SJiri Pirko 
347332927393SChristoph Hellwig int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, void *buffer,
3474cb5b09c1SJiri Pirko 				size_t *lenp, loff_t *ppos)
3475cb5b09c1SJiri Pirko {
34761d4c8c29SJiri Pirko 	int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
34771d4c8c29SJiri Pirko 
34781d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
34791d4c8c29SJiri Pirko 	return ret;
3480cb5b09c1SJiri Pirko }
3481cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
3482cb5b09c1SJiri Pirko 
3483cb5b09c1SJiri Pirko static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write,
348432927393SChristoph Hellwig 					      void *buffer, size_t *lenp,
348532927393SChristoph Hellwig 					      loff_t *ppos)
3486cb5b09c1SJiri Pirko {
34871d4c8c29SJiri Pirko 	int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
34881d4c8c29SJiri Pirko 
34891d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
34901d4c8c29SJiri Pirko 	return ret;
3491cb5b09c1SJiri Pirko }
3492cb5b09c1SJiri Pirko 
3493cb5b09c1SJiri Pirko int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
349432927393SChristoph Hellwig 				   void *buffer, size_t *lenp, loff_t *ppos)
3495cb5b09c1SJiri Pirko {
34961d4c8c29SJiri Pirko 	int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
34971d4c8c29SJiri Pirko 
34981d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
34991d4c8c29SJiri Pirko 	return ret;
3500cb5b09c1SJiri Pirko }
3501cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
3502cb5b09c1SJiri Pirko 
3503cb5b09c1SJiri Pirko static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
350432927393SChristoph Hellwig 					  void *buffer, size_t *lenp,
350532927393SChristoph Hellwig 					  loff_t *ppos)
3506cb5b09c1SJiri Pirko {
35071d4c8c29SJiri Pirko 	int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
35081d4c8c29SJiri Pirko 
35091d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
35101d4c8c29SJiri Pirko 	return ret;
3511cb5b09c1SJiri Pirko }
3512cb5b09c1SJiri Pirko 
35134bf6980dSJean-Francois Remy static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write,
351432927393SChristoph Hellwig 					  void *buffer, size_t *lenp,
351532927393SChristoph Hellwig 					  loff_t *ppos)
35164bf6980dSJean-Francois Remy {
35174bf6980dSJean-Francois Remy 	struct neigh_parms *p = ctl->extra2;
35184bf6980dSJean-Francois Remy 	int ret;
35194bf6980dSJean-Francois Remy 
35204bf6980dSJean-Francois Remy 	if (strcmp(ctl->procname, "base_reachable_time") == 0)
35214bf6980dSJean-Francois Remy 		ret = neigh_proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
35224bf6980dSJean-Francois Remy 	else if (strcmp(ctl->procname, "base_reachable_time_ms") == 0)
35234bf6980dSJean-Francois Remy 		ret = neigh_proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
35244bf6980dSJean-Francois Remy 	else
35254bf6980dSJean-Francois Remy 		ret = -1;
35264bf6980dSJean-Francois Remy 
35274bf6980dSJean-Francois Remy 	if (write && ret == 0) {
35284bf6980dSJean-Francois Remy 		/* update reachable_time as well, otherwise, the change will
35294bf6980dSJean-Francois Remy 		 * only be effective after the next time neigh_periodic_work
35304bf6980dSJean-Francois Remy 		 * decides to recompute it
35314bf6980dSJean-Francois Remy 		 */
35324bf6980dSJean-Francois Remy 		p->reachable_time =
35334bf6980dSJean-Francois Remy 			neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
35344bf6980dSJean-Francois Remy 	}
35354bf6980dSJean-Francois Remy 	return ret;
35364bf6980dSJean-Francois Remy }
35374bf6980dSJean-Francois Remy 
35381f9248e5SJiri Pirko #define NEIGH_PARMS_DATA_OFFSET(index)	\
35391f9248e5SJiri Pirko 	(&((struct neigh_parms *) 0)->data[index])
35401f9248e5SJiri Pirko 
35411f9248e5SJiri Pirko #define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \
35421f9248e5SJiri Pirko 	[NEIGH_VAR_ ## attr] = { \
35431f9248e5SJiri Pirko 		.procname	= name, \
35441f9248e5SJiri Pirko 		.data		= NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \
35451f9248e5SJiri Pirko 		.maxlen		= sizeof(int), \
35461f9248e5SJiri Pirko 		.mode		= mval, \
35471f9248e5SJiri Pirko 		.proc_handler	= proc, \
35481f9248e5SJiri Pirko 	}
35491f9248e5SJiri Pirko 
35501f9248e5SJiri Pirko #define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \
35511f9248e5SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax)
35521f9248e5SJiri Pirko 
35531f9248e5SJiri Pirko #define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \
3554cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies)
35551f9248e5SJiri Pirko 
35561f9248e5SJiri Pirko #define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
3557cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)
35581f9248e5SJiri Pirko 
35591f9248e5SJiri Pirko #define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \
3560cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
35611f9248e5SJiri Pirko 
35621f9248e5SJiri Pirko #define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \
3563cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_unres_qlen)
356454716e3bSEric W. Biederman 
35651da177e4SLinus Torvalds static struct neigh_sysctl_table {
35661da177e4SLinus Torvalds 	struct ctl_table_header *sysctl_header;
35678b5c171bSEric Dumazet 	struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
3568ab32ea5dSBrian Haley } neigh_sysctl_template __read_mostly = {
35691da177e4SLinus Torvalds 	.neigh_vars = {
35701f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"),
35711f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"),
35721f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"),
35738da86466SYOSHIFUJI Hideaki/吉藤英明 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_REPROBES, "mcast_resolicit"),
35741f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),
35751f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),
35761f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"),
35771f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"),
35781f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"),
35791f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"),
35801f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"),
35811f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"),
35821f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"),
35831f9248e5SJiri Pirko 		NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"),
35841f9248e5SJiri Pirko 		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"),
35851f9248e5SJiri Pirko 		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"),
35868b5c171bSEric Dumazet 		[NEIGH_VAR_GC_INTERVAL] = {
35871da177e4SLinus Torvalds 			.procname	= "gc_interval",
35881da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
35891da177e4SLinus Torvalds 			.mode		= 0644,
35906d9f239aSAlexey Dobriyan 			.proc_handler	= proc_dointvec_jiffies,
35911da177e4SLinus Torvalds 		},
35928b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH1] = {
35931da177e4SLinus Torvalds 			.procname	= "gc_thresh1",
35941da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
35951da177e4SLinus Torvalds 			.mode		= 0644,
3596eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3597eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3598555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
35991da177e4SLinus Torvalds 		},
36008b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH2] = {
36011da177e4SLinus Torvalds 			.procname	= "gc_thresh2",
36021da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
36031da177e4SLinus Torvalds 			.mode		= 0644,
3604eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3605eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3606555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
36071da177e4SLinus Torvalds 		},
36088b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH3] = {
36091da177e4SLinus Torvalds 			.procname	= "gc_thresh3",
36101da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
36111da177e4SLinus Torvalds 			.mode		= 0644,
3612eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3613eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3614555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
36151da177e4SLinus Torvalds 		},
3616c3bac5a7SPavel Emelyanov 		{},
36171da177e4SLinus Torvalds 	},
36181da177e4SLinus Torvalds };
36191da177e4SLinus Torvalds 
36201da177e4SLinus Torvalds int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
362173af614aSJiri Pirko 			  proc_handler *handler)
36221da177e4SLinus Torvalds {
36231f9248e5SJiri Pirko 	int i;
36243c607bbbSPavel Emelyanov 	struct neigh_sysctl_table *t;
36251f9248e5SJiri Pirko 	const char *dev_name_source;
36268f40a1f9SEric W. Biederman 	char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
362773af614aSJiri Pirko 	char *p_name;
36281da177e4SLinus Torvalds 
36293c607bbbSPavel Emelyanov 	t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
36301da177e4SLinus Torvalds 	if (!t)
36313c607bbbSPavel Emelyanov 		goto err;
36323c607bbbSPavel Emelyanov 
3633b194c1f1SJiri Pirko 	for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
36341f9248e5SJiri Pirko 		t->neigh_vars[i].data += (long) p;
3635cb5b09c1SJiri Pirko 		t->neigh_vars[i].extra1 = dev;
36361d4c8c29SJiri Pirko 		t->neigh_vars[i].extra2 = p;
3637cb5b09c1SJiri Pirko 	}
36381da177e4SLinus Torvalds 
36391da177e4SLinus Torvalds 	if (dev) {
36401da177e4SLinus Torvalds 		dev_name_source = dev->name;
3641d12af679SEric W. Biederman 		/* Terminate the table early */
36428b5c171bSEric Dumazet 		memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
36438b5c171bSEric Dumazet 		       sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
36441da177e4SLinus Torvalds 	} else {
36459ecf07a1SMathias Krause 		struct neigh_table *tbl = p->tbl;
36468f40a1f9SEric W. Biederman 		dev_name_source = "default";
36479ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = &tbl->gc_interval;
36489ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = &tbl->gc_thresh1;
36499ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = &tbl->gc_thresh2;
36509ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = &tbl->gc_thresh3;
36511da177e4SLinus Torvalds 	}
36521da177e4SLinus Torvalds 
3653f8572d8fSEric W. Biederman 	if (handler) {
36541da177e4SLinus Torvalds 		/* RetransTime */
36558b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
36561da177e4SLinus Torvalds 		/* ReachableTime */
36578b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
36581da177e4SLinus Torvalds 		/* RetransTime (in milliseconds)*/
36598b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
36601da177e4SLinus Torvalds 		/* ReachableTime (in milliseconds) */
36618b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
36624bf6980dSJean-Francois Remy 	} else {
36634bf6980dSJean-Francois Remy 		/* Those handlers will update p->reachable_time after
36644bf6980dSJean-Francois Remy 		 * base_reachable_time(_ms) is set to ensure the new timer starts being
36654bf6980dSJean-Francois Remy 		 * applied after the next neighbour update instead of waiting for
36664bf6980dSJean-Francois Remy 		 * neigh_periodic_work to update its value (can be multiple minutes)
36674bf6980dSJean-Francois Remy 		 * So any handler that replaces them should do this as well
36684bf6980dSJean-Francois Remy 		 */
36694bf6980dSJean-Francois Remy 		/* ReachableTime */
36704bf6980dSJean-Francois Remy 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler =
36714bf6980dSJean-Francois Remy 			neigh_proc_base_reachable_time;
36724bf6980dSJean-Francois Remy 		/* ReachableTime (in milliseconds) */
36734bf6980dSJean-Francois Remy 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler =
36744bf6980dSJean-Francois Remy 			neigh_proc_base_reachable_time;
36751da177e4SLinus Torvalds 	}
36761da177e4SLinus Torvalds 
3677464dc801SEric W. Biederman 	/* Don't export sysctls to unprivileged users */
3678464dc801SEric W. Biederman 	if (neigh_parms_net(p)->user_ns != &init_user_ns)
3679464dc801SEric W. Biederman 		t->neigh_vars[0].procname = NULL;
3680464dc801SEric W. Biederman 
368173af614aSJiri Pirko 	switch (neigh_parms_family(p)) {
368273af614aSJiri Pirko 	case AF_INET:
368373af614aSJiri Pirko 	      p_name = "ipv4";
368473af614aSJiri Pirko 	      break;
368573af614aSJiri Pirko 	case AF_INET6:
368673af614aSJiri Pirko 	      p_name = "ipv6";
368773af614aSJiri Pirko 	      break;
368873af614aSJiri Pirko 	default:
368973af614aSJiri Pirko 	      BUG();
369073af614aSJiri Pirko 	}
369173af614aSJiri Pirko 
36928f40a1f9SEric W. Biederman 	snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
36938f40a1f9SEric W. Biederman 		p_name, dev_name_source);
36944ab438fcSDenis V. Lunev 	t->sysctl_header =
36958f40a1f9SEric W. Biederman 		register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
36963c607bbbSPavel Emelyanov 	if (!t->sysctl_header)
36978f40a1f9SEric W. Biederman 		goto free;
36983c607bbbSPavel Emelyanov 
36991da177e4SLinus Torvalds 	p->sysctl_table = t;
37001da177e4SLinus Torvalds 	return 0;
37011da177e4SLinus Torvalds 
37021da177e4SLinus Torvalds free:
37031da177e4SLinus Torvalds 	kfree(t);
37043c607bbbSPavel Emelyanov err:
37053c607bbbSPavel Emelyanov 	return -ENOBUFS;
37061da177e4SLinus Torvalds }
37070a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_sysctl_register);
37081da177e4SLinus Torvalds 
37091da177e4SLinus Torvalds void neigh_sysctl_unregister(struct neigh_parms *p)
37101da177e4SLinus Torvalds {
37111da177e4SLinus Torvalds 	if (p->sysctl_table) {
37121da177e4SLinus Torvalds 		struct neigh_sysctl_table *t = p->sysctl_table;
37131da177e4SLinus Torvalds 		p->sysctl_table = NULL;
37145dd3df10SEric W. Biederman 		unregister_net_sysctl_table(t->sysctl_header);
37151da177e4SLinus Torvalds 		kfree(t);
37161da177e4SLinus Torvalds 	}
37171da177e4SLinus Torvalds }
37180a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_sysctl_unregister);
37191da177e4SLinus Torvalds 
37201da177e4SLinus Torvalds #endif	/* CONFIG_SYSCTL */
37211da177e4SLinus Torvalds 
3722c8822a4eSThomas Graf static int __init neigh_init(void)
3723c8822a4eSThomas Graf {
3724b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0);
3725b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0);
372682cbb5c6SRoopa Prabhu 	rtnl_register(PF_UNSPEC, RTM_GETNEIGH, neigh_get, neigh_dump_info, 0);
3727c8822a4eSThomas Graf 
3728c7ac8679SGreg Rose 	rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
3729b97bac64SFlorian Westphal 		      0);
3730b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, 0);
3731c8822a4eSThomas Graf 
3732c8822a4eSThomas Graf 	return 0;
3733c8822a4eSThomas Graf }
3734c8822a4eSThomas Graf 
3735c8822a4eSThomas Graf subsys_initcall(neigh_init);
3736