xref: /openbmc/linux/net/core/neighbour.c (revision c305c6ae)
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 {
1014f494554SThomas Graf 	if (neigh->parms->neigh_cleanup)
1024f494554SThomas Graf 		neigh->parms->neigh_cleanup(neigh);
1034f494554SThomas Graf 
10456dd18a4SRoopa Prabhu 	trace_neigh_cleanup_and_release(neigh, 0);
1057b8f7a40SRoopa Prabhu 	__neigh_notify(neigh, RTM_DELNEIGH, 0, 0);
10653f800e3SIdo Schimmel 	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
1074f494554SThomas Graf 	neigh_release(neigh);
1084f494554SThomas Graf }
1094f494554SThomas Graf 
1101da177e4SLinus Torvalds /*
1111da177e4SLinus Torvalds  * It is random distribution in the interval (1/2)*base...(3/2)*base.
1121da177e4SLinus Torvalds  * It corresponds to default IPv6 settings and is not overridable,
1131da177e4SLinus Torvalds  * because it is really reasonable choice.
1141da177e4SLinus Torvalds  */
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds unsigned long neigh_rand_reach_time(unsigned long base)
1171da177e4SLinus Torvalds {
11863862b5bSAruna-Hewapathirane 	return base ? (prandom_u32() % base) + (base >> 1) : 0;
1191da177e4SLinus Torvalds }
1200a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_rand_reach_time);
1211da177e4SLinus Torvalds 
12258956317SDavid Ahern static void neigh_mark_dead(struct neighbour *n)
12358956317SDavid Ahern {
12458956317SDavid Ahern 	n->dead = 1;
12558956317SDavid Ahern 	if (!list_empty(&n->gc_list)) {
12658956317SDavid Ahern 		list_del_init(&n->gc_list);
12758956317SDavid Ahern 		atomic_dec(&n->tbl->gc_entries);
12858956317SDavid Ahern 	}
12958956317SDavid Ahern }
13058956317SDavid Ahern 
1319c29a2f5SDavid Ahern static void neigh_update_gc_list(struct neighbour *n)
13258956317SDavid Ahern {
133e997f8a2SDavid Ahern 	bool on_gc_list, exempt_from_gc;
13458956317SDavid Ahern 
1359c29a2f5SDavid Ahern 	write_lock_bh(&n->tbl->lock);
1369c29a2f5SDavid Ahern 	write_lock(&n->lock);
13758956317SDavid Ahern 
138e997f8a2SDavid Ahern 	/* remove from the gc list if new state is permanent or if neighbor
139e997f8a2SDavid Ahern 	 * is externally learned; otherwise entry should be on the gc list
14058956317SDavid Ahern 	 */
141e997f8a2SDavid Ahern 	exempt_from_gc = n->nud_state & NUD_PERMANENT ||
142e997f8a2SDavid Ahern 			 n->flags & NTF_EXT_LEARNED;
1439c29a2f5SDavid Ahern 	on_gc_list = !list_empty(&n->gc_list);
1448cc196d6SDavid Ahern 
145e997f8a2SDavid Ahern 	if (exempt_from_gc && on_gc_list) {
1469c29a2f5SDavid Ahern 		list_del_init(&n->gc_list);
14758956317SDavid Ahern 		atomic_dec(&n->tbl->gc_entries);
148e997f8a2SDavid Ahern 	} else if (!exempt_from_gc && !on_gc_list) {
14958956317SDavid Ahern 		/* add entries to the tail; cleaning removes from the front */
15058956317SDavid Ahern 		list_add_tail(&n->gc_list, &n->tbl->gc_list);
15158956317SDavid Ahern 		atomic_inc(&n->tbl->gc_entries);
15258956317SDavid Ahern 	}
1539c29a2f5SDavid Ahern 
1549c29a2f5SDavid Ahern 	write_unlock(&n->lock);
1559c29a2f5SDavid Ahern 	write_unlock_bh(&n->tbl->lock);
15658956317SDavid Ahern }
1571da177e4SLinus Torvalds 
158e997f8a2SDavid Ahern static bool neigh_update_ext_learned(struct neighbour *neigh, u32 flags,
159526f1b58SDavid Ahern 				     int *notify)
160526f1b58SDavid Ahern {
161e997f8a2SDavid Ahern 	bool rc = false;
162526f1b58SDavid Ahern 	u8 ndm_flags;
163526f1b58SDavid Ahern 
164526f1b58SDavid Ahern 	if (!(flags & NEIGH_UPDATE_F_ADMIN))
165e997f8a2SDavid Ahern 		return rc;
166526f1b58SDavid Ahern 
167526f1b58SDavid Ahern 	ndm_flags = (flags & NEIGH_UPDATE_F_EXT_LEARNED) ? NTF_EXT_LEARNED : 0;
168526f1b58SDavid Ahern 	if ((neigh->flags ^ ndm_flags) & NTF_EXT_LEARNED) {
169526f1b58SDavid Ahern 		if (ndm_flags & NTF_EXT_LEARNED)
170526f1b58SDavid Ahern 			neigh->flags |= NTF_EXT_LEARNED;
171526f1b58SDavid Ahern 		else
172526f1b58SDavid Ahern 			neigh->flags &= ~NTF_EXT_LEARNED;
173e997f8a2SDavid Ahern 		rc = true;
174526f1b58SDavid Ahern 		*notify = 1;
175526f1b58SDavid Ahern 	}
176e997f8a2SDavid Ahern 
177e997f8a2SDavid Ahern 	return rc;
178526f1b58SDavid Ahern }
179526f1b58SDavid Ahern 
1807e6f182bSDavid Ahern static bool neigh_del(struct neighbour *n, struct neighbour __rcu **np,
1817e6f182bSDavid Ahern 		      struct neigh_table *tbl)
1825071034eSSowmini Varadhan {
1835071034eSSowmini Varadhan 	bool retval = false;
1845071034eSSowmini Varadhan 
1855071034eSSowmini Varadhan 	write_lock(&n->lock);
1867e6f182bSDavid Ahern 	if (refcount_read(&n->refcnt) == 1) {
1875071034eSSowmini Varadhan 		struct neighbour *neigh;
1885071034eSSowmini Varadhan 
1895071034eSSowmini Varadhan 		neigh = rcu_dereference_protected(n->next,
1905071034eSSowmini Varadhan 						  lockdep_is_held(&tbl->lock));
1915071034eSSowmini Varadhan 		rcu_assign_pointer(*np, neigh);
19258956317SDavid Ahern 		neigh_mark_dead(n);
1935071034eSSowmini Varadhan 		retval = true;
1945071034eSSowmini Varadhan 	}
1955071034eSSowmini Varadhan 	write_unlock(&n->lock);
1965071034eSSowmini Varadhan 	if (retval)
1975071034eSSowmini Varadhan 		neigh_cleanup_and_release(n);
1985071034eSSowmini Varadhan 	return retval;
1995071034eSSowmini Varadhan }
2005071034eSSowmini Varadhan 
2015071034eSSowmini Varadhan bool neigh_remove_one(struct neighbour *ndel, struct neigh_table *tbl)
2025071034eSSowmini Varadhan {
2035071034eSSowmini Varadhan 	struct neigh_hash_table *nht;
2045071034eSSowmini Varadhan 	void *pkey = ndel->primary_key;
2055071034eSSowmini Varadhan 	u32 hash_val;
2065071034eSSowmini Varadhan 	struct neighbour *n;
2075071034eSSowmini Varadhan 	struct neighbour __rcu **np;
2085071034eSSowmini Varadhan 
2095071034eSSowmini Varadhan 	nht = rcu_dereference_protected(tbl->nht,
2105071034eSSowmini Varadhan 					lockdep_is_held(&tbl->lock));
2115071034eSSowmini Varadhan 	hash_val = tbl->hash(pkey, ndel->dev, nht->hash_rnd);
2125071034eSSowmini Varadhan 	hash_val = hash_val >> (32 - nht->hash_shift);
2135071034eSSowmini Varadhan 
2145071034eSSowmini Varadhan 	np = &nht->hash_buckets[hash_val];
2155071034eSSowmini Varadhan 	while ((n = rcu_dereference_protected(*np,
2165071034eSSowmini Varadhan 					      lockdep_is_held(&tbl->lock)))) {
2175071034eSSowmini Varadhan 		if (n == ndel)
2187e6f182bSDavid Ahern 			return neigh_del(n, np, tbl);
2195071034eSSowmini Varadhan 		np = &n->next;
2205071034eSSowmini Varadhan 	}
2215071034eSSowmini Varadhan 	return false;
2225071034eSSowmini Varadhan }
2235071034eSSowmini Varadhan 
2241da177e4SLinus Torvalds static int neigh_forced_gc(struct neigh_table *tbl)
2251da177e4SLinus Torvalds {
22658956317SDavid Ahern 	int max_clean = atomic_read(&tbl->gc_entries) - tbl->gc_thresh2;
22758956317SDavid Ahern 	unsigned long tref = jiffies - 5 * HZ;
22858956317SDavid Ahern 	struct neighbour *n, *tmp;
2291da177e4SLinus Torvalds 	int shrunk = 0;
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
2341da177e4SLinus Torvalds 
23558956317SDavid Ahern 	list_for_each_entry_safe(n, tmp, &tbl->gc_list, gc_list) {
23658956317SDavid Ahern 		if (refcount_read(&n->refcnt) == 1) {
23758956317SDavid Ahern 			bool remove = false;
23858956317SDavid Ahern 
23958956317SDavid Ahern 			write_lock(&n->lock);
240758a7f0bSDavid Ahern 			if ((n->nud_state == NUD_FAILED) ||
241e997f8a2SDavid Ahern 			    time_after(tref, n->updated))
24258956317SDavid Ahern 				remove = true;
24358956317SDavid Ahern 			write_unlock(&n->lock);
24458956317SDavid Ahern 
24558956317SDavid Ahern 			if (remove && neigh_remove_one(n, tbl))
24658956317SDavid Ahern 				shrunk++;
24758956317SDavid Ahern 			if (shrunk >= max_clean)
24858956317SDavid Ahern 				break;
2491da177e4SLinus Torvalds 		}
2501da177e4SLinus Torvalds 	}
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds 	tbl->last_flush = jiffies;
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds 	return shrunk;
2571da177e4SLinus Torvalds }
2581da177e4SLinus Torvalds 
259a43d8994SPavel Emelyanov static void neigh_add_timer(struct neighbour *n, unsigned long when)
260a43d8994SPavel Emelyanov {
261a43d8994SPavel Emelyanov 	neigh_hold(n);
262a43d8994SPavel Emelyanov 	if (unlikely(mod_timer(&n->timer, when))) {
263a43d8994SPavel Emelyanov 		printk("NEIGH: BUG, double timer add, state is %x\n",
264a43d8994SPavel Emelyanov 		       n->nud_state);
265a43d8994SPavel Emelyanov 		dump_stack();
266a43d8994SPavel Emelyanov 	}
267a43d8994SPavel Emelyanov }
268a43d8994SPavel Emelyanov 
2691da177e4SLinus Torvalds static int neigh_del_timer(struct neighbour *n)
2701da177e4SLinus Torvalds {
2711da177e4SLinus Torvalds 	if ((n->nud_state & NUD_IN_TIMER) &&
2721da177e4SLinus Torvalds 	    del_timer(&n->timer)) {
2731da177e4SLinus Torvalds 		neigh_release(n);
2741da177e4SLinus Torvalds 		return 1;
2751da177e4SLinus Torvalds 	}
2761da177e4SLinus Torvalds 	return 0;
2771da177e4SLinus Torvalds }
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds static void pneigh_queue_purge(struct sk_buff_head *list)
2801da177e4SLinus Torvalds {
2811da177e4SLinus Torvalds 	struct sk_buff *skb;
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds 	while ((skb = skb_dequeue(list)) != NULL) {
2841da177e4SLinus Torvalds 		dev_put(skb->dev);
2851da177e4SLinus Torvalds 		kfree_skb(skb);
2861da177e4SLinus Torvalds 	}
2871da177e4SLinus Torvalds }
2881da177e4SLinus Torvalds 
289859bd2efSDavid Ahern static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev,
290859bd2efSDavid Ahern 			    bool skip_perm)
2911da177e4SLinus Torvalds {
2921da177e4SLinus Torvalds 	int i;
293d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
2941da177e4SLinus Torvalds 
295d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
296d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
297d6bf7817SEric Dumazet 
298cd089336SDavid S. Miller 	for (i = 0; i < (1 << nht->hash_shift); i++) {
299767e97e1SEric Dumazet 		struct neighbour *n;
300767e97e1SEric Dumazet 		struct neighbour __rcu **np = &nht->hash_buckets[i];
3011da177e4SLinus Torvalds 
302767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
303767e97e1SEric Dumazet 					lockdep_is_held(&tbl->lock))) != NULL) {
3041da177e4SLinus Torvalds 			if (dev && n->dev != dev) {
3051da177e4SLinus Torvalds 				np = &n->next;
3061da177e4SLinus Torvalds 				continue;
3071da177e4SLinus Torvalds 			}
308859bd2efSDavid Ahern 			if (skip_perm && n->nud_state & NUD_PERMANENT) {
309859bd2efSDavid Ahern 				np = &n->next;
310859bd2efSDavid Ahern 				continue;
311859bd2efSDavid Ahern 			}
312767e97e1SEric Dumazet 			rcu_assign_pointer(*np,
313767e97e1SEric Dumazet 				   rcu_dereference_protected(n->next,
314767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
3151da177e4SLinus Torvalds 			write_lock(&n->lock);
3161da177e4SLinus Torvalds 			neigh_del_timer(n);
31758956317SDavid Ahern 			neigh_mark_dead(n);
3189f237430SReshetova, Elena 			if (refcount_read(&n->refcnt) != 1) {
3191da177e4SLinus Torvalds 				/* The most unpleasant situation.
3201da177e4SLinus Torvalds 				   We must destroy neighbour entry,
3211da177e4SLinus Torvalds 				   but someone still uses it.
3221da177e4SLinus Torvalds 
3231da177e4SLinus Torvalds 				   The destroy will be delayed until
3241da177e4SLinus Torvalds 				   the last user releases us, but
3251da177e4SLinus Torvalds 				   we must kill timers etc. and move
3261da177e4SLinus Torvalds 				   it to safe state.
3271da177e4SLinus Torvalds 				 */
328c9ab4d85SEric Dumazet 				__skb_queue_purge(&n->arp_queue);
3298b5c171bSEric Dumazet 				n->arp_queue_len_bytes = 0;
3301da177e4SLinus Torvalds 				n->output = neigh_blackhole;
3311da177e4SLinus Torvalds 				if (n->nud_state & NUD_VALID)
3321da177e4SLinus Torvalds 					n->nud_state = NUD_NOARP;
3331da177e4SLinus Torvalds 				else
3341da177e4SLinus Torvalds 					n->nud_state = NUD_NONE;
335d5d427cdSJoe Perches 				neigh_dbg(2, "neigh %p is stray\n", n);
3361da177e4SLinus Torvalds 			}
3371da177e4SLinus Torvalds 			write_unlock(&n->lock);
3384f494554SThomas Graf 			neigh_cleanup_and_release(n);
3391da177e4SLinus Torvalds 		}
3401da177e4SLinus Torvalds 	}
34149636bb1SHerbert Xu }
3421da177e4SLinus Torvalds 
34349636bb1SHerbert Xu void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
34449636bb1SHerbert Xu {
34549636bb1SHerbert Xu 	write_lock_bh(&tbl->lock);
346859bd2efSDavid Ahern 	neigh_flush_dev(tbl, dev, false);
34749636bb1SHerbert Xu 	write_unlock_bh(&tbl->lock);
34849636bb1SHerbert Xu }
3490a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_changeaddr);
35049636bb1SHerbert Xu 
351859bd2efSDavid Ahern static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
352859bd2efSDavid Ahern 			  bool skip_perm)
35349636bb1SHerbert Xu {
35449636bb1SHerbert Xu 	write_lock_bh(&tbl->lock);
355859bd2efSDavid Ahern 	neigh_flush_dev(tbl, dev, skip_perm);
35653b76cdfSWolfgang Bumiller 	pneigh_ifdown_and_unlock(tbl, dev);
3571da177e4SLinus Torvalds 
3581da177e4SLinus Torvalds 	del_timer_sync(&tbl->proxy_timer);
3591da177e4SLinus Torvalds 	pneigh_queue_purge(&tbl->proxy_queue);
3601da177e4SLinus Torvalds 	return 0;
3611da177e4SLinus Torvalds }
362859bd2efSDavid Ahern 
363859bd2efSDavid Ahern int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev)
364859bd2efSDavid Ahern {
365859bd2efSDavid Ahern 	__neigh_ifdown(tbl, dev, true);
366859bd2efSDavid Ahern 	return 0;
367859bd2efSDavid Ahern }
368859bd2efSDavid Ahern EXPORT_SYMBOL(neigh_carrier_down);
369859bd2efSDavid Ahern 
370859bd2efSDavid Ahern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
371859bd2efSDavid Ahern {
372859bd2efSDavid Ahern 	__neigh_ifdown(tbl, dev, false);
373859bd2efSDavid Ahern 	return 0;
374859bd2efSDavid Ahern }
3750a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_ifdown);
3761da177e4SLinus Torvalds 
37758956317SDavid Ahern static struct neighbour *neigh_alloc(struct neigh_table *tbl,
37858956317SDavid Ahern 				     struct net_device *dev,
379e997f8a2SDavid Ahern 				     bool exempt_from_gc)
3801da177e4SLinus Torvalds {
3811da177e4SLinus Torvalds 	struct neighbour *n = NULL;
3821da177e4SLinus Torvalds 	unsigned long now = jiffies;
3831da177e4SLinus Torvalds 	int entries;
3841da177e4SLinus Torvalds 
385e997f8a2SDavid Ahern 	if (exempt_from_gc)
38658956317SDavid Ahern 		goto do_alloc;
38758956317SDavid Ahern 
38858956317SDavid Ahern 	entries = atomic_inc_return(&tbl->gc_entries) - 1;
3891da177e4SLinus Torvalds 	if (entries >= tbl->gc_thresh3 ||
3901da177e4SLinus Torvalds 	    (entries >= tbl->gc_thresh2 &&
3911da177e4SLinus Torvalds 	     time_after(now, tbl->last_flush + 5 * HZ))) {
3921da177e4SLinus Torvalds 		if (!neigh_forced_gc(tbl) &&
393fb811395SRick Jones 		    entries >= tbl->gc_thresh3) {
394fb811395SRick Jones 			net_info_ratelimited("%s: neighbor table overflow!\n",
395fb811395SRick Jones 					     tbl->id);
396fb811395SRick Jones 			NEIGH_CACHE_STAT_INC(tbl, table_fulls);
3971da177e4SLinus Torvalds 			goto out_entries;
3981da177e4SLinus Torvalds 		}
399fb811395SRick Jones 	}
4001da177e4SLinus Torvalds 
40158956317SDavid Ahern do_alloc:
40208433effSYOSHIFUJI Hideaki / 吉藤英明 	n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
4031da177e4SLinus Torvalds 	if (!n)
4041da177e4SLinus Torvalds 		goto out_entries;
4051da177e4SLinus Torvalds 
406c9ab4d85SEric Dumazet 	__skb_queue_head_init(&n->arp_queue);
4071da177e4SLinus Torvalds 	rwlock_init(&n->lock);
4080ed8ddf4SEric Dumazet 	seqlock_init(&n->ha_lock);
4091da177e4SLinus Torvalds 	n->updated	  = n->used = now;
4101da177e4SLinus Torvalds 	n->nud_state	  = NUD_NONE;
4111da177e4SLinus Torvalds 	n->output	  = neigh_blackhole;
412f6b72b62SDavid S. Miller 	seqlock_init(&n->hh.hh_lock);
4131da177e4SLinus Torvalds 	n->parms	  = neigh_parms_clone(&tbl->parms);
414e99e88a9SKees Cook 	timer_setup(&n->timer, neigh_timer_handler, 0);
4151da177e4SLinus Torvalds 
4161da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, allocs);
4171da177e4SLinus Torvalds 	n->tbl		  = tbl;
4189f237430SReshetova, Elena 	refcount_set(&n->refcnt, 1);
4191da177e4SLinus Torvalds 	n->dead		  = 1;
42058956317SDavid Ahern 	INIT_LIST_HEAD(&n->gc_list);
42158956317SDavid Ahern 
42258956317SDavid Ahern 	atomic_inc(&tbl->entries);
4231da177e4SLinus Torvalds out:
4241da177e4SLinus Torvalds 	return n;
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds out_entries:
427e997f8a2SDavid Ahern 	if (!exempt_from_gc)
42858956317SDavid Ahern 		atomic_dec(&tbl->gc_entries);
4291da177e4SLinus Torvalds 	goto out;
4301da177e4SLinus Torvalds }
4311da177e4SLinus Torvalds 
4322c2aba6cSDavid S. Miller static void neigh_get_hash_rnd(u32 *x)
4332c2aba6cSDavid S. Miller {
434b3d0f789SJason A. Donenfeld 	*x = get_random_u32() | 1;
4352c2aba6cSDavid S. Miller }
4362c2aba6cSDavid S. Miller 
437cd089336SDavid S. Miller static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
4381da177e4SLinus Torvalds {
439cd089336SDavid S. Miller 	size_t size = (1 << shift) * sizeof(struct neighbour *);
440d6bf7817SEric Dumazet 	struct neigh_hash_table *ret;
4416193d2beSEric Dumazet 	struct neighbour __rcu **buckets;
4422c2aba6cSDavid S. Miller 	int i;
4431da177e4SLinus Torvalds 
444d6bf7817SEric Dumazet 	ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
445d6bf7817SEric Dumazet 	if (!ret)
446d6bf7817SEric Dumazet 		return NULL;
44785704cb8SKonstantin Khlebnikov 	if (size <= PAGE_SIZE) {
448d6bf7817SEric Dumazet 		buckets = kzalloc(size, GFP_ATOMIC);
44985704cb8SKonstantin Khlebnikov 	} else {
4506193d2beSEric Dumazet 		buckets = (struct neighbour __rcu **)
451d6bf7817SEric Dumazet 			  __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
452d6bf7817SEric Dumazet 					   get_order(size));
45301b833abSKonstantin Khlebnikov 		kmemleak_alloc(buckets, size, 1, GFP_ATOMIC);
45485704cb8SKonstantin Khlebnikov 	}
455d6bf7817SEric Dumazet 	if (!buckets) {
456d6bf7817SEric Dumazet 		kfree(ret);
457d6bf7817SEric Dumazet 		return NULL;
4581da177e4SLinus Torvalds 	}
4596193d2beSEric Dumazet 	ret->hash_buckets = buckets;
460cd089336SDavid S. Miller 	ret->hash_shift = shift;
4612c2aba6cSDavid S. Miller 	for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
4622c2aba6cSDavid S. Miller 		neigh_get_hash_rnd(&ret->hash_rnd[i]);
4631da177e4SLinus Torvalds 	return ret;
4641da177e4SLinus Torvalds }
4651da177e4SLinus Torvalds 
466d6bf7817SEric Dumazet static void neigh_hash_free_rcu(struct rcu_head *head)
4671da177e4SLinus Torvalds {
468d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = container_of(head,
469d6bf7817SEric Dumazet 						    struct neigh_hash_table,
470d6bf7817SEric Dumazet 						    rcu);
471cd089336SDavid S. Miller 	size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
4726193d2beSEric Dumazet 	struct neighbour __rcu **buckets = nht->hash_buckets;
4731da177e4SLinus Torvalds 
47485704cb8SKonstantin Khlebnikov 	if (size <= PAGE_SIZE) {
475d6bf7817SEric Dumazet 		kfree(buckets);
47685704cb8SKonstantin Khlebnikov 	} else {
47785704cb8SKonstantin Khlebnikov 		kmemleak_free(buckets);
478d6bf7817SEric Dumazet 		free_pages((unsigned long)buckets, get_order(size));
47985704cb8SKonstantin Khlebnikov 	}
480d6bf7817SEric Dumazet 	kfree(nht);
4811da177e4SLinus Torvalds }
4821da177e4SLinus Torvalds 
483d6bf7817SEric Dumazet static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
484cd089336SDavid S. Miller 						unsigned long new_shift)
4851da177e4SLinus Torvalds {
486d6bf7817SEric Dumazet 	unsigned int i, hash;
487d6bf7817SEric Dumazet 	struct neigh_hash_table *new_nht, *old_nht;
4881da177e4SLinus Torvalds 
4891da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, hash_grows);
4901da177e4SLinus Torvalds 
491d6bf7817SEric Dumazet 	old_nht = rcu_dereference_protected(tbl->nht,
492d6bf7817SEric Dumazet 					    lockdep_is_held(&tbl->lock));
493cd089336SDavid S. Miller 	new_nht = neigh_hash_alloc(new_shift);
494d6bf7817SEric Dumazet 	if (!new_nht)
495d6bf7817SEric Dumazet 		return old_nht;
4961da177e4SLinus Torvalds 
497cd089336SDavid S. Miller 	for (i = 0; i < (1 << old_nht->hash_shift); i++) {
4981da177e4SLinus Torvalds 		struct neighbour *n, *next;
4991da177e4SLinus Torvalds 
500767e97e1SEric Dumazet 		for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
501767e97e1SEric Dumazet 						   lockdep_is_held(&tbl->lock));
502d6bf7817SEric Dumazet 		     n != NULL;
503d6bf7817SEric Dumazet 		     n = next) {
504d6bf7817SEric Dumazet 			hash = tbl->hash(n->primary_key, n->dev,
505d6bf7817SEric Dumazet 					 new_nht->hash_rnd);
5061da177e4SLinus Torvalds 
507cd089336SDavid S. Miller 			hash >>= (32 - new_nht->hash_shift);
508767e97e1SEric Dumazet 			next = rcu_dereference_protected(n->next,
509767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock));
5101da177e4SLinus Torvalds 
511767e97e1SEric Dumazet 			rcu_assign_pointer(n->next,
512767e97e1SEric Dumazet 					   rcu_dereference_protected(
513767e97e1SEric Dumazet 						new_nht->hash_buckets[hash],
514767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
515767e97e1SEric Dumazet 			rcu_assign_pointer(new_nht->hash_buckets[hash], n);
5161da177e4SLinus Torvalds 		}
5171da177e4SLinus Torvalds 	}
5181da177e4SLinus Torvalds 
519d6bf7817SEric Dumazet 	rcu_assign_pointer(tbl->nht, new_nht);
520d6bf7817SEric Dumazet 	call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
521d6bf7817SEric Dumazet 	return new_nht;
5221da177e4SLinus Torvalds }
5231da177e4SLinus Torvalds 
5241da177e4SLinus Torvalds struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
5251da177e4SLinus Torvalds 			       struct net_device *dev)
5261da177e4SLinus Torvalds {
5271da177e4SLinus Torvalds 	struct neighbour *n;
5281da177e4SLinus Torvalds 
5291da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, lookups);
5301da177e4SLinus Torvalds 
531d6bf7817SEric Dumazet 	rcu_read_lock_bh();
53260395a20SEric W. Biederman 	n = __neigh_lookup_noref(tbl, pkey, dev);
53360395a20SEric W. Biederman 	if (n) {
5349f237430SReshetova, Elena 		if (!refcount_inc_not_zero(&n->refcnt))
535767e97e1SEric Dumazet 			n = NULL;
5361da177e4SLinus Torvalds 		NEIGH_CACHE_STAT_INC(tbl, hits);
5371da177e4SLinus Torvalds 	}
538767e97e1SEric Dumazet 
539d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
5401da177e4SLinus Torvalds 	return n;
5411da177e4SLinus Torvalds }
5420a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_lookup);
5431da177e4SLinus Torvalds 
544426b5303SEric W. Biederman struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
545426b5303SEric W. Biederman 				     const void *pkey)
5461da177e4SLinus Torvalds {
5471da177e4SLinus Torvalds 	struct neighbour *n;
54801ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
549bc4bf5f3SPavel Emelyanov 	u32 hash_val;
550d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
5511da177e4SLinus Torvalds 
5521da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, lookups);
5531da177e4SLinus Torvalds 
554d6bf7817SEric Dumazet 	rcu_read_lock_bh();
555d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
556cd089336SDavid S. Miller 	hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
557767e97e1SEric Dumazet 
558767e97e1SEric Dumazet 	for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
559767e97e1SEric Dumazet 	     n != NULL;
560767e97e1SEric Dumazet 	     n = rcu_dereference_bh(n->next)) {
561426b5303SEric W. Biederman 		if (!memcmp(n->primary_key, pkey, key_len) &&
562878628fbSYOSHIFUJI Hideaki 		    net_eq(dev_net(n->dev), net)) {
5639f237430SReshetova, Elena 			if (!refcount_inc_not_zero(&n->refcnt))
564767e97e1SEric Dumazet 				n = NULL;
5651da177e4SLinus Torvalds 			NEIGH_CACHE_STAT_INC(tbl, hits);
5661da177e4SLinus Torvalds 			break;
5671da177e4SLinus Torvalds 		}
5681da177e4SLinus Torvalds 	}
569767e97e1SEric Dumazet 
570d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
5711da177e4SLinus Torvalds 	return n;
5721da177e4SLinus Torvalds }
5730a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_lookup_nodev);
5741da177e4SLinus Torvalds 
57558956317SDavid Ahern static struct neighbour *___neigh_create(struct neigh_table *tbl,
57658956317SDavid Ahern 					 const void *pkey,
57758956317SDavid Ahern 					 struct net_device *dev,
578e997f8a2SDavid Ahern 					 bool exempt_from_gc, bool want_ref)
5791da177e4SLinus Torvalds {
580e997f8a2SDavid Ahern 	struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev, exempt_from_gc);
5811da177e4SLinus Torvalds 	u32 hash_val;
58201ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
5831da177e4SLinus Torvalds 	int error;
584d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
5851da177e4SLinus Torvalds 
586fc651001SDavid Ahern 	trace_neigh_create(tbl, dev, pkey, n, exempt_from_gc);
587fc651001SDavid Ahern 
5881da177e4SLinus Torvalds 	if (!n) {
5891da177e4SLinus Torvalds 		rc = ERR_PTR(-ENOBUFS);
5901da177e4SLinus Torvalds 		goto out;
5911da177e4SLinus Torvalds 	}
5921da177e4SLinus Torvalds 
5931da177e4SLinus Torvalds 	memcpy(n->primary_key, pkey, key_len);
5941da177e4SLinus Torvalds 	n->dev = dev;
5951da177e4SLinus Torvalds 	dev_hold(dev);
5961da177e4SLinus Torvalds 
5971da177e4SLinus Torvalds 	/* Protocol specific setup. */
5981da177e4SLinus Torvalds 	if (tbl->constructor &&	(error = tbl->constructor(n)) < 0) {
5991da177e4SLinus Torvalds 		rc = ERR_PTR(error);
6001da177e4SLinus Torvalds 		goto out_neigh_release;
6011da177e4SLinus Torvalds 	}
6021da177e4SLinus Torvalds 
603da6a8fa0SDavid Miller 	if (dev->netdev_ops->ndo_neigh_construct) {
604503eebc2SJiri Pirko 		error = dev->netdev_ops->ndo_neigh_construct(dev, n);
605da6a8fa0SDavid Miller 		if (error < 0) {
606da6a8fa0SDavid Miller 			rc = ERR_PTR(error);
607da6a8fa0SDavid Miller 			goto out_neigh_release;
608da6a8fa0SDavid Miller 		}
609da6a8fa0SDavid Miller 	}
610da6a8fa0SDavid Miller 
611447f2191SDavid S. Miller 	/* Device specific setup. */
612447f2191SDavid S. Miller 	if (n->parms->neigh_setup &&
613447f2191SDavid S. Miller 	    (error = n->parms->neigh_setup(n)) < 0) {
614447f2191SDavid S. Miller 		rc = ERR_PTR(error);
615447f2191SDavid S. Miller 		goto out_neigh_release;
616447f2191SDavid S. Miller 	}
617447f2191SDavid S. Miller 
6181f9248e5SJiri Pirko 	n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1);
6191da177e4SLinus Torvalds 
6201da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
621d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
622d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
6231da177e4SLinus Torvalds 
624cd089336SDavid S. Miller 	if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
625cd089336SDavid S. Miller 		nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
6261da177e4SLinus Torvalds 
627096b9854SJim Westfall 	hash_val = tbl->hash(n->primary_key, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds 	if (n->parms->dead) {
6301da177e4SLinus Torvalds 		rc = ERR_PTR(-EINVAL);
6311da177e4SLinus Torvalds 		goto out_tbl_unlock;
6321da177e4SLinus Torvalds 	}
6331da177e4SLinus Torvalds 
634767e97e1SEric Dumazet 	for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
635767e97e1SEric Dumazet 					    lockdep_is_held(&tbl->lock));
636767e97e1SEric Dumazet 	     n1 != NULL;
637767e97e1SEric Dumazet 	     n1 = rcu_dereference_protected(n1->next,
638767e97e1SEric Dumazet 			lockdep_is_held(&tbl->lock))) {
639096b9854SJim Westfall 		if (dev == n1->dev && !memcmp(n1->primary_key, n->primary_key, key_len)) {
640a263b309SDavid S. Miller 			if (want_ref)
6411da177e4SLinus Torvalds 				neigh_hold(n1);
6421da177e4SLinus Torvalds 			rc = n1;
6431da177e4SLinus Torvalds 			goto out_tbl_unlock;
6441da177e4SLinus Torvalds 		}
6451da177e4SLinus Torvalds 	}
6461da177e4SLinus Torvalds 
6471da177e4SLinus Torvalds 	n->dead = 0;
648e997f8a2SDavid Ahern 	if (!exempt_from_gc)
6498cc196d6SDavid Ahern 		list_add_tail(&n->gc_list, &n->tbl->gc_list);
6508cc196d6SDavid Ahern 
651a263b309SDavid S. Miller 	if (want_ref)
6521da177e4SLinus Torvalds 		neigh_hold(n);
653767e97e1SEric Dumazet 	rcu_assign_pointer(n->next,
654767e97e1SEric Dumazet 			   rcu_dereference_protected(nht->hash_buckets[hash_val],
655767e97e1SEric Dumazet 						     lockdep_is_held(&tbl->lock)));
656767e97e1SEric Dumazet 	rcu_assign_pointer(nht->hash_buckets[hash_val], n);
6571da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
658d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is created\n", n);
6591da177e4SLinus Torvalds 	rc = n;
6601da177e4SLinus Torvalds out:
6611da177e4SLinus Torvalds 	return rc;
6621da177e4SLinus Torvalds out_tbl_unlock:
6631da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
6641da177e4SLinus Torvalds out_neigh_release:
66564c6f4bbSDavid Ahern 	if (!exempt_from_gc)
66664c6f4bbSDavid Ahern 		atomic_dec(&tbl->gc_entries);
6671da177e4SLinus Torvalds 	neigh_release(n);
6681da177e4SLinus Torvalds 	goto out;
6691da177e4SLinus Torvalds }
67058956317SDavid Ahern 
67158956317SDavid Ahern struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
67258956317SDavid Ahern 				 struct net_device *dev, bool want_ref)
67358956317SDavid Ahern {
67458956317SDavid Ahern 	return ___neigh_create(tbl, pkey, dev, false, want_ref);
67558956317SDavid Ahern }
676a263b309SDavid S. Miller EXPORT_SYMBOL(__neigh_create);
6771da177e4SLinus Torvalds 
67801ccdf12SAlexey Dobriyan static u32 pneigh_hash(const void *pkey, unsigned int key_len)
679fa86d322SPavel Emelyanov {
680fa86d322SPavel Emelyanov 	u32 hash_val = *(u32 *)(pkey + key_len - 4);
681fa86d322SPavel Emelyanov 	hash_val ^= (hash_val >> 16);
682fa86d322SPavel Emelyanov 	hash_val ^= hash_val >> 8;
683fa86d322SPavel Emelyanov 	hash_val ^= hash_val >> 4;
684fa86d322SPavel Emelyanov 	hash_val &= PNEIGH_HASHMASK;
685be01d655SYOSHIFUJI Hideaki 	return hash_val;
686fa86d322SPavel Emelyanov }
687fa86d322SPavel Emelyanov 
688be01d655SYOSHIFUJI Hideaki static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
689be01d655SYOSHIFUJI Hideaki 					      struct net *net,
690be01d655SYOSHIFUJI Hideaki 					      const void *pkey,
69101ccdf12SAlexey Dobriyan 					      unsigned int key_len,
692be01d655SYOSHIFUJI Hideaki 					      struct net_device *dev)
693be01d655SYOSHIFUJI Hideaki {
694be01d655SYOSHIFUJI Hideaki 	while (n) {
695be01d655SYOSHIFUJI Hideaki 		if (!memcmp(n->key, pkey, key_len) &&
696be01d655SYOSHIFUJI Hideaki 		    net_eq(pneigh_net(n), net) &&
697be01d655SYOSHIFUJI Hideaki 		    (n->dev == dev || !n->dev))
698fa86d322SPavel Emelyanov 			return n;
699be01d655SYOSHIFUJI Hideaki 		n = n->next;
700be01d655SYOSHIFUJI Hideaki 	}
701be01d655SYOSHIFUJI Hideaki 	return NULL;
702be01d655SYOSHIFUJI Hideaki }
703be01d655SYOSHIFUJI Hideaki 
704be01d655SYOSHIFUJI Hideaki struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
705be01d655SYOSHIFUJI Hideaki 		struct net *net, const void *pkey, struct net_device *dev)
706be01d655SYOSHIFUJI Hideaki {
70701ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
708be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
709be01d655SYOSHIFUJI Hideaki 
710be01d655SYOSHIFUJI Hideaki 	return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
711be01d655SYOSHIFUJI Hideaki 				 net, pkey, key_len, dev);
712fa86d322SPavel Emelyanov }
7130a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL_GPL(__pneigh_lookup);
714fa86d322SPavel Emelyanov 
715426b5303SEric W. Biederman struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
716426b5303SEric W. Biederman 				    struct net *net, const void *pkey,
7171da177e4SLinus Torvalds 				    struct net_device *dev, int creat)
7181da177e4SLinus Torvalds {
7191da177e4SLinus Torvalds 	struct pneigh_entry *n;
72001ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
721be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
7221da177e4SLinus Torvalds 
7231da177e4SLinus Torvalds 	read_lock_bh(&tbl->lock);
724be01d655SYOSHIFUJI Hideaki 	n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
725be01d655SYOSHIFUJI Hideaki 			      net, pkey, key_len, dev);
726be01d655SYOSHIFUJI Hideaki 	read_unlock_bh(&tbl->lock);
7271da177e4SLinus Torvalds 
728be01d655SYOSHIFUJI Hideaki 	if (n || !creat)
7291da177e4SLinus Torvalds 		goto out;
7301da177e4SLinus Torvalds 
7314ae28944SPavel Emelyanov 	ASSERT_RTNL();
7324ae28944SPavel Emelyanov 
7331da177e4SLinus Torvalds 	n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
7341da177e4SLinus Torvalds 	if (!n)
7351da177e4SLinus Torvalds 		goto out;
7361da177e4SLinus Torvalds 
737754d5da6SDavid Ahern 	n->protocol = 0;
738efd7ef1cSEric W. Biederman 	write_pnet(&n->net, net);
7391da177e4SLinus Torvalds 	memcpy(n->key, pkey, key_len);
7401da177e4SLinus Torvalds 	n->dev = dev;
7411da177e4SLinus Torvalds 	if (dev)
7421da177e4SLinus Torvalds 		dev_hold(dev);
7431da177e4SLinus Torvalds 
7441da177e4SLinus Torvalds 	if (tbl->pconstructor && tbl->pconstructor(n)) {
7451da177e4SLinus Torvalds 		if (dev)
7461da177e4SLinus Torvalds 			dev_put(dev);
7471da177e4SLinus Torvalds 		kfree(n);
7481da177e4SLinus Torvalds 		n = NULL;
7491da177e4SLinus Torvalds 		goto out;
7501da177e4SLinus Torvalds 	}
7511da177e4SLinus Torvalds 
7521da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
7531da177e4SLinus Torvalds 	n->next = tbl->phash_buckets[hash_val];
7541da177e4SLinus Torvalds 	tbl->phash_buckets[hash_val] = n;
7551da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
7561da177e4SLinus Torvalds out:
7571da177e4SLinus Torvalds 	return n;
7581da177e4SLinus Torvalds }
7590a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(pneigh_lookup);
7601da177e4SLinus Torvalds 
7611da177e4SLinus Torvalds 
762426b5303SEric W. Biederman int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
7631da177e4SLinus Torvalds 		  struct net_device *dev)
7641da177e4SLinus Torvalds {
7651da177e4SLinus Torvalds 	struct pneigh_entry *n, **np;
76601ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
767be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
7681da177e4SLinus Torvalds 
7691da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
7701da177e4SLinus Torvalds 	for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
7711da177e4SLinus Torvalds 	     np = &n->next) {
772426b5303SEric W. Biederman 		if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
773878628fbSYOSHIFUJI Hideaki 		    net_eq(pneigh_net(n), net)) {
7741da177e4SLinus Torvalds 			*np = n->next;
7751da177e4SLinus Torvalds 			write_unlock_bh(&tbl->lock);
7761da177e4SLinus Torvalds 			if (tbl->pdestructor)
7771da177e4SLinus Torvalds 				tbl->pdestructor(n);
7781da177e4SLinus Torvalds 			if (n->dev)
7791da177e4SLinus Torvalds 				dev_put(n->dev);
7801da177e4SLinus Torvalds 			kfree(n);
7811da177e4SLinus Torvalds 			return 0;
7821da177e4SLinus Torvalds 		}
7831da177e4SLinus Torvalds 	}
7841da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
7851da177e4SLinus Torvalds 	return -ENOENT;
7861da177e4SLinus Torvalds }
7871da177e4SLinus Torvalds 
78853b76cdfSWolfgang Bumiller static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
78953b76cdfSWolfgang Bumiller 				    struct net_device *dev)
7901da177e4SLinus Torvalds {
79153b76cdfSWolfgang Bumiller 	struct pneigh_entry *n, **np, *freelist = NULL;
7921da177e4SLinus Torvalds 	u32 h;
7931da177e4SLinus Torvalds 
7941da177e4SLinus Torvalds 	for (h = 0; h <= PNEIGH_HASHMASK; h++) {
7951da177e4SLinus Torvalds 		np = &tbl->phash_buckets[h];
7961da177e4SLinus Torvalds 		while ((n = *np) != NULL) {
7971da177e4SLinus Torvalds 			if (!dev || n->dev == dev) {
7981da177e4SLinus Torvalds 				*np = n->next;
79953b76cdfSWolfgang Bumiller 				n->next = freelist;
80053b76cdfSWolfgang Bumiller 				freelist = n;
80153b76cdfSWolfgang Bumiller 				continue;
80253b76cdfSWolfgang Bumiller 			}
80353b76cdfSWolfgang Bumiller 			np = &n->next;
80453b76cdfSWolfgang Bumiller 		}
80553b76cdfSWolfgang Bumiller 	}
80653b76cdfSWolfgang Bumiller 	write_unlock_bh(&tbl->lock);
80753b76cdfSWolfgang Bumiller 	while ((n = freelist)) {
80853b76cdfSWolfgang Bumiller 		freelist = n->next;
80953b76cdfSWolfgang Bumiller 		n->next = NULL;
8101da177e4SLinus Torvalds 		if (tbl->pdestructor)
8111da177e4SLinus Torvalds 			tbl->pdestructor(n);
8121da177e4SLinus Torvalds 		if (n->dev)
8131da177e4SLinus Torvalds 			dev_put(n->dev);
8141da177e4SLinus Torvalds 		kfree(n);
8151da177e4SLinus Torvalds 	}
8161da177e4SLinus Torvalds 	return -ENOENT;
8171da177e4SLinus Torvalds }
8181da177e4SLinus Torvalds 
81906f0511dSDenis V. Lunev static void neigh_parms_destroy(struct neigh_parms *parms);
82006f0511dSDenis V. Lunev 
82106f0511dSDenis V. Lunev static inline void neigh_parms_put(struct neigh_parms *parms)
82206f0511dSDenis V. Lunev {
8236343944bSReshetova, Elena 	if (refcount_dec_and_test(&parms->refcnt))
82406f0511dSDenis V. Lunev 		neigh_parms_destroy(parms);
82506f0511dSDenis V. Lunev }
8261da177e4SLinus Torvalds 
8271da177e4SLinus Torvalds /*
8281da177e4SLinus Torvalds  *	neighbour must already be out of the table;
8291da177e4SLinus Torvalds  *
8301da177e4SLinus Torvalds  */
8311da177e4SLinus Torvalds void neigh_destroy(struct neighbour *neigh)
8321da177e4SLinus Torvalds {
833da6a8fa0SDavid Miller 	struct net_device *dev = neigh->dev;
834da6a8fa0SDavid Miller 
8351da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
8361da177e4SLinus Torvalds 
8371da177e4SLinus Torvalds 	if (!neigh->dead) {
838e005d193SJoe Perches 		pr_warn("Destroying alive neighbour %p\n", neigh);
8391da177e4SLinus Torvalds 		dump_stack();
8401da177e4SLinus Torvalds 		return;
8411da177e4SLinus Torvalds 	}
8421da177e4SLinus Torvalds 
8431da177e4SLinus Torvalds 	if (neigh_del_timer(neigh))
844e005d193SJoe Perches 		pr_warn("Impossible event\n");
8451da177e4SLinus Torvalds 
846c9ab4d85SEric Dumazet 	write_lock_bh(&neigh->lock);
847c9ab4d85SEric Dumazet 	__skb_queue_purge(&neigh->arp_queue);
848c9ab4d85SEric Dumazet 	write_unlock_bh(&neigh->lock);
8498b5c171bSEric Dumazet 	neigh->arp_queue_len_bytes = 0;
8501da177e4SLinus Torvalds 
851447f2191SDavid S. Miller 	if (dev->netdev_ops->ndo_neigh_destroy)
852503eebc2SJiri Pirko 		dev->netdev_ops->ndo_neigh_destroy(dev, neigh);
853447f2191SDavid S. Miller 
854da6a8fa0SDavid Miller 	dev_put(dev);
8551da177e4SLinus Torvalds 	neigh_parms_put(neigh->parms);
8561da177e4SLinus Torvalds 
857d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is destroyed\n", neigh);
8581da177e4SLinus Torvalds 
8591da177e4SLinus Torvalds 	atomic_dec(&neigh->tbl->entries);
8605b8b0060SDavid Miller 	kfree_rcu(neigh, rcu);
8611da177e4SLinus Torvalds }
8620a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_destroy);
8631da177e4SLinus Torvalds 
8641da177e4SLinus Torvalds /* Neighbour state is suspicious;
8651da177e4SLinus Torvalds    disable fast path.
8661da177e4SLinus Torvalds 
8671da177e4SLinus Torvalds    Called with write_locked neigh.
8681da177e4SLinus Torvalds  */
8691da177e4SLinus Torvalds static void neigh_suspect(struct neighbour *neigh)
8701da177e4SLinus Torvalds {
871d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is suspected\n", neigh);
8721da177e4SLinus Torvalds 
8731da177e4SLinus Torvalds 	neigh->output = neigh->ops->output;
8741da177e4SLinus Torvalds }
8751da177e4SLinus Torvalds 
8761da177e4SLinus Torvalds /* Neighbour state is OK;
8771da177e4SLinus Torvalds    enable fast path.
8781da177e4SLinus Torvalds 
8791da177e4SLinus Torvalds    Called with write_locked neigh.
8801da177e4SLinus Torvalds  */
8811da177e4SLinus Torvalds static void neigh_connect(struct neighbour *neigh)
8821da177e4SLinus Torvalds {
883d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is connected\n", neigh);
8841da177e4SLinus Torvalds 
8851da177e4SLinus Torvalds 	neigh->output = neigh->ops->connected_output;
8861da177e4SLinus Torvalds }
8871da177e4SLinus Torvalds 
888e4c4e448SEric Dumazet static void neigh_periodic_work(struct work_struct *work)
8891da177e4SLinus Torvalds {
890e4c4e448SEric Dumazet 	struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
891767e97e1SEric Dumazet 	struct neighbour *n;
892767e97e1SEric Dumazet 	struct neighbour __rcu **np;
893e4c4e448SEric Dumazet 	unsigned int i;
894d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
8951da177e4SLinus Torvalds 
8961da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
8971da177e4SLinus Torvalds 
898e4c4e448SEric Dumazet 	write_lock_bh(&tbl->lock);
899d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
900d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
9011da177e4SLinus Torvalds 
9021da177e4SLinus Torvalds 	/*
9031da177e4SLinus Torvalds 	 *	periodically recompute ReachableTime from random function
9041da177e4SLinus Torvalds 	 */
9051da177e4SLinus Torvalds 
906e4c4e448SEric Dumazet 	if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
9071da177e4SLinus Torvalds 		struct neigh_parms *p;
908e4c4e448SEric Dumazet 		tbl->last_rand = jiffies;
90975fbfd33SNicolas Dichtel 		list_for_each_entry(p, &tbl->parms_list, list)
9101da177e4SLinus Torvalds 			p->reachable_time =
9111f9248e5SJiri Pirko 				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
9121da177e4SLinus Torvalds 	}
9131da177e4SLinus Torvalds 
914feff9ab2SDuan Jiong 	if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
915feff9ab2SDuan Jiong 		goto out;
916feff9ab2SDuan Jiong 
917cd089336SDavid S. Miller 	for (i = 0 ; i < (1 << nht->hash_shift); i++) {
918d6bf7817SEric Dumazet 		np = &nht->hash_buckets[i];
9191da177e4SLinus Torvalds 
920767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
921767e97e1SEric Dumazet 				lockdep_is_held(&tbl->lock))) != NULL) {
9221da177e4SLinus Torvalds 			unsigned int state;
9231da177e4SLinus Torvalds 
9241da177e4SLinus Torvalds 			write_lock(&n->lock);
9251da177e4SLinus Torvalds 
9261da177e4SLinus Torvalds 			state = n->nud_state;
9279ce33e46SRoopa Prabhu 			if ((state & (NUD_PERMANENT | NUD_IN_TIMER)) ||
9289ce33e46SRoopa Prabhu 			    (n->flags & NTF_EXT_LEARNED)) {
9291da177e4SLinus Torvalds 				write_unlock(&n->lock);
9301da177e4SLinus Torvalds 				goto next_elt;
9311da177e4SLinus Torvalds 			}
9321da177e4SLinus Torvalds 
9331da177e4SLinus Torvalds 			if (time_before(n->used, n->confirmed))
9341da177e4SLinus Torvalds 				n->used = n->confirmed;
9351da177e4SLinus Torvalds 
9369f237430SReshetova, Elena 			if (refcount_read(&n->refcnt) == 1 &&
9371da177e4SLinus Torvalds 			    (state == NUD_FAILED ||
9381f9248e5SJiri Pirko 			     time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
9391da177e4SLinus Torvalds 				*np = n->next;
94058956317SDavid Ahern 				neigh_mark_dead(n);
9411da177e4SLinus Torvalds 				write_unlock(&n->lock);
9424f494554SThomas Graf 				neigh_cleanup_and_release(n);
9431da177e4SLinus Torvalds 				continue;
9441da177e4SLinus Torvalds 			}
9451da177e4SLinus Torvalds 			write_unlock(&n->lock);
9461da177e4SLinus Torvalds 
9471da177e4SLinus Torvalds next_elt:
9481da177e4SLinus Torvalds 			np = &n->next;
9491da177e4SLinus Torvalds 		}
950e4c4e448SEric Dumazet 		/*
951e4c4e448SEric Dumazet 		 * It's fine to release lock here, even if hash table
952e4c4e448SEric Dumazet 		 * grows while we are preempted.
953e4c4e448SEric Dumazet 		 */
954e4c4e448SEric Dumazet 		write_unlock_bh(&tbl->lock);
955e4c4e448SEric Dumazet 		cond_resched();
956e4c4e448SEric Dumazet 		write_lock_bh(&tbl->lock);
95784338a6cSMichel Machado 		nht = rcu_dereference_protected(tbl->nht,
95884338a6cSMichel Machado 						lockdep_is_held(&tbl->lock));
959e4c4e448SEric Dumazet 	}
9602724680bSYOSHIFUJI Hideaki / 吉藤英明 out:
9611f9248e5SJiri Pirko 	/* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks.
9621f9248e5SJiri Pirko 	 * ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2
9631f9248e5SJiri Pirko 	 * BASE_REACHABLE_TIME.
9641da177e4SLinus Torvalds 	 */
965f618002bSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
9661f9248e5SJiri Pirko 			      NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1);
967e4c4e448SEric Dumazet 	write_unlock_bh(&tbl->lock);
9681da177e4SLinus Torvalds }
9691da177e4SLinus Torvalds 
9701da177e4SLinus Torvalds static __inline__ int neigh_max_probes(struct neighbour *n)
9711da177e4SLinus Torvalds {
9721da177e4SLinus Torvalds 	struct neigh_parms *p = n->parms;
9738da86466SYOSHIFUJI Hideaki/吉藤英明 	return NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) +
9748da86466SYOSHIFUJI Hideaki/吉藤英明 	       (n->nud_state & NUD_PROBE ? NEIGH_VAR(p, MCAST_REPROBES) :
9758da86466SYOSHIFUJI Hideaki/吉藤英明 	        NEIGH_VAR(p, MCAST_PROBES));
9761da177e4SLinus Torvalds }
9771da177e4SLinus Torvalds 
9785ef12d98STimo Teras static void neigh_invalidate(struct neighbour *neigh)
9790a141509SEric Dumazet 	__releases(neigh->lock)
9800a141509SEric Dumazet 	__acquires(neigh->lock)
9815ef12d98STimo Teras {
9825ef12d98STimo Teras 	struct sk_buff *skb;
9835ef12d98STimo Teras 
9845ef12d98STimo Teras 	NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
985d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is failed\n", neigh);
9865ef12d98STimo Teras 	neigh->updated = jiffies;
9875ef12d98STimo Teras 
9885ef12d98STimo Teras 	/* It is very thin place. report_unreachable is very complicated
9895ef12d98STimo Teras 	   routine. Particularly, it can hit the same neighbour entry!
9905ef12d98STimo Teras 
9915ef12d98STimo Teras 	   So that, we try to be accurate and avoid dead loop. --ANK
9925ef12d98STimo Teras 	 */
9935ef12d98STimo Teras 	while (neigh->nud_state == NUD_FAILED &&
9945ef12d98STimo Teras 	       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
9955ef12d98STimo Teras 		write_unlock(&neigh->lock);
9965ef12d98STimo Teras 		neigh->ops->error_report(neigh, skb);
9975ef12d98STimo Teras 		write_lock(&neigh->lock);
9985ef12d98STimo Teras 	}
999c9ab4d85SEric Dumazet 	__skb_queue_purge(&neigh->arp_queue);
10008b5c171bSEric Dumazet 	neigh->arp_queue_len_bytes = 0;
10015ef12d98STimo Teras }
10025ef12d98STimo Teras 
1003cd28ca0aSEric Dumazet static void neigh_probe(struct neighbour *neigh)
1004cd28ca0aSEric Dumazet 	__releases(neigh->lock)
1005cd28ca0aSEric Dumazet {
10064ed377e3SHannes Frederic Sowa 	struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);
1007cd28ca0aSEric Dumazet 	/* keep skb alive even if arp_queue overflows */
1008cd28ca0aSEric Dumazet 	if (skb)
100919125c1aSMartin Zhang 		skb = skb_clone(skb, GFP_ATOMIC);
1010cd28ca0aSEric Dumazet 	write_unlock(&neigh->lock);
101148481c8fSEric Dumazet 	if (neigh->ops->solicit)
1012cd28ca0aSEric Dumazet 		neigh->ops->solicit(neigh, skb);
1013cd28ca0aSEric Dumazet 	atomic_inc(&neigh->probes);
101487fff3caSYang Wei 	consume_skb(skb);
1015cd28ca0aSEric Dumazet }
1016cd28ca0aSEric Dumazet 
10171da177e4SLinus Torvalds /* Called when a timer expires for a neighbour entry. */
10181da177e4SLinus Torvalds 
1019e99e88a9SKees Cook static void neigh_timer_handler(struct timer_list *t)
10201da177e4SLinus Torvalds {
10211da177e4SLinus Torvalds 	unsigned long now, next;
1022e99e88a9SKees Cook 	struct neighbour *neigh = from_timer(neigh, t, timer);
102395c96174SEric Dumazet 	unsigned int state;
10241da177e4SLinus Torvalds 	int notify = 0;
10251da177e4SLinus Torvalds 
10261da177e4SLinus Torvalds 	write_lock(&neigh->lock);
10271da177e4SLinus Torvalds 
10281da177e4SLinus Torvalds 	state = neigh->nud_state;
10291da177e4SLinus Torvalds 	now = jiffies;
10301da177e4SLinus Torvalds 	next = now + HZ;
10311da177e4SLinus Torvalds 
1032045f7b3bSDavid S. Miller 	if (!(state & NUD_IN_TIMER))
10331da177e4SLinus Torvalds 		goto out;
10341da177e4SLinus Torvalds 
10351da177e4SLinus Torvalds 	if (state & NUD_REACHABLE) {
10361da177e4SLinus Torvalds 		if (time_before_eq(now,
10371da177e4SLinus Torvalds 				   neigh->confirmed + neigh->parms->reachable_time)) {
1038d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is still alive\n", neigh);
10391da177e4SLinus Torvalds 			next = neigh->confirmed + neigh->parms->reachable_time;
10401da177e4SLinus Torvalds 		} else if (time_before_eq(now,
10411f9248e5SJiri Pirko 					  neigh->used +
10421f9248e5SJiri Pirko 					  NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
1043d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is delayed\n", neigh);
10441da177e4SLinus Torvalds 			neigh->nud_state = NUD_DELAY;
1045955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10461da177e4SLinus Torvalds 			neigh_suspect(neigh);
10471f9248e5SJiri Pirko 			next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME);
10481da177e4SLinus Torvalds 		} else {
1049d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is suspected\n", neigh);
10501da177e4SLinus Torvalds 			neigh->nud_state = NUD_STALE;
1051955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10521da177e4SLinus Torvalds 			neigh_suspect(neigh);
10538d71740cSTom Tucker 			notify = 1;
10541da177e4SLinus Torvalds 		}
10551da177e4SLinus Torvalds 	} else if (state & NUD_DELAY) {
10561da177e4SLinus Torvalds 		if (time_before_eq(now,
10571f9248e5SJiri Pirko 				   neigh->confirmed +
10581f9248e5SJiri Pirko 				   NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
1059d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is now reachable\n", neigh);
10601da177e4SLinus Torvalds 			neigh->nud_state = NUD_REACHABLE;
1061955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10621da177e4SLinus Torvalds 			neigh_connect(neigh);
10638d71740cSTom Tucker 			notify = 1;
10641da177e4SLinus Torvalds 			next = neigh->confirmed + neigh->parms->reachable_time;
10651da177e4SLinus Torvalds 		} else {
1066d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is probed\n", neigh);
10671da177e4SLinus Torvalds 			neigh->nud_state = NUD_PROBE;
1068955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10691da177e4SLinus Torvalds 			atomic_set(&neigh->probes, 0);
1070765c9c63SErik Kline 			notify = 1;
10711f9248e5SJiri Pirko 			next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
10721da177e4SLinus Torvalds 		}
10731da177e4SLinus Torvalds 	} else {
10741da177e4SLinus Torvalds 		/* NUD_PROBE|NUD_INCOMPLETE */
10751f9248e5SJiri Pirko 		next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
10761da177e4SLinus Torvalds 	}
10771da177e4SLinus Torvalds 
10781da177e4SLinus Torvalds 	if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
10791da177e4SLinus Torvalds 	    atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
10801da177e4SLinus Torvalds 		neigh->nud_state = NUD_FAILED;
10811da177e4SLinus Torvalds 		notify = 1;
10825ef12d98STimo Teras 		neigh_invalidate(neigh);
10835e2c21dcSDuan Jiong 		goto out;
10841da177e4SLinus Torvalds 	}
10851da177e4SLinus Torvalds 
10861da177e4SLinus Torvalds 	if (neigh->nud_state & NUD_IN_TIMER) {
10871da177e4SLinus Torvalds 		if (time_before(next, jiffies + HZ/2))
10881da177e4SLinus Torvalds 			next = jiffies + HZ/2;
10896fb9974fSHerbert Xu 		if (!mod_timer(&neigh->timer, next))
10906fb9974fSHerbert Xu 			neigh_hold(neigh);
10911da177e4SLinus Torvalds 	}
10921da177e4SLinus Torvalds 	if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
1093cd28ca0aSEric Dumazet 		neigh_probe(neigh);
10949ff56607SDavid S. Miller 	} else {
10951da177e4SLinus Torvalds out:
10961da177e4SLinus Torvalds 		write_unlock(&neigh->lock);
10979ff56607SDavid S. Miller 	}
10981da177e4SLinus Torvalds 
1099d961db35SThomas Graf 	if (notify)
11007b8f7a40SRoopa Prabhu 		neigh_update_notify(neigh, 0);
1101d961db35SThomas Graf 
110256dd18a4SRoopa Prabhu 	trace_neigh_timer_handler(neigh, 0);
110356dd18a4SRoopa Prabhu 
11041da177e4SLinus Torvalds 	neigh_release(neigh);
11051da177e4SLinus Torvalds }
11061da177e4SLinus Torvalds 
11071da177e4SLinus Torvalds int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
11081da177e4SLinus Torvalds {
11091da177e4SLinus Torvalds 	int rc;
1110cd28ca0aSEric Dumazet 	bool immediate_probe = false;
11111da177e4SLinus Torvalds 
11121da177e4SLinus Torvalds 	write_lock_bh(&neigh->lock);
11131da177e4SLinus Torvalds 
11141da177e4SLinus Torvalds 	rc = 0;
11151da177e4SLinus Torvalds 	if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
11161da177e4SLinus Torvalds 		goto out_unlock_bh;
11172c51a97fSJulian Anastasov 	if (neigh->dead)
11182c51a97fSJulian Anastasov 		goto out_dead;
11191da177e4SLinus Torvalds 
11201da177e4SLinus Torvalds 	if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
11211f9248e5SJiri Pirko 		if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
11221f9248e5SJiri Pirko 		    NEIGH_VAR(neigh->parms, APP_PROBES)) {
1123cd28ca0aSEric Dumazet 			unsigned long next, now = jiffies;
1124cd28ca0aSEric Dumazet 
11251f9248e5SJiri Pirko 			atomic_set(&neigh->probes,
11261f9248e5SJiri Pirko 				   NEIGH_VAR(neigh->parms, UCAST_PROBES));
1127071c3798SLorenzo Bianconi 			neigh_del_timer(neigh);
11281da177e4SLinus Torvalds 			neigh->nud_state     = NUD_INCOMPLETE;
1129cd28ca0aSEric Dumazet 			neigh->updated = now;
11301f9248e5SJiri Pirko 			next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
11311f9248e5SJiri Pirko 					 HZ/2);
1132cd28ca0aSEric Dumazet 			neigh_add_timer(neigh, next);
1133cd28ca0aSEric Dumazet 			immediate_probe = true;
11341da177e4SLinus Torvalds 		} else {
11351da177e4SLinus Torvalds 			neigh->nud_state = NUD_FAILED;
1136955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
11371da177e4SLinus Torvalds 			write_unlock_bh(&neigh->lock);
11381da177e4SLinus Torvalds 
11391da177e4SLinus Torvalds 			kfree_skb(skb);
11401da177e4SLinus Torvalds 			return 1;
11411da177e4SLinus Torvalds 		}
11421da177e4SLinus Torvalds 	} else if (neigh->nud_state & NUD_STALE) {
1143d5d427cdSJoe Perches 		neigh_dbg(2, "neigh %p is delayed\n", neigh);
1144071c3798SLorenzo Bianconi 		neigh_del_timer(neigh);
11451da177e4SLinus Torvalds 		neigh->nud_state = NUD_DELAY;
1146955aaa2fSYOSHIFUJI Hideaki 		neigh->updated = jiffies;
11471f9248e5SJiri Pirko 		neigh_add_timer(neigh, jiffies +
11481f9248e5SJiri Pirko 				NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME));
11491da177e4SLinus Torvalds 	}
11501da177e4SLinus Torvalds 
11511da177e4SLinus Torvalds 	if (neigh->nud_state == NUD_INCOMPLETE) {
11521da177e4SLinus Torvalds 		if (skb) {
11538b5c171bSEric Dumazet 			while (neigh->arp_queue_len_bytes + skb->truesize >
11541f9248e5SJiri Pirko 			       NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) {
11551da177e4SLinus Torvalds 				struct sk_buff *buff;
11568b5c171bSEric Dumazet 
1157f72051b0SDavid S. Miller 				buff = __skb_dequeue(&neigh->arp_queue);
11588b5c171bSEric Dumazet 				if (!buff)
11598b5c171bSEric Dumazet 					break;
11608b5c171bSEric Dumazet 				neigh->arp_queue_len_bytes -= buff->truesize;
11611da177e4SLinus Torvalds 				kfree_skb(buff);
11629a6d276eSNeil Horman 				NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
11631da177e4SLinus Torvalds 			}
1164a4731138SEric Dumazet 			skb_dst_force(skb);
11651da177e4SLinus Torvalds 			__skb_queue_tail(&neigh->arp_queue, skb);
11668b5c171bSEric Dumazet 			neigh->arp_queue_len_bytes += skb->truesize;
11671da177e4SLinus Torvalds 		}
11681da177e4SLinus Torvalds 		rc = 1;
11691da177e4SLinus Torvalds 	}
11701da177e4SLinus Torvalds out_unlock_bh:
1171cd28ca0aSEric Dumazet 	if (immediate_probe)
1172cd28ca0aSEric Dumazet 		neigh_probe(neigh);
1173cd28ca0aSEric Dumazet 	else
1174cd28ca0aSEric Dumazet 		write_unlock(&neigh->lock);
1175cd28ca0aSEric Dumazet 	local_bh_enable();
117656dd18a4SRoopa Prabhu 	trace_neigh_event_send_done(neigh, rc);
11771da177e4SLinus Torvalds 	return rc;
11782c51a97fSJulian Anastasov 
11792c51a97fSJulian Anastasov out_dead:
11802c51a97fSJulian Anastasov 	if (neigh->nud_state & NUD_STALE)
11812c51a97fSJulian Anastasov 		goto out_unlock_bh;
11822c51a97fSJulian Anastasov 	write_unlock_bh(&neigh->lock);
11832c51a97fSJulian Anastasov 	kfree_skb(skb);
118456dd18a4SRoopa Prabhu 	trace_neigh_event_send_dead(neigh, 1);
11852c51a97fSJulian Anastasov 	return 1;
11861da177e4SLinus Torvalds }
11870a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(__neigh_event_send);
11881da177e4SLinus Torvalds 
1189f6b72b62SDavid S. Miller static void neigh_update_hhs(struct neighbour *neigh)
11901da177e4SLinus Torvalds {
11911da177e4SLinus Torvalds 	struct hh_cache *hh;
11923b04dddeSStephen Hemminger 	void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
119391a72a70SDoug Kehn 		= NULL;
119491a72a70SDoug Kehn 
119591a72a70SDoug Kehn 	if (neigh->dev->header_ops)
119691a72a70SDoug Kehn 		update = neigh->dev->header_ops->cache_update;
11971da177e4SLinus Torvalds 
11981da177e4SLinus Torvalds 	if (update) {
1199f6b72b62SDavid S. Miller 		hh = &neigh->hh;
1200c305c6aeSEric Dumazet 		if (READ_ONCE(hh->hh_len)) {
12013644f0ceSStephen Hemminger 			write_seqlock_bh(&hh->hh_lock);
12021da177e4SLinus Torvalds 			update(hh, neigh->dev, neigh->ha);
12033644f0ceSStephen Hemminger 			write_sequnlock_bh(&hh->hh_lock);
12041da177e4SLinus Torvalds 		}
12051da177e4SLinus Torvalds 	}
12061da177e4SLinus Torvalds }
12071da177e4SLinus Torvalds 
12081da177e4SLinus Torvalds 
12091da177e4SLinus Torvalds 
12101da177e4SLinus Torvalds /* Generic update routine.
12111da177e4SLinus Torvalds    -- lladdr is new lladdr or NULL, if it is not supplied.
12121da177e4SLinus Torvalds    -- new    is new state.
12131da177e4SLinus Torvalds    -- flags
12141da177e4SLinus Torvalds 	NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
12151da177e4SLinus Torvalds 				if it is different.
12161da177e4SLinus Torvalds 	NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
12171da177e4SLinus Torvalds 				lladdr instead of overriding it
12181da177e4SLinus Torvalds 				if it is different.
12191da177e4SLinus Torvalds 	NEIGH_UPDATE_F_ADMIN	means that the change is administrative.
12201da177e4SLinus Torvalds 
12211da177e4SLinus Torvalds 	NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
12221da177e4SLinus Torvalds 				NTF_ROUTER flag.
12231da177e4SLinus Torvalds 	NEIGH_UPDATE_F_ISROUTER	indicates if the neighbour is known as
12241da177e4SLinus Torvalds 				a router.
12251da177e4SLinus Torvalds 
12261da177e4SLinus Torvalds    Caller MUST hold reference count on the entry.
12271da177e4SLinus Torvalds  */
12281da177e4SLinus Torvalds 
12297a35a50dSDavid Ahern static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
12307a35a50dSDavid Ahern 			  u8 new, u32 flags, u32 nlmsg_pid,
12317a35a50dSDavid Ahern 			  struct netlink_ext_ack *extack)
12321da177e4SLinus Torvalds {
1233e997f8a2SDavid Ahern 	bool ext_learn_change = false;
12341da177e4SLinus Torvalds 	u8 old;
12351da177e4SLinus Torvalds 	int err;
12361da177e4SLinus Torvalds 	int notify = 0;
12371da177e4SLinus Torvalds 	struct net_device *dev;
12381da177e4SLinus Torvalds 	int update_isrouter = 0;
12391da177e4SLinus Torvalds 
124056dd18a4SRoopa Prabhu 	trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid);
124156dd18a4SRoopa Prabhu 
12421da177e4SLinus Torvalds 	write_lock_bh(&neigh->lock);
12431da177e4SLinus Torvalds 
12441da177e4SLinus Torvalds 	dev    = neigh->dev;
12451da177e4SLinus Torvalds 	old    = neigh->nud_state;
12461da177e4SLinus Torvalds 	err    = -EPERM;
12471da177e4SLinus Torvalds 
12481da177e4SLinus Torvalds 	if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
12491da177e4SLinus Torvalds 	    (old & (NUD_NOARP | NUD_PERMANENT)))
12501da177e4SLinus Torvalds 		goto out;
12517a35a50dSDavid Ahern 	if (neigh->dead) {
12527a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Neighbor entry is now dead");
12532c51a97fSJulian Anastasov 		goto out;
12547a35a50dSDavid Ahern 	}
12551da177e4SLinus Torvalds 
1256e997f8a2SDavid Ahern 	ext_learn_change = neigh_update_ext_learned(neigh, flags, &notify);
12579ce33e46SRoopa Prabhu 
12581da177e4SLinus Torvalds 	if (!(new & NUD_VALID)) {
12591da177e4SLinus Torvalds 		neigh_del_timer(neigh);
12601da177e4SLinus Torvalds 		if (old & NUD_CONNECTED)
12611da177e4SLinus Torvalds 			neigh_suspect(neigh);
12629c29a2f5SDavid Ahern 		neigh->nud_state = new;
12631da177e4SLinus Torvalds 		err = 0;
12641da177e4SLinus Torvalds 		notify = old & NUD_VALID;
1265d2fb4fb8SRoopa Prabhu 		if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
12665ef12d98STimo Teras 		    (new & NUD_FAILED)) {
12675ef12d98STimo Teras 			neigh_invalidate(neigh);
12685ef12d98STimo Teras 			notify = 1;
12695ef12d98STimo Teras 		}
12701da177e4SLinus Torvalds 		goto out;
12711da177e4SLinus Torvalds 	}
12721da177e4SLinus Torvalds 
12731da177e4SLinus Torvalds 	/* Compare new lladdr with cached one */
12741da177e4SLinus Torvalds 	if (!dev->addr_len) {
12751da177e4SLinus Torvalds 		/* First case: device needs no address. */
12761da177e4SLinus Torvalds 		lladdr = neigh->ha;
12771da177e4SLinus Torvalds 	} else if (lladdr) {
12781da177e4SLinus Torvalds 		/* The second case: if something is already cached
12791da177e4SLinus Torvalds 		   and a new address is proposed:
12801da177e4SLinus Torvalds 		   - compare new & old
12811da177e4SLinus Torvalds 		   - if they are different, check override flag
12821da177e4SLinus Torvalds 		 */
12831da177e4SLinus Torvalds 		if ((old & NUD_VALID) &&
12841da177e4SLinus Torvalds 		    !memcmp(lladdr, neigh->ha, dev->addr_len))
12851da177e4SLinus Torvalds 			lladdr = neigh->ha;
12861da177e4SLinus Torvalds 	} else {
12871da177e4SLinus Torvalds 		/* No address is supplied; if we know something,
12881da177e4SLinus Torvalds 		   use it, otherwise discard the request.
12891da177e4SLinus Torvalds 		 */
12901da177e4SLinus Torvalds 		err = -EINVAL;
12917a35a50dSDavid Ahern 		if (!(old & NUD_VALID)) {
12927a35a50dSDavid Ahern 			NL_SET_ERR_MSG(extack, "No link layer address given");
12931da177e4SLinus Torvalds 			goto out;
12947a35a50dSDavid Ahern 		}
12951da177e4SLinus Torvalds 		lladdr = neigh->ha;
12961da177e4SLinus Torvalds 	}
12971da177e4SLinus Torvalds 
1298f0e0d044SVasily Khoruzhick 	/* Update confirmed timestamp for neighbour entry after we
1299f0e0d044SVasily Khoruzhick 	 * received ARP packet even if it doesn't change IP to MAC binding.
1300f0e0d044SVasily Khoruzhick 	 */
1301f0e0d044SVasily Khoruzhick 	if (new & NUD_CONNECTED)
1302f0e0d044SVasily Khoruzhick 		neigh->confirmed = jiffies;
1303f0e0d044SVasily Khoruzhick 
13041da177e4SLinus Torvalds 	/* If entry was valid and address is not changed,
13051da177e4SLinus Torvalds 	   do not change entry state, if new one is STALE.
13061da177e4SLinus Torvalds 	 */
13071da177e4SLinus Torvalds 	err = 0;
13081da177e4SLinus Torvalds 	update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
13091da177e4SLinus Torvalds 	if (old & NUD_VALID) {
13101da177e4SLinus Torvalds 		if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
13111da177e4SLinus Torvalds 			update_isrouter = 0;
13121da177e4SLinus Torvalds 			if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
13131da177e4SLinus Torvalds 			    (old & NUD_CONNECTED)) {
13141da177e4SLinus Torvalds 				lladdr = neigh->ha;
13151da177e4SLinus Torvalds 				new = NUD_STALE;
13161da177e4SLinus Torvalds 			} else
13171da177e4SLinus Torvalds 				goto out;
13181da177e4SLinus Torvalds 		} else {
13190e7bbcc1SJulian Anastasov 			if (lladdr == neigh->ha && new == NUD_STALE &&
13200e7bbcc1SJulian Anastasov 			    !(flags & NEIGH_UPDATE_F_ADMIN))
13211da177e4SLinus Torvalds 				new = old;
13221da177e4SLinus Torvalds 		}
13231da177e4SLinus Torvalds 	}
13241da177e4SLinus Torvalds 
1325f0e0d044SVasily Khoruzhick 	/* Update timestamp only once we know we will make a change to the
132677d71233SIhar Hrachyshka 	 * neighbour entry. Otherwise we risk to move the locktime window with
132777d71233SIhar Hrachyshka 	 * noop updates and ignore relevant ARP updates.
132877d71233SIhar Hrachyshka 	 */
1329f0e0d044SVasily Khoruzhick 	if (new != old || lladdr != neigh->ha)
133077d71233SIhar Hrachyshka 		neigh->updated = jiffies;
133177d71233SIhar Hrachyshka 
13321da177e4SLinus Torvalds 	if (new != old) {
13331da177e4SLinus Torvalds 		neigh_del_timer(neigh);
1334765c9c63SErik Kline 		if (new & NUD_PROBE)
1335765c9c63SErik Kline 			atomic_set(&neigh->probes, 0);
1336a43d8994SPavel Emelyanov 		if (new & NUD_IN_TIMER)
1337667347f1SDavid S. Miller 			neigh_add_timer(neigh, (jiffies +
13381da177e4SLinus Torvalds 						((new & NUD_REACHABLE) ?
1339667347f1SDavid S. Miller 						 neigh->parms->reachable_time :
1340667347f1SDavid S. Miller 						 0)));
13419c29a2f5SDavid Ahern 		neigh->nud_state = new;
134253385d2dSBob Gilligan 		notify = 1;
13431da177e4SLinus Torvalds 	}
13441da177e4SLinus Torvalds 
13451da177e4SLinus Torvalds 	if (lladdr != neigh->ha) {
13460ed8ddf4SEric Dumazet 		write_seqlock(&neigh->ha_lock);
13471da177e4SLinus Torvalds 		memcpy(&neigh->ha, lladdr, dev->addr_len);
13480ed8ddf4SEric Dumazet 		write_sequnlock(&neigh->ha_lock);
13491da177e4SLinus Torvalds 		neigh_update_hhs(neigh);
13501da177e4SLinus Torvalds 		if (!(new & NUD_CONNECTED))
13511da177e4SLinus Torvalds 			neigh->confirmed = jiffies -
13521f9248e5SJiri Pirko 				      (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1);
13531da177e4SLinus Torvalds 		notify = 1;
13541da177e4SLinus Torvalds 	}
13551da177e4SLinus Torvalds 	if (new == old)
13561da177e4SLinus Torvalds 		goto out;
13571da177e4SLinus Torvalds 	if (new & NUD_CONNECTED)
13581da177e4SLinus Torvalds 		neigh_connect(neigh);
13591da177e4SLinus Torvalds 	else
13601da177e4SLinus Torvalds 		neigh_suspect(neigh);
13611da177e4SLinus Torvalds 	if (!(old & NUD_VALID)) {
13621da177e4SLinus Torvalds 		struct sk_buff *skb;
13631da177e4SLinus Torvalds 
13641da177e4SLinus Torvalds 		/* Again: avoid dead loop if something went wrong */
13651da177e4SLinus Torvalds 
13661da177e4SLinus Torvalds 		while (neigh->nud_state & NUD_VALID &&
13671da177e4SLinus Torvalds 		       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
136869cce1d1SDavid S. Miller 			struct dst_entry *dst = skb_dst(skb);
136969cce1d1SDavid S. Miller 			struct neighbour *n2, *n1 = neigh;
13701da177e4SLinus Torvalds 			write_unlock_bh(&neigh->lock);
1371e049f288Sroy.qing.li@gmail.com 
1372e049f288Sroy.qing.li@gmail.com 			rcu_read_lock();
137313a43d94SDavid S. Miller 
137413a43d94SDavid S. Miller 			/* Why not just use 'neigh' as-is?  The problem is that
137513a43d94SDavid S. Miller 			 * things such as shaper, eql, and sch_teql can end up
137613a43d94SDavid S. Miller 			 * using alternative, different, neigh objects to output
137713a43d94SDavid S. Miller 			 * the packet in the output path.  So what we need to do
137813a43d94SDavid S. Miller 			 * here is re-lookup the top-level neigh in the path so
137913a43d94SDavid S. Miller 			 * we can reinject the packet there.
138013a43d94SDavid S. Miller 			 */
138113a43d94SDavid S. Miller 			n2 = NULL;
138213a43d94SDavid S. Miller 			if (dst) {
138313a43d94SDavid S. Miller 				n2 = dst_neigh_lookup_skb(dst, skb);
138413a43d94SDavid S. Miller 				if (n2)
138569cce1d1SDavid S. Miller 					n1 = n2;
138613a43d94SDavid S. Miller 			}
13878f40b161SDavid S. Miller 			n1->output(n1, skb);
138813a43d94SDavid S. Miller 			if (n2)
138913a43d94SDavid S. Miller 				neigh_release(n2);
1390e049f288Sroy.qing.li@gmail.com 			rcu_read_unlock();
1391e049f288Sroy.qing.li@gmail.com 
13921da177e4SLinus Torvalds 			write_lock_bh(&neigh->lock);
13931da177e4SLinus Torvalds 		}
1394c9ab4d85SEric Dumazet 		__skb_queue_purge(&neigh->arp_queue);
13958b5c171bSEric Dumazet 		neigh->arp_queue_len_bytes = 0;
13961da177e4SLinus Torvalds 	}
13971da177e4SLinus Torvalds out:
1398fc6e8073SRoopa Prabhu 	if (update_isrouter)
1399fc6e8073SRoopa Prabhu 		neigh_update_is_router(neigh, flags, &notify);
14001da177e4SLinus Torvalds 	write_unlock_bh(&neigh->lock);
14018d71740cSTom Tucker 
1402e997f8a2SDavid Ahern 	if (((new ^ old) & NUD_PERMANENT) || ext_learn_change)
14039c29a2f5SDavid Ahern 		neigh_update_gc_list(neigh);
14049c29a2f5SDavid Ahern 
14058d71740cSTom Tucker 	if (notify)
14067b8f7a40SRoopa Prabhu 		neigh_update_notify(neigh, nlmsg_pid);
1407d961db35SThomas Graf 
140856dd18a4SRoopa Prabhu 	trace_neigh_update_done(neigh, err);
140956dd18a4SRoopa Prabhu 
14101da177e4SLinus Torvalds 	return err;
14111da177e4SLinus Torvalds }
14127a35a50dSDavid Ahern 
14137a35a50dSDavid Ahern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
14147a35a50dSDavid Ahern 		 u32 flags, u32 nlmsg_pid)
14157a35a50dSDavid Ahern {
14167a35a50dSDavid Ahern 	return __neigh_update(neigh, lladdr, new, flags, nlmsg_pid, NULL);
14177a35a50dSDavid Ahern }
14180a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_update);
14191da177e4SLinus Torvalds 
14207e980569SJiri Benc /* Update the neigh to listen temporarily for probe responses, even if it is
14217e980569SJiri Benc  * in a NUD_FAILED state. The caller has to hold neigh->lock for writing.
14227e980569SJiri Benc  */
14237e980569SJiri Benc void __neigh_set_probe_once(struct neighbour *neigh)
14247e980569SJiri Benc {
14252c51a97fSJulian Anastasov 	if (neigh->dead)
14262c51a97fSJulian Anastasov 		return;
14277e980569SJiri Benc 	neigh->updated = jiffies;
14287e980569SJiri Benc 	if (!(neigh->nud_state & NUD_FAILED))
14297e980569SJiri Benc 		return;
14302176d5d4SDuan Jiong 	neigh->nud_state = NUD_INCOMPLETE;
14312176d5d4SDuan Jiong 	atomic_set(&neigh->probes, neigh_max_probes(neigh));
14327e980569SJiri Benc 	neigh_add_timer(neigh,
14337e980569SJiri Benc 			jiffies + NEIGH_VAR(neigh->parms, RETRANS_TIME));
14347e980569SJiri Benc }
14357e980569SJiri Benc EXPORT_SYMBOL(__neigh_set_probe_once);
14367e980569SJiri Benc 
14371da177e4SLinus Torvalds struct neighbour *neigh_event_ns(struct neigh_table *tbl,
14381da177e4SLinus Torvalds 				 u8 *lladdr, void *saddr,
14391da177e4SLinus Torvalds 				 struct net_device *dev)
14401da177e4SLinus Torvalds {
14411da177e4SLinus Torvalds 	struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
14421da177e4SLinus Torvalds 						 lladdr || !dev->addr_len);
14431da177e4SLinus Torvalds 	if (neigh)
14441da177e4SLinus Torvalds 		neigh_update(neigh, lladdr, NUD_STALE,
14457b8f7a40SRoopa Prabhu 			     NEIGH_UPDATE_F_OVERRIDE, 0);
14461da177e4SLinus Torvalds 	return neigh;
14471da177e4SLinus Torvalds }
14480a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_event_ns);
14491da177e4SLinus Torvalds 
145034d101ddSEric Dumazet /* called with read_lock_bh(&n->lock); */
1451bdf53c58SEric W. Biederman static void neigh_hh_init(struct neighbour *n)
14521da177e4SLinus Torvalds {
1453bdf53c58SEric W. Biederman 	struct net_device *dev = n->dev;
1454bdf53c58SEric W. Biederman 	__be16 prot = n->tbl->protocol;
1455f6b72b62SDavid S. Miller 	struct hh_cache	*hh = &n->hh;
14560ed8ddf4SEric Dumazet 
14570ed8ddf4SEric Dumazet 	write_lock_bh(&n->lock);
145834d101ddSEric Dumazet 
1459f6b72b62SDavid S. Miller 	/* Only one thread can come in here and initialize the
1460f6b72b62SDavid S. Miller 	 * hh_cache entry.
1461f6b72b62SDavid S. Miller 	 */
1462b23b5455SDavid S. Miller 	if (!hh->hh_len)
1463b23b5455SDavid S. Miller 		dev->header_ops->cache(n, hh, prot);
1464f6b72b62SDavid S. Miller 
14650ed8ddf4SEric Dumazet 	write_unlock_bh(&n->lock);
14661da177e4SLinus Torvalds }
14671da177e4SLinus Torvalds 
14681da177e4SLinus Torvalds /* Slow and careful. */
14691da177e4SLinus Torvalds 
14708f40b161SDavid S. Miller int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
14711da177e4SLinus Torvalds {
14721da177e4SLinus Torvalds 	int rc = 0;
14731da177e4SLinus Torvalds 
14741da177e4SLinus Torvalds 	if (!neigh_event_send(neigh, skb)) {
14751da177e4SLinus Torvalds 		int err;
14761da177e4SLinus Torvalds 		struct net_device *dev = neigh->dev;
14770ed8ddf4SEric Dumazet 		unsigned int seq;
147834d101ddSEric Dumazet 
1479c305c6aeSEric Dumazet 		if (dev->header_ops->cache && !READ_ONCE(neigh->hh.hh_len))
1480bdf53c58SEric W. Biederman 			neigh_hh_init(neigh);
148134d101ddSEric Dumazet 
14820ed8ddf4SEric Dumazet 		do {
1483e1f16503Sramesh.nagappa@gmail.com 			__skb_pull(skb, skb_network_offset(skb));
14840ed8ddf4SEric Dumazet 			seq = read_seqbegin(&neigh->ha_lock);
14850c4e8581SStephen Hemminger 			err = dev_hard_header(skb, dev, ntohs(skb->protocol),
14861da177e4SLinus Torvalds 					      neigh->ha, NULL, skb->len);
14870ed8ddf4SEric Dumazet 		} while (read_seqretry(&neigh->ha_lock, seq));
148834d101ddSEric Dumazet 
14891da177e4SLinus Torvalds 		if (err >= 0)
1490542d4d68SDavid S. Miller 			rc = dev_queue_xmit(skb);
14911da177e4SLinus Torvalds 		else
14921da177e4SLinus Torvalds 			goto out_kfree_skb;
14931da177e4SLinus Torvalds 	}
14941da177e4SLinus Torvalds out:
14951da177e4SLinus Torvalds 	return rc;
14961da177e4SLinus Torvalds out_kfree_skb:
14971da177e4SLinus Torvalds 	rc = -EINVAL;
14981da177e4SLinus Torvalds 	kfree_skb(skb);
14991da177e4SLinus Torvalds 	goto out;
15001da177e4SLinus Torvalds }
15010a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_resolve_output);
15021da177e4SLinus Torvalds 
15031da177e4SLinus Torvalds /* As fast as possible without hh cache */
15041da177e4SLinus Torvalds 
15058f40b161SDavid S. Miller int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
15061da177e4SLinus Torvalds {
15071da177e4SLinus Torvalds 	struct net_device *dev = neigh->dev;
15080ed8ddf4SEric Dumazet 	unsigned int seq;
15098f40b161SDavid S. Miller 	int err;
15101da177e4SLinus Torvalds 
15110ed8ddf4SEric Dumazet 	do {
1512e1f16503Sramesh.nagappa@gmail.com 		__skb_pull(skb, skb_network_offset(skb));
15130ed8ddf4SEric Dumazet 		seq = read_seqbegin(&neigh->ha_lock);
15140c4e8581SStephen Hemminger 		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
15151da177e4SLinus Torvalds 				      neigh->ha, NULL, skb->len);
15160ed8ddf4SEric Dumazet 	} while (read_seqretry(&neigh->ha_lock, seq));
15170ed8ddf4SEric Dumazet 
15181da177e4SLinus Torvalds 	if (err >= 0)
1519542d4d68SDavid S. Miller 		err = dev_queue_xmit(skb);
15201da177e4SLinus Torvalds 	else {
15211da177e4SLinus Torvalds 		err = -EINVAL;
15221da177e4SLinus Torvalds 		kfree_skb(skb);
15231da177e4SLinus Torvalds 	}
15241da177e4SLinus Torvalds 	return err;
15251da177e4SLinus Torvalds }
15260a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_connected_output);
15271da177e4SLinus Torvalds 
15288f40b161SDavid S. Miller int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
15298f40b161SDavid S. Miller {
15308f40b161SDavid S. Miller 	return dev_queue_xmit(skb);
15318f40b161SDavid S. Miller }
15328f40b161SDavid S. Miller EXPORT_SYMBOL(neigh_direct_output);
15338f40b161SDavid S. Miller 
1534e99e88a9SKees Cook static void neigh_proxy_process(struct timer_list *t)
15351da177e4SLinus Torvalds {
1536e99e88a9SKees Cook 	struct neigh_table *tbl = from_timer(tbl, t, proxy_timer);
15371da177e4SLinus Torvalds 	long sched_next = 0;
15381da177e4SLinus Torvalds 	unsigned long now = jiffies;
1539f72051b0SDavid S. Miller 	struct sk_buff *skb, *n;
15401da177e4SLinus Torvalds 
15411da177e4SLinus Torvalds 	spin_lock(&tbl->proxy_queue.lock);
15421da177e4SLinus Torvalds 
1543f72051b0SDavid S. Miller 	skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1544f72051b0SDavid S. Miller 		long tdif = NEIGH_CB(skb)->sched_next - now;
15451da177e4SLinus Torvalds 
15461da177e4SLinus Torvalds 		if (tdif <= 0) {
1547f72051b0SDavid S. Miller 			struct net_device *dev = skb->dev;
154820e6074eSEric Dumazet 
1549f72051b0SDavid S. Miller 			__skb_unlink(skb, &tbl->proxy_queue);
155020e6074eSEric Dumazet 			if (tbl->proxy_redo && netif_running(dev)) {
155120e6074eSEric Dumazet 				rcu_read_lock();
1552f72051b0SDavid S. Miller 				tbl->proxy_redo(skb);
155320e6074eSEric Dumazet 				rcu_read_unlock();
155420e6074eSEric Dumazet 			} else {
1555f72051b0SDavid S. Miller 				kfree_skb(skb);
155620e6074eSEric Dumazet 			}
15571da177e4SLinus Torvalds 
15581da177e4SLinus Torvalds 			dev_put(dev);
15591da177e4SLinus Torvalds 		} else if (!sched_next || tdif < sched_next)
15601da177e4SLinus Torvalds 			sched_next = tdif;
15611da177e4SLinus Torvalds 	}
15621da177e4SLinus Torvalds 	del_timer(&tbl->proxy_timer);
15631da177e4SLinus Torvalds 	if (sched_next)
15641da177e4SLinus Torvalds 		mod_timer(&tbl->proxy_timer, jiffies + sched_next);
15651da177e4SLinus Torvalds 	spin_unlock(&tbl->proxy_queue.lock);
15661da177e4SLinus Torvalds }
15671da177e4SLinus Torvalds 
15681da177e4SLinus Torvalds void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
15691da177e4SLinus Torvalds 		    struct sk_buff *skb)
15701da177e4SLinus Torvalds {
15711da177e4SLinus Torvalds 	unsigned long now = jiffies;
157263862b5bSAruna-Hewapathirane 
157363862b5bSAruna-Hewapathirane 	unsigned long sched_next = now + (prandom_u32() %
15741f9248e5SJiri Pirko 					  NEIGH_VAR(p, PROXY_DELAY));
15751da177e4SLinus Torvalds 
15761f9248e5SJiri Pirko 	if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) {
15771da177e4SLinus Torvalds 		kfree_skb(skb);
15781da177e4SLinus Torvalds 		return;
15791da177e4SLinus Torvalds 	}
1580a61bbcf2SPatrick McHardy 
1581a61bbcf2SPatrick McHardy 	NEIGH_CB(skb)->sched_next = sched_next;
1582a61bbcf2SPatrick McHardy 	NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
15831da177e4SLinus Torvalds 
15841da177e4SLinus Torvalds 	spin_lock(&tbl->proxy_queue.lock);
15851da177e4SLinus Torvalds 	if (del_timer(&tbl->proxy_timer)) {
15861da177e4SLinus Torvalds 		if (time_before(tbl->proxy_timer.expires, sched_next))
15871da177e4SLinus Torvalds 			sched_next = tbl->proxy_timer.expires;
15881da177e4SLinus Torvalds 	}
1589adf30907SEric Dumazet 	skb_dst_drop(skb);
15901da177e4SLinus Torvalds 	dev_hold(skb->dev);
15911da177e4SLinus Torvalds 	__skb_queue_tail(&tbl->proxy_queue, skb);
15921da177e4SLinus Torvalds 	mod_timer(&tbl->proxy_timer, sched_next);
15931da177e4SLinus Torvalds 	spin_unlock(&tbl->proxy_queue.lock);
15941da177e4SLinus Torvalds }
15950a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(pneigh_enqueue);
15961da177e4SLinus Torvalds 
159797fd5bc7STobias Klauser static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
1598426b5303SEric W. Biederman 						      struct net *net, int ifindex)
1599426b5303SEric W. Biederman {
1600426b5303SEric W. Biederman 	struct neigh_parms *p;
1601426b5303SEric W. Biederman 
160275fbfd33SNicolas Dichtel 	list_for_each_entry(p, &tbl->parms_list, list) {
1603878628fbSYOSHIFUJI Hideaki 		if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
1604170d6f99SGao feng 		    (!p->dev && !ifindex && net_eq(net, &init_net)))
1605426b5303SEric W. Biederman 			return p;
1606426b5303SEric W. Biederman 	}
1607426b5303SEric W. Biederman 
1608426b5303SEric W. Biederman 	return NULL;
1609426b5303SEric W. Biederman }
16101da177e4SLinus Torvalds 
16111da177e4SLinus Torvalds struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
16121da177e4SLinus Torvalds 				      struct neigh_table *tbl)
16131da177e4SLinus Torvalds {
1614cf89d6b2SGao feng 	struct neigh_parms *p;
161500829823SStephen Hemminger 	struct net *net = dev_net(dev);
161600829823SStephen Hemminger 	const struct net_device_ops *ops = dev->netdev_ops;
16171da177e4SLinus Torvalds 
1618cf89d6b2SGao feng 	p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL);
16191da177e4SLinus Torvalds 	if (p) {
16201da177e4SLinus Torvalds 		p->tbl		  = tbl;
16216343944bSReshetova, Elena 		refcount_set(&p->refcnt, 1);
16221da177e4SLinus Torvalds 		p->reachable_time =
16231f9248e5SJiri Pirko 				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
1624c7fb64dbSThomas Graf 		dev_hold(dev);
1625c7fb64dbSThomas Graf 		p->dev = dev;
1626efd7ef1cSEric W. Biederman 		write_pnet(&p->net, net);
16271da177e4SLinus Torvalds 		p->sysctl_table = NULL;
162863134803SVeaceslav Falico 
162963134803SVeaceslav Falico 		if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
163063134803SVeaceslav Falico 			dev_put(dev);
163163134803SVeaceslav Falico 			kfree(p);
163263134803SVeaceslav Falico 			return NULL;
163363134803SVeaceslav Falico 		}
163463134803SVeaceslav Falico 
16351da177e4SLinus Torvalds 		write_lock_bh(&tbl->lock);
163675fbfd33SNicolas Dichtel 		list_add(&p->list, &tbl->parms.list);
16371da177e4SLinus Torvalds 		write_unlock_bh(&tbl->lock);
16381d4c8c29SJiri Pirko 
16391d4c8c29SJiri Pirko 		neigh_parms_data_state_cleanall(p);
16401da177e4SLinus Torvalds 	}
16411da177e4SLinus Torvalds 	return p;
16421da177e4SLinus Torvalds }
16430a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_parms_alloc);
16441da177e4SLinus Torvalds 
16451da177e4SLinus Torvalds static void neigh_rcu_free_parms(struct rcu_head *head)
16461da177e4SLinus Torvalds {
16471da177e4SLinus Torvalds 	struct neigh_parms *parms =
16481da177e4SLinus Torvalds 		container_of(head, struct neigh_parms, rcu_head);
16491da177e4SLinus Torvalds 
16501da177e4SLinus Torvalds 	neigh_parms_put(parms);
16511da177e4SLinus Torvalds }
16521da177e4SLinus Torvalds 
16531da177e4SLinus Torvalds void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
16541da177e4SLinus Torvalds {
16551da177e4SLinus Torvalds 	if (!parms || parms == &tbl->parms)
16561da177e4SLinus Torvalds 		return;
16571da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
165875fbfd33SNicolas Dichtel 	list_del(&parms->list);
16591da177e4SLinus Torvalds 	parms->dead = 1;
16601da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
1661cecbb639SDavid S. Miller 	if (parms->dev)
1662cecbb639SDavid S. Miller 		dev_put(parms->dev);
16631da177e4SLinus Torvalds 	call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
16641da177e4SLinus Torvalds }
16650a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_parms_release);
16661da177e4SLinus Torvalds 
166706f0511dSDenis V. Lunev static void neigh_parms_destroy(struct neigh_parms *parms)
16681da177e4SLinus Torvalds {
16691da177e4SLinus Torvalds 	kfree(parms);
16701da177e4SLinus Torvalds }
16711da177e4SLinus Torvalds 
1672c2ecba71SPavel Emelianov static struct lock_class_key neigh_table_proxy_queue_class;
1673c2ecba71SPavel Emelianov 
1674d7480fd3SWANG Cong static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly;
1675d7480fd3SWANG Cong 
1676d7480fd3SWANG Cong void neigh_table_init(int index, struct neigh_table *tbl)
16771da177e4SLinus Torvalds {
16781da177e4SLinus Torvalds 	unsigned long now = jiffies;
16791da177e4SLinus Torvalds 	unsigned long phsize;
16801da177e4SLinus Torvalds 
168175fbfd33SNicolas Dichtel 	INIT_LIST_HEAD(&tbl->parms_list);
168258956317SDavid Ahern 	INIT_LIST_HEAD(&tbl->gc_list);
168375fbfd33SNicolas Dichtel 	list_add(&tbl->parms.list, &tbl->parms_list);
1684e42ea986SEric Dumazet 	write_pnet(&tbl->parms.net, &init_net);
16856343944bSReshetova, Elena 	refcount_set(&tbl->parms.refcnt, 1);
16861da177e4SLinus Torvalds 	tbl->parms.reachable_time =
16871f9248e5SJiri Pirko 			  neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME));
16881da177e4SLinus Torvalds 
16891da177e4SLinus Torvalds 	tbl->stats = alloc_percpu(struct neigh_statistics);
16901da177e4SLinus Torvalds 	if (!tbl->stats)
16911da177e4SLinus Torvalds 		panic("cannot create neighbour cache statistics");
16921da177e4SLinus Torvalds 
16931da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
169471a5053aSChristoph Hellwig 	if (!proc_create_seq_data(tbl->id, 0, init_net.proc_net_stat,
169571a5053aSChristoph Hellwig 			      &neigh_stat_seq_ops, tbl))
16961da177e4SLinus Torvalds 		panic("cannot create neighbour proc dir entry");
16971da177e4SLinus Torvalds #endif
16981da177e4SLinus Torvalds 
1699cd089336SDavid S. Miller 	RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
17001da177e4SLinus Torvalds 
17011da177e4SLinus Torvalds 	phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
170277d04bd9SAndrew Morton 	tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
17031da177e4SLinus Torvalds 
1704d6bf7817SEric Dumazet 	if (!tbl->nht || !tbl->phash_buckets)
17051da177e4SLinus Torvalds 		panic("cannot allocate neighbour cache hashes");
17061da177e4SLinus Torvalds 
170708433effSYOSHIFUJI Hideaki / 吉藤英明 	if (!tbl->entry_size)
170808433effSYOSHIFUJI Hideaki / 吉藤英明 		tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
170908433effSYOSHIFUJI Hideaki / 吉藤英明 					tbl->key_len, NEIGH_PRIV_ALIGN);
171008433effSYOSHIFUJI Hideaki / 吉藤英明 	else
171108433effSYOSHIFUJI Hideaki / 吉藤英明 		WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
171208433effSYOSHIFUJI Hideaki / 吉藤英明 
17131da177e4SLinus Torvalds 	rwlock_init(&tbl->lock);
1714203b42f7STejun Heo 	INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
1715f618002bSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
1716f618002bSviresh kumar 			tbl->parms.reachable_time);
1717e99e88a9SKees Cook 	timer_setup(&tbl->proxy_timer, neigh_proxy_process, 0);
1718c2ecba71SPavel Emelianov 	skb_queue_head_init_class(&tbl->proxy_queue,
1719c2ecba71SPavel Emelianov 			&neigh_table_proxy_queue_class);
17201da177e4SLinus Torvalds 
17211da177e4SLinus Torvalds 	tbl->last_flush = now;
17221da177e4SLinus Torvalds 	tbl->last_rand	= now + tbl->parms.reachable_time * 20;
1723bd89efc5SSimon Kelley 
1724d7480fd3SWANG Cong 	neigh_tables[index] = tbl;
17251da177e4SLinus Torvalds }
17260a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_table_init);
17271da177e4SLinus Torvalds 
1728d7480fd3SWANG Cong int neigh_table_clear(int index, struct neigh_table *tbl)
17291da177e4SLinus Torvalds {
1730d7480fd3SWANG Cong 	neigh_tables[index] = NULL;
17311da177e4SLinus Torvalds 	/* It is not clean... Fix it to unload IPv6 module safely */
1732a5c30b34STejun Heo 	cancel_delayed_work_sync(&tbl->gc_work);
17331da177e4SLinus Torvalds 	del_timer_sync(&tbl->proxy_timer);
17341da177e4SLinus Torvalds 	pneigh_queue_purge(&tbl->proxy_queue);
17351da177e4SLinus Torvalds 	neigh_ifdown(tbl, NULL);
17361da177e4SLinus Torvalds 	if (atomic_read(&tbl->entries))
1737e005d193SJoe Perches 		pr_crit("neighbour leakage\n");
17381da177e4SLinus Torvalds 
17396193d2beSEric Dumazet 	call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
17406193d2beSEric Dumazet 		 neigh_hash_free_rcu);
1741d6bf7817SEric Dumazet 	tbl->nht = NULL;
17421da177e4SLinus Torvalds 
17431da177e4SLinus Torvalds 	kfree(tbl->phash_buckets);
17441da177e4SLinus Torvalds 	tbl->phash_buckets = NULL;
17451da177e4SLinus Torvalds 
17463f192b5cSAlexey Dobriyan 	remove_proc_entry(tbl->id, init_net.proc_net_stat);
17473f192b5cSAlexey Dobriyan 
17483fcde74bSKirill Korotaev 	free_percpu(tbl->stats);
17493fcde74bSKirill Korotaev 	tbl->stats = NULL;
17503fcde74bSKirill Korotaev 
17511da177e4SLinus Torvalds 	return 0;
17521da177e4SLinus Torvalds }
17530a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_table_clear);
17541da177e4SLinus Torvalds 
1755d7480fd3SWANG Cong static struct neigh_table *neigh_find_table(int family)
1756d7480fd3SWANG Cong {
1757d7480fd3SWANG Cong 	struct neigh_table *tbl = NULL;
1758d7480fd3SWANG Cong 
1759d7480fd3SWANG Cong 	switch (family) {
1760d7480fd3SWANG Cong 	case AF_INET:
1761d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_ARP_TABLE];
1762d7480fd3SWANG Cong 		break;
1763d7480fd3SWANG Cong 	case AF_INET6:
1764d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_ND_TABLE];
1765d7480fd3SWANG Cong 		break;
1766d7480fd3SWANG Cong 	case AF_DECnet:
1767d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_DN_TABLE];
1768d7480fd3SWANG Cong 		break;
1769d7480fd3SWANG Cong 	}
1770d7480fd3SWANG Cong 
1771d7480fd3SWANG Cong 	return tbl;
1772d7480fd3SWANG Cong }
1773d7480fd3SWANG Cong 
177482cbb5c6SRoopa Prabhu const struct nla_policy nda_policy[NDA_MAX+1] = {
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 },
178582cbb5c6SRoopa Prabhu };
178682cbb5c6SRoopa Prabhu 
1787c21ef3e3SDavid Ahern static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
1788c21ef3e3SDavid Ahern 			struct netlink_ext_ack *extack)
17891da177e4SLinus Torvalds {
17903b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
1791a14a49d2SThomas Graf 	struct ndmsg *ndm;
1792a14a49d2SThomas Graf 	struct nlattr *dst_attr;
17931da177e4SLinus Torvalds 	struct neigh_table *tbl;
1794d7480fd3SWANG Cong 	struct neighbour *neigh;
17951da177e4SLinus Torvalds 	struct net_device *dev = NULL;
1796a14a49d2SThomas Graf 	int err = -EINVAL;
17971da177e4SLinus Torvalds 
1798110b2499SEric Dumazet 	ASSERT_RTNL();
1799a14a49d2SThomas Graf 	if (nlmsg_len(nlh) < sizeof(*ndm))
18001da177e4SLinus Torvalds 		goto out;
18011da177e4SLinus Torvalds 
1802a14a49d2SThomas Graf 	dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
18037a35a50dSDavid Ahern 	if (!dst_attr) {
18047a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Network address not specified");
1805a14a49d2SThomas Graf 		goto out;
18067a35a50dSDavid Ahern 	}
1807a14a49d2SThomas Graf 
1808a14a49d2SThomas Graf 	ndm = nlmsg_data(nlh);
1809a14a49d2SThomas Graf 	if (ndm->ndm_ifindex) {
1810110b2499SEric Dumazet 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
1811a14a49d2SThomas Graf 		if (dev == NULL) {
1812a14a49d2SThomas Graf 			err = -ENODEV;
1813a14a49d2SThomas Graf 			goto out;
1814a14a49d2SThomas Graf 		}
1815a14a49d2SThomas Graf 	}
1816a14a49d2SThomas Graf 
1817d7480fd3SWANG Cong 	tbl = neigh_find_table(ndm->ndm_family);
1818d7480fd3SWANG Cong 	if (tbl == NULL)
1819d7480fd3SWANG Cong 		return -EAFNOSUPPORT;
18201da177e4SLinus Torvalds 
18217a35a50dSDavid Ahern 	if (nla_len(dst_attr) < (int)tbl->key_len) {
18227a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid network address");
1823110b2499SEric Dumazet 		goto out;
18247a35a50dSDavid Ahern 	}
18251da177e4SLinus Torvalds 
18261da177e4SLinus Torvalds 	if (ndm->ndm_flags & NTF_PROXY) {
1827426b5303SEric W. Biederman 		err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
1828110b2499SEric Dumazet 		goto out;
18291da177e4SLinus Torvalds 	}
18301da177e4SLinus Torvalds 
1831a14a49d2SThomas Graf 	if (dev == NULL)
1832110b2499SEric Dumazet 		goto out;
18331da177e4SLinus Torvalds 
1834a14a49d2SThomas Graf 	neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1835a14a49d2SThomas Graf 	if (neigh == NULL) {
1836a14a49d2SThomas Graf 		err = -ENOENT;
1837110b2499SEric Dumazet 		goto out;
1838a14a49d2SThomas Graf 	}
1839a14a49d2SThomas Graf 
18407a35a50dSDavid Ahern 	err = __neigh_update(neigh, NULL, NUD_FAILED,
18417a35a50dSDavid Ahern 			     NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN,
18427a35a50dSDavid Ahern 			     NETLINK_CB(skb).portid, extack);
18435071034eSSowmini Varadhan 	write_lock_bh(&tbl->lock);
1844a14a49d2SThomas Graf 	neigh_release(neigh);
18455071034eSSowmini Varadhan 	neigh_remove_one(neigh, tbl);
18465071034eSSowmini Varadhan 	write_unlock_bh(&tbl->lock);
1847a14a49d2SThomas Graf 
18481da177e4SLinus Torvalds out:
18491da177e4SLinus Torvalds 	return err;
18501da177e4SLinus Torvalds }
18511da177e4SLinus Torvalds 
1852c21ef3e3SDavid Ahern static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
1853c21ef3e3SDavid Ahern 		     struct netlink_ext_ack *extack)
18541da177e4SLinus Torvalds {
1855f7aa74e4SRoopa Prabhu 	int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE |
1856f7aa74e4SRoopa Prabhu 		NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
18573b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
18585208debdSThomas Graf 	struct ndmsg *ndm;
18595208debdSThomas Graf 	struct nlattr *tb[NDA_MAX+1];
18601da177e4SLinus Torvalds 	struct neigh_table *tbl;
18611da177e4SLinus Torvalds 	struct net_device *dev = NULL;
1862d7480fd3SWANG Cong 	struct neighbour *neigh;
1863d7480fd3SWANG Cong 	void *dst, *lladdr;
1864df9b0e30SDavid Ahern 	u8 protocol = 0;
18655208debdSThomas Graf 	int err;
18661da177e4SLinus Torvalds 
1867110b2499SEric Dumazet 	ASSERT_RTNL();
18688cb08174SJohannes Berg 	err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX,
18698cb08174SJohannes Berg 				     nda_policy, extack);
18705208debdSThomas Graf 	if (err < 0)
18711da177e4SLinus Torvalds 		goto out;
18721da177e4SLinus Torvalds 
18735208debdSThomas Graf 	err = -EINVAL;
18747a35a50dSDavid Ahern 	if (!tb[NDA_DST]) {
18757a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Network address not specified");
18765208debdSThomas Graf 		goto out;
18777a35a50dSDavid Ahern 	}
18785208debdSThomas Graf 
18795208debdSThomas Graf 	ndm = nlmsg_data(nlh);
18805208debdSThomas Graf 	if (ndm->ndm_ifindex) {
1881110b2499SEric Dumazet 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
18825208debdSThomas Graf 		if (dev == NULL) {
18835208debdSThomas Graf 			err = -ENODEV;
18845208debdSThomas Graf 			goto out;
18855208debdSThomas Graf 		}
18865208debdSThomas Graf 
18877a35a50dSDavid Ahern 		if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) {
18887a35a50dSDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid link address");
1889110b2499SEric Dumazet 			goto out;
18905208debdSThomas Graf 		}
18917a35a50dSDavid Ahern 	}
18925208debdSThomas Graf 
1893d7480fd3SWANG Cong 	tbl = neigh_find_table(ndm->ndm_family);
1894d7480fd3SWANG Cong 	if (tbl == NULL)
1895d7480fd3SWANG Cong 		return -EAFNOSUPPORT;
18961da177e4SLinus Torvalds 
18977a35a50dSDavid Ahern 	if (nla_len(tb[NDA_DST]) < (int)tbl->key_len) {
18987a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid network address");
1899110b2499SEric Dumazet 		goto out;
19007a35a50dSDavid Ahern 	}
19017a35a50dSDavid Ahern 
19025208debdSThomas Graf 	dst = nla_data(tb[NDA_DST]);
19035208debdSThomas Graf 	lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
19041da177e4SLinus Torvalds 
1905a9cd3439SDavid Ahern 	if (tb[NDA_PROTOCOL])
1906df9b0e30SDavid Ahern 		protocol = nla_get_u8(tb[NDA_PROTOCOL]);
1907df9b0e30SDavid Ahern 
19081da177e4SLinus Torvalds 	if (ndm->ndm_flags & NTF_PROXY) {
190962dd9318SVille Nuorvala 		struct pneigh_entry *pn;
191062dd9318SVille Nuorvala 
19115208debdSThomas Graf 		err = -ENOBUFS;
1912426b5303SEric W. Biederman 		pn = pneigh_lookup(tbl, net, dst, dev, 1);
191362dd9318SVille Nuorvala 		if (pn) {
191462dd9318SVille Nuorvala 			pn->flags = ndm->ndm_flags;
1915df9b0e30SDavid Ahern 			if (protocol)
1916df9b0e30SDavid Ahern 				pn->protocol = protocol;
191762dd9318SVille Nuorvala 			err = 0;
191862dd9318SVille Nuorvala 		}
1919110b2499SEric Dumazet 		goto out;
19201da177e4SLinus Torvalds 	}
19211da177e4SLinus Torvalds 
19227a35a50dSDavid Ahern 	if (!dev) {
19237a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Device not specified");
1924110b2499SEric Dumazet 		goto out;
19257a35a50dSDavid Ahern 	}
19261da177e4SLinus Torvalds 
1927b8fb1ab4SDavid Ahern 	if (tbl->allow_add && !tbl->allow_add(dev, extack)) {
1928b8fb1ab4SDavid Ahern 		err = -EINVAL;
1929b8fb1ab4SDavid Ahern 		goto out;
1930b8fb1ab4SDavid Ahern 	}
1931b8fb1ab4SDavid Ahern 
19325208debdSThomas Graf 	neigh = neigh_lookup(tbl, dst, dev);
19335208debdSThomas Graf 	if (neigh == NULL) {
1934e997f8a2SDavid Ahern 		bool exempt_from_gc;
1935e997f8a2SDavid Ahern 
19365208debdSThomas Graf 		if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
19371da177e4SLinus Torvalds 			err = -ENOENT;
1938110b2499SEric Dumazet 			goto out;
19395208debdSThomas Graf 		}
19405208debdSThomas Graf 
1941e997f8a2SDavid Ahern 		exempt_from_gc = ndm->ndm_state & NUD_PERMANENT ||
1942e997f8a2SDavid Ahern 				 ndm->ndm_flags & NTF_EXT_LEARNED;
1943e997f8a2SDavid Ahern 		neigh = ___neigh_create(tbl, dst, dev, exempt_from_gc, true);
19445208debdSThomas Graf 		if (IS_ERR(neigh)) {
19455208debdSThomas Graf 			err = PTR_ERR(neigh);
1946110b2499SEric Dumazet 			goto out;
19471da177e4SLinus Torvalds 		}
19485208debdSThomas Graf 	} else {
19495208debdSThomas Graf 		if (nlh->nlmsg_flags & NLM_F_EXCL) {
19505208debdSThomas Graf 			err = -EEXIST;
19515208debdSThomas Graf 			neigh_release(neigh);
1952110b2499SEric Dumazet 			goto out;
19531da177e4SLinus Torvalds 		}
19541da177e4SLinus Torvalds 
19555208debdSThomas Graf 		if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
1956f7aa74e4SRoopa Prabhu 			flags &= ~(NEIGH_UPDATE_F_OVERRIDE |
1957f7aa74e4SRoopa Prabhu 				   NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
19585208debdSThomas Graf 	}
19591da177e4SLinus Torvalds 
19609ce33e46SRoopa Prabhu 	if (ndm->ndm_flags & NTF_EXT_LEARNED)
19619ce33e46SRoopa Prabhu 		flags |= NEIGH_UPDATE_F_EXT_LEARNED;
19629ce33e46SRoopa Prabhu 
1963f7aa74e4SRoopa Prabhu 	if (ndm->ndm_flags & NTF_ROUTER)
1964f7aa74e4SRoopa Prabhu 		flags |= NEIGH_UPDATE_F_ISROUTER;
1965f7aa74e4SRoopa Prabhu 
19660c5c2d30SEric Biederman 	if (ndm->ndm_flags & NTF_USE) {
19670c5c2d30SEric Biederman 		neigh_event_send(neigh, NULL);
19680c5c2d30SEric Biederman 		err = 0;
19690c5c2d30SEric Biederman 	} else
19707a35a50dSDavid Ahern 		err = __neigh_update(neigh, lladdr, ndm->ndm_state, flags,
19717a35a50dSDavid Ahern 				     NETLINK_CB(skb).portid, extack);
1972df9b0e30SDavid Ahern 
1973df9b0e30SDavid Ahern 	if (protocol)
1974df9b0e30SDavid Ahern 		neigh->protocol = protocol;
1975df9b0e30SDavid Ahern 
19765208debdSThomas Graf 	neigh_release(neigh);
19771da177e4SLinus Torvalds 
19781da177e4SLinus Torvalds out:
19791da177e4SLinus Torvalds 	return err;
19801da177e4SLinus Torvalds }
19811da177e4SLinus Torvalds 
1982c7fb64dbSThomas Graf static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
1983c7fb64dbSThomas Graf {
1984ca860fb3SThomas Graf 	struct nlattr *nest;
1985e386c6ebSThomas Graf 
1986ae0be8deSMichal Kubecek 	nest = nla_nest_start_noflag(skb, NDTA_PARMS);
1987ca860fb3SThomas Graf 	if (nest == NULL)
1988ca860fb3SThomas Graf 		return -ENOBUFS;
1989c7fb64dbSThomas Graf 
19909a6308d7SDavid S. Miller 	if ((parms->dev &&
19919a6308d7SDavid S. Miller 	     nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
19926343944bSReshetova, Elena 	    nla_put_u32(skb, NDTPA_REFCNT, refcount_read(&parms->refcnt)) ||
19931f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_QUEUE_LENBYTES,
19941f9248e5SJiri Pirko 			NEIGH_VAR(parms, QUEUE_LEN_BYTES)) ||
19958b5c171bSEric Dumazet 	    /* approximative value for deprecated QUEUE_LEN (in packets) */
19969a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTPA_QUEUE_LEN,
19971f9248e5SJiri Pirko 			NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) ||
19981f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) ||
19991f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) ||
20001f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_UCAST_PROBES,
20011f9248e5SJiri Pirko 			NEIGH_VAR(parms, UCAST_PROBES)) ||
20021f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_MCAST_PROBES,
20031f9248e5SJiri Pirko 			NEIGH_VAR(parms, MCAST_PROBES)) ||
20048da86466SYOSHIFUJI Hideaki/吉藤英明 	    nla_put_u32(skb, NDTPA_MCAST_REPROBES,
20058da86466SYOSHIFUJI Hideaki/吉藤英明 			NEIGH_VAR(parms, MCAST_REPROBES)) ||
20062175d87cSNicolas Dichtel 	    nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time,
20072175d87cSNicolas Dichtel 			  NDTPA_PAD) ||
20089a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
20092175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, BASE_REACHABLE_TIME), NDTPA_PAD) ||
20101f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_GC_STALETIME,
20112175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, GC_STALETIME), NDTPA_PAD) ||
20129a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
20132175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, DELAY_PROBE_TIME), NDTPA_PAD) ||
20141f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_RETRANS_TIME,
20152175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, RETRANS_TIME), NDTPA_PAD) ||
20161f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_ANYCAST_DELAY,
20172175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, ANYCAST_DELAY), NDTPA_PAD) ||
20181f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_PROXY_DELAY,
20192175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, PROXY_DELAY), NDTPA_PAD) ||
20201f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_LOCKTIME,
20212175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, LOCKTIME), NDTPA_PAD))
20229a6308d7SDavid S. Miller 		goto nla_put_failure;
2023ca860fb3SThomas Graf 	return nla_nest_end(skb, nest);
2024c7fb64dbSThomas Graf 
2025ca860fb3SThomas Graf nla_put_failure:
2026bc3ed28cSThomas Graf 	nla_nest_cancel(skb, nest);
2027bc3ed28cSThomas Graf 	return -EMSGSIZE;
2028c7fb64dbSThomas Graf }
2029c7fb64dbSThomas Graf 
2030ca860fb3SThomas Graf static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
2031ca860fb3SThomas Graf 			      u32 pid, u32 seq, int type, int flags)
2032c7fb64dbSThomas Graf {
2033c7fb64dbSThomas Graf 	struct nlmsghdr *nlh;
2034c7fb64dbSThomas Graf 	struct ndtmsg *ndtmsg;
2035c7fb64dbSThomas Graf 
2036ca860fb3SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2037ca860fb3SThomas Graf 	if (nlh == NULL)
203826932566SPatrick McHardy 		return -EMSGSIZE;
2039c7fb64dbSThomas Graf 
2040ca860fb3SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2041c7fb64dbSThomas Graf 
2042c7fb64dbSThomas Graf 	read_lock_bh(&tbl->lock);
2043c7fb64dbSThomas Graf 	ndtmsg->ndtm_family = tbl->family;
20449ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad1   = 0;
20459ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad2   = 0;
2046c7fb64dbSThomas Graf 
20479a6308d7SDavid S. Miller 	if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
20482175d87cSNicolas Dichtel 	    nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval, NDTA_PAD) ||
20499a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
20509a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
20519a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
20529a6308d7SDavid S. Miller 		goto nla_put_failure;
2053c7fb64dbSThomas Graf 	{
2054c7fb64dbSThomas Graf 		unsigned long now = jiffies;
20559d027e3aSEric Dumazet 		long flush_delta = now - tbl->last_flush;
20569d027e3aSEric Dumazet 		long rand_delta = now - tbl->last_rand;
2057d6bf7817SEric Dumazet 		struct neigh_hash_table *nht;
2058c7fb64dbSThomas Graf 		struct ndt_config ndc = {
2059c7fb64dbSThomas Graf 			.ndtc_key_len		= tbl->key_len,
2060c7fb64dbSThomas Graf 			.ndtc_entry_size	= tbl->entry_size,
2061c7fb64dbSThomas Graf 			.ndtc_entries		= atomic_read(&tbl->entries),
2062c7fb64dbSThomas Graf 			.ndtc_last_flush	= jiffies_to_msecs(flush_delta),
2063c7fb64dbSThomas Graf 			.ndtc_last_rand		= jiffies_to_msecs(rand_delta),
2064c7fb64dbSThomas Graf 			.ndtc_proxy_qlen	= tbl->proxy_queue.qlen,
2065c7fb64dbSThomas Graf 		};
2066c7fb64dbSThomas Graf 
2067d6bf7817SEric Dumazet 		rcu_read_lock_bh();
2068d6bf7817SEric Dumazet 		nht = rcu_dereference_bh(tbl->nht);
20692c2aba6cSDavid S. Miller 		ndc.ndtc_hash_rnd = nht->hash_rnd[0];
2070cd089336SDavid S. Miller 		ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
2071d6bf7817SEric Dumazet 		rcu_read_unlock_bh();
2072d6bf7817SEric Dumazet 
20739a6308d7SDavid S. Miller 		if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
20749a6308d7SDavid S. Miller 			goto nla_put_failure;
2075c7fb64dbSThomas Graf 	}
2076c7fb64dbSThomas Graf 
2077c7fb64dbSThomas Graf 	{
2078c7fb64dbSThomas Graf 		int cpu;
2079c7fb64dbSThomas Graf 		struct ndt_stats ndst;
2080c7fb64dbSThomas Graf 
2081c7fb64dbSThomas Graf 		memset(&ndst, 0, sizeof(ndst));
2082c7fb64dbSThomas Graf 
20836f912042SKAMEZAWA Hiroyuki 		for_each_possible_cpu(cpu) {
2084c7fb64dbSThomas Graf 			struct neigh_statistics	*st;
2085c7fb64dbSThomas Graf 
2086c7fb64dbSThomas Graf 			st = per_cpu_ptr(tbl->stats, cpu);
2087c7fb64dbSThomas Graf 			ndst.ndts_allocs		+= st->allocs;
2088c7fb64dbSThomas Graf 			ndst.ndts_destroys		+= st->destroys;
2089c7fb64dbSThomas Graf 			ndst.ndts_hash_grows		+= st->hash_grows;
2090c7fb64dbSThomas Graf 			ndst.ndts_res_failed		+= st->res_failed;
2091c7fb64dbSThomas Graf 			ndst.ndts_lookups		+= st->lookups;
2092c7fb64dbSThomas Graf 			ndst.ndts_hits			+= st->hits;
2093c7fb64dbSThomas Graf 			ndst.ndts_rcv_probes_mcast	+= st->rcv_probes_mcast;
2094c7fb64dbSThomas Graf 			ndst.ndts_rcv_probes_ucast	+= st->rcv_probes_ucast;
2095c7fb64dbSThomas Graf 			ndst.ndts_periodic_gc_runs	+= st->periodic_gc_runs;
2096c7fb64dbSThomas Graf 			ndst.ndts_forced_gc_runs	+= st->forced_gc_runs;
2097fb811395SRick Jones 			ndst.ndts_table_fulls		+= st->table_fulls;
2098c7fb64dbSThomas Graf 		}
2099c7fb64dbSThomas Graf 
2100b676338fSNicolas Dichtel 		if (nla_put_64bit(skb, NDTA_STATS, sizeof(ndst), &ndst,
2101b676338fSNicolas Dichtel 				  NDTA_PAD))
21029a6308d7SDavid S. Miller 			goto nla_put_failure;
2103c7fb64dbSThomas Graf 	}
2104c7fb64dbSThomas Graf 
2105c7fb64dbSThomas Graf 	BUG_ON(tbl->parms.dev);
2106c7fb64dbSThomas Graf 	if (neightbl_fill_parms(skb, &tbl->parms) < 0)
2107ca860fb3SThomas Graf 		goto nla_put_failure;
2108c7fb64dbSThomas Graf 
2109c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
2110053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2111053c095aSJohannes Berg 	return 0;
2112c7fb64dbSThomas Graf 
2113ca860fb3SThomas Graf nla_put_failure:
2114c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
211526932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
211626932566SPatrick McHardy 	return -EMSGSIZE;
2117c7fb64dbSThomas Graf }
2118c7fb64dbSThomas Graf 
2119ca860fb3SThomas Graf static int neightbl_fill_param_info(struct sk_buff *skb,
2120ca860fb3SThomas Graf 				    struct neigh_table *tbl,
2121c7fb64dbSThomas Graf 				    struct neigh_parms *parms,
2122ca860fb3SThomas Graf 				    u32 pid, u32 seq, int type,
2123ca860fb3SThomas Graf 				    unsigned int flags)
2124c7fb64dbSThomas Graf {
2125c7fb64dbSThomas Graf 	struct ndtmsg *ndtmsg;
2126c7fb64dbSThomas Graf 	struct nlmsghdr *nlh;
2127c7fb64dbSThomas Graf 
2128ca860fb3SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2129ca860fb3SThomas Graf 	if (nlh == NULL)
213026932566SPatrick McHardy 		return -EMSGSIZE;
2131c7fb64dbSThomas Graf 
2132ca860fb3SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2133c7fb64dbSThomas Graf 
2134c7fb64dbSThomas Graf 	read_lock_bh(&tbl->lock);
2135c7fb64dbSThomas Graf 	ndtmsg->ndtm_family = tbl->family;
21369ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad1   = 0;
21379ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad2   = 0;
2138c7fb64dbSThomas Graf 
2139ca860fb3SThomas Graf 	if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
2140ca860fb3SThomas Graf 	    neightbl_fill_parms(skb, parms) < 0)
2141ca860fb3SThomas Graf 		goto errout;
2142c7fb64dbSThomas Graf 
2143c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
2144053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2145053c095aSJohannes Berg 	return 0;
2146ca860fb3SThomas Graf errout:
2147c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
214826932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
214926932566SPatrick McHardy 	return -EMSGSIZE;
2150c7fb64dbSThomas Graf }
2151c7fb64dbSThomas Graf 
2152ef7c79edSPatrick McHardy static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
21536b3f8674SThomas Graf 	[NDTA_NAME]		= { .type = NLA_STRING },
21546b3f8674SThomas Graf 	[NDTA_THRESH1]		= { .type = NLA_U32 },
21556b3f8674SThomas Graf 	[NDTA_THRESH2]		= { .type = NLA_U32 },
21566b3f8674SThomas Graf 	[NDTA_THRESH3]		= { .type = NLA_U32 },
21576b3f8674SThomas Graf 	[NDTA_GC_INTERVAL]	= { .type = NLA_U64 },
21586b3f8674SThomas Graf 	[NDTA_PARMS]		= { .type = NLA_NESTED },
21596b3f8674SThomas Graf };
21606b3f8674SThomas Graf 
2161ef7c79edSPatrick McHardy static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
21626b3f8674SThomas Graf 	[NDTPA_IFINDEX]			= { .type = NLA_U32 },
21636b3f8674SThomas Graf 	[NDTPA_QUEUE_LEN]		= { .type = NLA_U32 },
21646b3f8674SThomas Graf 	[NDTPA_PROXY_QLEN]		= { .type = NLA_U32 },
21656b3f8674SThomas Graf 	[NDTPA_APP_PROBES]		= { .type = NLA_U32 },
21666b3f8674SThomas Graf 	[NDTPA_UCAST_PROBES]		= { .type = NLA_U32 },
21676b3f8674SThomas Graf 	[NDTPA_MCAST_PROBES]		= { .type = NLA_U32 },
21688da86466SYOSHIFUJI Hideaki/吉藤英明 	[NDTPA_MCAST_REPROBES]		= { .type = NLA_U32 },
21696b3f8674SThomas Graf 	[NDTPA_BASE_REACHABLE_TIME]	= { .type = NLA_U64 },
21706b3f8674SThomas Graf 	[NDTPA_GC_STALETIME]		= { .type = NLA_U64 },
21716b3f8674SThomas Graf 	[NDTPA_DELAY_PROBE_TIME]	= { .type = NLA_U64 },
21726b3f8674SThomas Graf 	[NDTPA_RETRANS_TIME]		= { .type = NLA_U64 },
21736b3f8674SThomas Graf 	[NDTPA_ANYCAST_DELAY]		= { .type = NLA_U64 },
21746b3f8674SThomas Graf 	[NDTPA_PROXY_DELAY]		= { .type = NLA_U64 },
21756b3f8674SThomas Graf 	[NDTPA_LOCKTIME]		= { .type = NLA_U64 },
21766b3f8674SThomas Graf };
21776b3f8674SThomas Graf 
2178c21ef3e3SDavid Ahern static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
2179c21ef3e3SDavid Ahern 			struct netlink_ext_ack *extack)
2180c7fb64dbSThomas Graf {
21813b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
2182c7fb64dbSThomas Graf 	struct neigh_table *tbl;
21836b3f8674SThomas Graf 	struct ndtmsg *ndtmsg;
21846b3f8674SThomas Graf 	struct nlattr *tb[NDTA_MAX+1];
2185d7480fd3SWANG Cong 	bool found = false;
2186d7480fd3SWANG Cong 	int err, tidx;
2187c7fb64dbSThomas Graf 
21888cb08174SJohannes Berg 	err = nlmsg_parse_deprecated(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
2189c21ef3e3SDavid Ahern 				     nl_neightbl_policy, extack);
21906b3f8674SThomas Graf 	if (err < 0)
21916b3f8674SThomas Graf 		goto errout;
2192c7fb64dbSThomas Graf 
21936b3f8674SThomas Graf 	if (tb[NDTA_NAME] == NULL) {
21946b3f8674SThomas Graf 		err = -EINVAL;
21956b3f8674SThomas Graf 		goto errout;
21966b3f8674SThomas Graf 	}
21976b3f8674SThomas Graf 
21986b3f8674SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2199d7480fd3SWANG Cong 
2200d7480fd3SWANG Cong 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2201d7480fd3SWANG Cong 		tbl = neigh_tables[tidx];
2202d7480fd3SWANG Cong 		if (!tbl)
2203d7480fd3SWANG Cong 			continue;
2204c7fb64dbSThomas Graf 		if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
2205c7fb64dbSThomas Graf 			continue;
2206d7480fd3SWANG Cong 		if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) {
2207d7480fd3SWANG Cong 			found = true;
2208c7fb64dbSThomas Graf 			break;
2209c7fb64dbSThomas Graf 		}
2210c7fb64dbSThomas Graf 	}
2211c7fb64dbSThomas Graf 
2212d7480fd3SWANG Cong 	if (!found)
2213d7480fd3SWANG Cong 		return -ENOENT;
2214d7480fd3SWANG Cong 
2215c7fb64dbSThomas Graf 	/*
2216c7fb64dbSThomas Graf 	 * We acquire tbl->lock to be nice to the periodic timers and
2217c7fb64dbSThomas Graf 	 * make sure they always see a consistent set of values.
2218c7fb64dbSThomas Graf 	 */
2219c7fb64dbSThomas Graf 	write_lock_bh(&tbl->lock);
2220c7fb64dbSThomas Graf 
22216b3f8674SThomas Graf 	if (tb[NDTA_PARMS]) {
22226b3f8674SThomas Graf 		struct nlattr *tbp[NDTPA_MAX+1];
2223c7fb64dbSThomas Graf 		struct neigh_parms *p;
22246b3f8674SThomas Graf 		int i, ifindex = 0;
2225c7fb64dbSThomas Graf 
22268cb08174SJohannes Berg 		err = nla_parse_nested_deprecated(tbp, NDTPA_MAX,
22278cb08174SJohannes Berg 						  tb[NDTA_PARMS],
2228c21ef3e3SDavid Ahern 						  nl_ntbl_parm_policy, extack);
22296b3f8674SThomas Graf 		if (err < 0)
22306b3f8674SThomas Graf 			goto errout_tbl_lock;
2231c7fb64dbSThomas Graf 
22326b3f8674SThomas Graf 		if (tbp[NDTPA_IFINDEX])
22336b3f8674SThomas Graf 			ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
2234c7fb64dbSThomas Graf 
223597fd5bc7STobias Klauser 		p = lookup_neigh_parms(tbl, net, ifindex);
2236c7fb64dbSThomas Graf 		if (p == NULL) {
2237c7fb64dbSThomas Graf 			err = -ENOENT;
22386b3f8674SThomas Graf 			goto errout_tbl_lock;
2239c7fb64dbSThomas Graf 		}
2240c7fb64dbSThomas Graf 
22416b3f8674SThomas Graf 		for (i = 1; i <= NDTPA_MAX; i++) {
22426b3f8674SThomas Graf 			if (tbp[i] == NULL)
22436b3f8674SThomas Graf 				continue;
2244c7fb64dbSThomas Graf 
22456b3f8674SThomas Graf 			switch (i) {
22466b3f8674SThomas Graf 			case NDTPA_QUEUE_LEN:
22471f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
22481f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]) *
22491f9248e5SJiri Pirko 					      SKB_TRUESIZE(ETH_FRAME_LEN));
22508b5c171bSEric Dumazet 				break;
22518b5c171bSEric Dumazet 			case NDTPA_QUEUE_LENBYTES:
22521f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
22531f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
22546b3f8674SThomas Graf 				break;
22556b3f8674SThomas Graf 			case NDTPA_PROXY_QLEN:
22561f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, PROXY_QLEN,
22571f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
22586b3f8674SThomas Graf 				break;
22596b3f8674SThomas Graf 			case NDTPA_APP_PROBES:
22601f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, APP_PROBES,
22611f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
22626b3f8674SThomas Graf 				break;
22636b3f8674SThomas Graf 			case NDTPA_UCAST_PROBES:
22641f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, UCAST_PROBES,
22651f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
22666b3f8674SThomas Graf 				break;
22676b3f8674SThomas Graf 			case NDTPA_MCAST_PROBES:
22681f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, MCAST_PROBES,
22691f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
22706b3f8674SThomas Graf 				break;
22718da86466SYOSHIFUJI Hideaki/吉藤英明 			case NDTPA_MCAST_REPROBES:
22728da86466SYOSHIFUJI Hideaki/吉藤英明 				NEIGH_VAR_SET(p, MCAST_REPROBES,
22738da86466SYOSHIFUJI Hideaki/吉藤英明 					      nla_get_u32(tbp[i]));
22748da86466SYOSHIFUJI Hideaki/吉藤英明 				break;
22756b3f8674SThomas Graf 			case NDTPA_BASE_REACHABLE_TIME:
22761f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,
22771f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
22784bf6980dSJean-Francois Remy 				/* update reachable_time as well, otherwise, the change will
22794bf6980dSJean-Francois Remy 				 * only be effective after the next time neigh_periodic_work
22804bf6980dSJean-Francois Remy 				 * decides to recompute it (can be multiple minutes)
22814bf6980dSJean-Francois Remy 				 */
22824bf6980dSJean-Francois Remy 				p->reachable_time =
22834bf6980dSJean-Francois Remy 					neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
22846b3f8674SThomas Graf 				break;
22856b3f8674SThomas Graf 			case NDTPA_GC_STALETIME:
22861f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, GC_STALETIME,
22871f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
22886b3f8674SThomas Graf 				break;
22896b3f8674SThomas Graf 			case NDTPA_DELAY_PROBE_TIME:
22901f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, DELAY_PROBE_TIME,
22911f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
22922a4501aeSIdo Schimmel 				call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
22936b3f8674SThomas Graf 				break;
22946b3f8674SThomas Graf 			case NDTPA_RETRANS_TIME:
22951f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, RETRANS_TIME,
22961f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
22976b3f8674SThomas Graf 				break;
22986b3f8674SThomas Graf 			case NDTPA_ANYCAST_DELAY:
22993977458cSJiri Pirko 				NEIGH_VAR_SET(p, ANYCAST_DELAY,
23003977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
23016b3f8674SThomas Graf 				break;
23026b3f8674SThomas Graf 			case NDTPA_PROXY_DELAY:
23033977458cSJiri Pirko 				NEIGH_VAR_SET(p, PROXY_DELAY,
23043977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
23056b3f8674SThomas Graf 				break;
23066b3f8674SThomas Graf 			case NDTPA_LOCKTIME:
23073977458cSJiri Pirko 				NEIGH_VAR_SET(p, LOCKTIME,
23083977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
23096b3f8674SThomas Graf 				break;
2310c7fb64dbSThomas Graf 			}
23116b3f8674SThomas Graf 		}
23126b3f8674SThomas Graf 	}
23136b3f8674SThomas Graf 
2314dc25c676SGao feng 	err = -ENOENT;
2315dc25c676SGao feng 	if ((tb[NDTA_THRESH1] || tb[NDTA_THRESH2] ||
2316dc25c676SGao feng 	     tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]) &&
2317dc25c676SGao feng 	    !net_eq(net, &init_net))
2318dc25c676SGao feng 		goto errout_tbl_lock;
2319dc25c676SGao feng 
23206b3f8674SThomas Graf 	if (tb[NDTA_THRESH1])
23216b3f8674SThomas Graf 		tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
23226b3f8674SThomas Graf 
23236b3f8674SThomas Graf 	if (tb[NDTA_THRESH2])
23246b3f8674SThomas Graf 		tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
23256b3f8674SThomas Graf 
23266b3f8674SThomas Graf 	if (tb[NDTA_THRESH3])
23276b3f8674SThomas Graf 		tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
23286b3f8674SThomas Graf 
23296b3f8674SThomas Graf 	if (tb[NDTA_GC_INTERVAL])
23306b3f8674SThomas Graf 		tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2331c7fb64dbSThomas Graf 
2332c7fb64dbSThomas Graf 	err = 0;
2333c7fb64dbSThomas Graf 
23346b3f8674SThomas Graf errout_tbl_lock:
2335c7fb64dbSThomas Graf 	write_unlock_bh(&tbl->lock);
23366b3f8674SThomas Graf errout:
2337c7fb64dbSThomas Graf 	return err;
2338c7fb64dbSThomas Graf }
2339c7fb64dbSThomas Graf 
23409632d47fSDavid Ahern static int neightbl_valid_dump_info(const struct nlmsghdr *nlh,
23419632d47fSDavid Ahern 				    struct netlink_ext_ack *extack)
23429632d47fSDavid Ahern {
23439632d47fSDavid Ahern 	struct ndtmsg *ndtm;
23449632d47fSDavid Ahern 
23459632d47fSDavid Ahern 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndtm))) {
23469632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid header for neighbor table dump request");
23479632d47fSDavid Ahern 		return -EINVAL;
23489632d47fSDavid Ahern 	}
23499632d47fSDavid Ahern 
23509632d47fSDavid Ahern 	ndtm = nlmsg_data(nlh);
23519632d47fSDavid Ahern 	if (ndtm->ndtm_pad1  || ndtm->ndtm_pad2) {
23529632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor table dump request");
23539632d47fSDavid Ahern 		return -EINVAL;
23549632d47fSDavid Ahern 	}
23559632d47fSDavid Ahern 
23569632d47fSDavid Ahern 	if (nlmsg_attrlen(nlh, sizeof(*ndtm))) {
23579632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid data after header in neighbor table dump request");
23589632d47fSDavid Ahern 		return -EINVAL;
23599632d47fSDavid Ahern 	}
23609632d47fSDavid Ahern 
23619632d47fSDavid Ahern 	return 0;
23629632d47fSDavid Ahern }
23639632d47fSDavid Ahern 
2364c8822a4eSThomas Graf static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
2365c7fb64dbSThomas Graf {
23669632d47fSDavid Ahern 	const struct nlmsghdr *nlh = cb->nlh;
23673b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
2368ca860fb3SThomas Graf 	int family, tidx, nidx = 0;
2369ca860fb3SThomas Graf 	int tbl_skip = cb->args[0];
2370ca860fb3SThomas Graf 	int neigh_skip = cb->args[1];
2371c7fb64dbSThomas Graf 	struct neigh_table *tbl;
2372c7fb64dbSThomas Graf 
23739632d47fSDavid Ahern 	if (cb->strict_check) {
23749632d47fSDavid Ahern 		int err = neightbl_valid_dump_info(nlh, cb->extack);
23759632d47fSDavid Ahern 
23769632d47fSDavid Ahern 		if (err < 0)
23779632d47fSDavid Ahern 			return err;
23789632d47fSDavid Ahern 	}
23799632d47fSDavid Ahern 
23809632d47fSDavid Ahern 	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
2381c7fb64dbSThomas Graf 
2382d7480fd3SWANG Cong 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2383c7fb64dbSThomas Graf 		struct neigh_parms *p;
2384c7fb64dbSThomas Graf 
2385d7480fd3SWANG Cong 		tbl = neigh_tables[tidx];
2386d7480fd3SWANG Cong 		if (!tbl)
2387d7480fd3SWANG Cong 			continue;
2388d7480fd3SWANG Cong 
2389ca860fb3SThomas Graf 		if (tidx < tbl_skip || (family && tbl->family != family))
2390c7fb64dbSThomas Graf 			continue;
2391c7fb64dbSThomas Graf 
239215e47304SEric W. Biederman 		if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
23939632d47fSDavid Ahern 				       nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
23947b46a644SDavid S. Miller 				       NLM_F_MULTI) < 0)
2395c7fb64dbSThomas Graf 			break;
2396c7fb64dbSThomas Graf 
239775fbfd33SNicolas Dichtel 		nidx = 0;
239875fbfd33SNicolas Dichtel 		p = list_next_entry(&tbl->parms, list);
239975fbfd33SNicolas Dichtel 		list_for_each_entry_from(p, &tbl->parms_list, list) {
2400878628fbSYOSHIFUJI Hideaki 			if (!net_eq(neigh_parms_net(p), net))
2401426b5303SEric W. Biederman 				continue;
2402426b5303SEric W. Biederman 
2403efc683fcSGautam Kachroo 			if (nidx < neigh_skip)
2404efc683fcSGautam Kachroo 				goto next;
2405c7fb64dbSThomas Graf 
2406ca860fb3SThomas Graf 			if (neightbl_fill_param_info(skb, tbl, p,
240715e47304SEric W. Biederman 						     NETLINK_CB(cb->skb).portid,
24089632d47fSDavid Ahern 						     nlh->nlmsg_seq,
2409ca860fb3SThomas Graf 						     RTM_NEWNEIGHTBL,
24107b46a644SDavid S. Miller 						     NLM_F_MULTI) < 0)
2411c7fb64dbSThomas Graf 				goto out;
2412efc683fcSGautam Kachroo 		next:
2413efc683fcSGautam Kachroo 			nidx++;
2414c7fb64dbSThomas Graf 		}
2415c7fb64dbSThomas Graf 
2416ca860fb3SThomas Graf 		neigh_skip = 0;
2417c7fb64dbSThomas Graf 	}
2418c7fb64dbSThomas Graf out:
2419ca860fb3SThomas Graf 	cb->args[0] = tidx;
2420ca860fb3SThomas Graf 	cb->args[1] = nidx;
2421c7fb64dbSThomas Graf 
2422c7fb64dbSThomas Graf 	return skb->len;
2423c7fb64dbSThomas Graf }
24241da177e4SLinus Torvalds 
24258b8aec50SThomas Graf static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
24268b8aec50SThomas Graf 			   u32 pid, u32 seq, int type, unsigned int flags)
24271da177e4SLinus Torvalds {
24281da177e4SLinus Torvalds 	unsigned long now = jiffies;
24291da177e4SLinus Torvalds 	struct nda_cacheinfo ci;
24308b8aec50SThomas Graf 	struct nlmsghdr *nlh;
24318b8aec50SThomas Graf 	struct ndmsg *ndm;
24321da177e4SLinus Torvalds 
24338b8aec50SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
24348b8aec50SThomas Graf 	if (nlh == NULL)
243526932566SPatrick McHardy 		return -EMSGSIZE;
24368b8aec50SThomas Graf 
24378b8aec50SThomas Graf 	ndm = nlmsg_data(nlh);
24388b8aec50SThomas Graf 	ndm->ndm_family	 = neigh->ops->family;
24399ef1d4c7SPatrick McHardy 	ndm->ndm_pad1    = 0;
24409ef1d4c7SPatrick McHardy 	ndm->ndm_pad2    = 0;
24418b8aec50SThomas Graf 	ndm->ndm_flags	 = neigh->flags;
24428b8aec50SThomas Graf 	ndm->ndm_type	 = neigh->type;
24438b8aec50SThomas Graf 	ndm->ndm_ifindex = neigh->dev->ifindex;
24441da177e4SLinus Torvalds 
24459a6308d7SDavid S. Miller 	if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
24469a6308d7SDavid S. Miller 		goto nla_put_failure;
24478b8aec50SThomas Graf 
24488b8aec50SThomas Graf 	read_lock_bh(&neigh->lock);
24498b8aec50SThomas Graf 	ndm->ndm_state	 = neigh->nud_state;
24500ed8ddf4SEric Dumazet 	if (neigh->nud_state & NUD_VALID) {
24510ed8ddf4SEric Dumazet 		char haddr[MAX_ADDR_LEN];
24520ed8ddf4SEric Dumazet 
24530ed8ddf4SEric Dumazet 		neigh_ha_snapshot(haddr, neigh, neigh->dev);
24540ed8ddf4SEric Dumazet 		if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
24558b8aec50SThomas Graf 			read_unlock_bh(&neigh->lock);
24568b8aec50SThomas Graf 			goto nla_put_failure;
24578b8aec50SThomas Graf 		}
24580ed8ddf4SEric Dumazet 	}
24598b8aec50SThomas Graf 
2460b9f5f52cSStephen Hemminger 	ci.ndm_used	 = jiffies_to_clock_t(now - neigh->used);
2461b9f5f52cSStephen Hemminger 	ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2462b9f5f52cSStephen Hemminger 	ci.ndm_updated	 = jiffies_to_clock_t(now - neigh->updated);
24639f237430SReshetova, Elena 	ci.ndm_refcnt	 = refcount_read(&neigh->refcnt) - 1;
24648b8aec50SThomas Graf 	read_unlock_bh(&neigh->lock);
24658b8aec50SThomas Graf 
24669a6308d7SDavid S. Miller 	if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
24679a6308d7SDavid S. Miller 	    nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
24689a6308d7SDavid S. Miller 		goto nla_put_failure;
24698b8aec50SThomas Graf 
2470df9b0e30SDavid Ahern 	if (neigh->protocol && nla_put_u8(skb, NDA_PROTOCOL, neigh->protocol))
2471df9b0e30SDavid Ahern 		goto nla_put_failure;
2472df9b0e30SDavid Ahern 
2473053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2474053c095aSJohannes Berg 	return 0;
24758b8aec50SThomas Graf 
24768b8aec50SThomas Graf nla_put_failure:
247726932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
247826932566SPatrick McHardy 	return -EMSGSIZE;
24791da177e4SLinus Torvalds }
24801da177e4SLinus Torvalds 
248184920c14STony Zelenoff static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
248284920c14STony Zelenoff 			    u32 pid, u32 seq, int type, unsigned int flags,
248384920c14STony Zelenoff 			    struct neigh_table *tbl)
248484920c14STony Zelenoff {
248584920c14STony Zelenoff 	struct nlmsghdr *nlh;
248684920c14STony Zelenoff 	struct ndmsg *ndm;
248784920c14STony Zelenoff 
248884920c14STony Zelenoff 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
248984920c14STony Zelenoff 	if (nlh == NULL)
249084920c14STony Zelenoff 		return -EMSGSIZE;
249184920c14STony Zelenoff 
249284920c14STony Zelenoff 	ndm = nlmsg_data(nlh);
249384920c14STony Zelenoff 	ndm->ndm_family	 = tbl->family;
249484920c14STony Zelenoff 	ndm->ndm_pad1    = 0;
249584920c14STony Zelenoff 	ndm->ndm_pad2    = 0;
249684920c14STony Zelenoff 	ndm->ndm_flags	 = pn->flags | NTF_PROXY;
2497545469f7SJun Zhao 	ndm->ndm_type	 = RTN_UNICAST;
24986adc5fd6SKonstantin Khlebnikov 	ndm->ndm_ifindex = pn->dev ? pn->dev->ifindex : 0;
249984920c14STony Zelenoff 	ndm->ndm_state	 = NUD_NONE;
250084920c14STony Zelenoff 
25019a6308d7SDavid S. Miller 	if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
25029a6308d7SDavid S. Miller 		goto nla_put_failure;
250384920c14STony Zelenoff 
2504df9b0e30SDavid Ahern 	if (pn->protocol && nla_put_u8(skb, NDA_PROTOCOL, pn->protocol))
2505df9b0e30SDavid Ahern 		goto nla_put_failure;
2506df9b0e30SDavid Ahern 
2507053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2508053c095aSJohannes Berg 	return 0;
250984920c14STony Zelenoff 
251084920c14STony Zelenoff nla_put_failure:
251184920c14STony Zelenoff 	nlmsg_cancel(skb, nlh);
251284920c14STony Zelenoff 	return -EMSGSIZE;
251384920c14STony Zelenoff }
251484920c14STony Zelenoff 
25157b8f7a40SRoopa Prabhu static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid)
2516d961db35SThomas Graf {
2517d961db35SThomas Graf 	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
25187b8f7a40SRoopa Prabhu 	__neigh_notify(neigh, RTM_NEWNEIGH, 0, nlmsg_pid);
2519d961db35SThomas Graf }
25201da177e4SLinus Torvalds 
252121fdd092SDavid Ahern static bool neigh_master_filtered(struct net_device *dev, int master_idx)
252221fdd092SDavid Ahern {
252321fdd092SDavid Ahern 	struct net_device *master;
252421fdd092SDavid Ahern 
252521fdd092SDavid Ahern 	if (!master_idx)
252621fdd092SDavid Ahern 		return false;
252721fdd092SDavid Ahern 
2528aab456dfSEric Dumazet 	master = dev ? netdev_master_upper_dev_get(dev) : NULL;
252921fdd092SDavid Ahern 	if (!master || master->ifindex != master_idx)
253021fdd092SDavid Ahern 		return true;
253121fdd092SDavid Ahern 
253221fdd092SDavid Ahern 	return false;
253321fdd092SDavid Ahern }
253421fdd092SDavid Ahern 
253516660f0bSDavid Ahern static bool neigh_ifindex_filtered(struct net_device *dev, int filter_idx)
253616660f0bSDavid Ahern {
2537aab456dfSEric Dumazet 	if (filter_idx && (!dev || dev->ifindex != filter_idx))
253816660f0bSDavid Ahern 		return true;
253916660f0bSDavid Ahern 
254016660f0bSDavid Ahern 	return false;
254116660f0bSDavid Ahern }
254216660f0bSDavid Ahern 
25436f52f80eSDavid Ahern struct neigh_dump_filter {
25446f52f80eSDavid Ahern 	int master_idx;
25456f52f80eSDavid Ahern 	int dev_idx;
25466f52f80eSDavid Ahern };
25476f52f80eSDavid Ahern 
25481da177e4SLinus Torvalds static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
25496f52f80eSDavid Ahern 			    struct netlink_callback *cb,
25506f52f80eSDavid Ahern 			    struct neigh_dump_filter *filter)
25511da177e4SLinus Torvalds {
25523b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
25531da177e4SLinus Torvalds 	struct neighbour *n;
25541da177e4SLinus Torvalds 	int rc, h, s_h = cb->args[1];
25551da177e4SLinus Torvalds 	int idx, s_idx = idx = cb->args[2];
2556d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
255721fdd092SDavid Ahern 	unsigned int flags = NLM_F_MULTI;
255821fdd092SDavid Ahern 
25596f52f80eSDavid Ahern 	if (filter->dev_idx || filter->master_idx)
256021fdd092SDavid Ahern 		flags |= NLM_F_DUMP_FILTERED;
25611da177e4SLinus Torvalds 
2562d6bf7817SEric Dumazet 	rcu_read_lock_bh();
2563d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
2564d6bf7817SEric Dumazet 
25654bd6683bSEric Dumazet 	for (h = s_h; h < (1 << nht->hash_shift); h++) {
25661da177e4SLinus Torvalds 		if (h > s_h)
25671da177e4SLinus Torvalds 			s_idx = 0;
2568767e97e1SEric Dumazet 		for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2569767e97e1SEric Dumazet 		     n != NULL;
2570767e97e1SEric Dumazet 		     n = rcu_dereference_bh(n->next)) {
257118502acdSZhang Shengju 			if (idx < s_idx || !net_eq(dev_net(n->dev), net))
257218502acdSZhang Shengju 				goto next;
25736f52f80eSDavid Ahern 			if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
25746f52f80eSDavid Ahern 			    neigh_master_filtered(n->dev, filter->master_idx))
2575efc683fcSGautam Kachroo 				goto next;
257615e47304SEric W. Biederman 			if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
25771da177e4SLinus Torvalds 					    cb->nlh->nlmsg_seq,
2578b6544c0bSJamal Hadi Salim 					    RTM_NEWNEIGH,
257921fdd092SDavid Ahern 					    flags) < 0) {
25801da177e4SLinus Torvalds 				rc = -1;
25811da177e4SLinus Torvalds 				goto out;
25821da177e4SLinus Torvalds 			}
2583efc683fcSGautam Kachroo next:
2584efc683fcSGautam Kachroo 			idx++;
25851da177e4SLinus Torvalds 		}
25861da177e4SLinus Torvalds 	}
25871da177e4SLinus Torvalds 	rc = skb->len;
25881da177e4SLinus Torvalds out:
2589d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
25901da177e4SLinus Torvalds 	cb->args[1] = h;
25911da177e4SLinus Torvalds 	cb->args[2] = idx;
25921da177e4SLinus Torvalds 	return rc;
25931da177e4SLinus Torvalds }
25941da177e4SLinus Torvalds 
259584920c14STony Zelenoff static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
25966f52f80eSDavid Ahern 			     struct netlink_callback *cb,
25976f52f80eSDavid Ahern 			     struct neigh_dump_filter *filter)
259884920c14STony Zelenoff {
259984920c14STony Zelenoff 	struct pneigh_entry *n;
260084920c14STony Zelenoff 	struct net *net = sock_net(skb->sk);
260184920c14STony Zelenoff 	int rc, h, s_h = cb->args[3];
260284920c14STony Zelenoff 	int idx, s_idx = idx = cb->args[4];
26036f52f80eSDavid Ahern 	unsigned int flags = NLM_F_MULTI;
26046f52f80eSDavid Ahern 
26056f52f80eSDavid Ahern 	if (filter->dev_idx || filter->master_idx)
26066f52f80eSDavid Ahern 		flags |= NLM_F_DUMP_FILTERED;
260784920c14STony Zelenoff 
260884920c14STony Zelenoff 	read_lock_bh(&tbl->lock);
260984920c14STony Zelenoff 
26104bd6683bSEric Dumazet 	for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
261184920c14STony Zelenoff 		if (h > s_h)
261284920c14STony Zelenoff 			s_idx = 0;
261384920c14STony Zelenoff 		for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
261418502acdSZhang Shengju 			if (idx < s_idx || pneigh_net(n) != net)
261584920c14STony Zelenoff 				goto next;
26166f52f80eSDavid Ahern 			if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
26176f52f80eSDavid Ahern 			    neigh_master_filtered(n->dev, filter->master_idx))
26186f52f80eSDavid Ahern 				goto next;
261915e47304SEric W. Biederman 			if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
262084920c14STony Zelenoff 					    cb->nlh->nlmsg_seq,
26216f52f80eSDavid Ahern 					    RTM_NEWNEIGH, flags, tbl) < 0) {
262284920c14STony Zelenoff 				read_unlock_bh(&tbl->lock);
262384920c14STony Zelenoff 				rc = -1;
262484920c14STony Zelenoff 				goto out;
262584920c14STony Zelenoff 			}
262684920c14STony Zelenoff 		next:
262784920c14STony Zelenoff 			idx++;
262884920c14STony Zelenoff 		}
262984920c14STony Zelenoff 	}
263084920c14STony Zelenoff 
263184920c14STony Zelenoff 	read_unlock_bh(&tbl->lock);
263284920c14STony Zelenoff 	rc = skb->len;
263384920c14STony Zelenoff out:
263484920c14STony Zelenoff 	cb->args[3] = h;
263584920c14STony Zelenoff 	cb->args[4] = idx;
263684920c14STony Zelenoff 	return rc;
263784920c14STony Zelenoff 
263884920c14STony Zelenoff }
263984920c14STony Zelenoff 
264051183d23SDavid Ahern static int neigh_valid_dump_req(const struct nlmsghdr *nlh,
264151183d23SDavid Ahern 				bool strict_check,
264251183d23SDavid Ahern 				struct neigh_dump_filter *filter,
264351183d23SDavid Ahern 				struct netlink_ext_ack *extack)
264451183d23SDavid Ahern {
264551183d23SDavid Ahern 	struct nlattr *tb[NDA_MAX + 1];
264651183d23SDavid Ahern 	int err, i;
264751183d23SDavid Ahern 
264851183d23SDavid Ahern 	if (strict_check) {
264951183d23SDavid Ahern 		struct ndmsg *ndm;
265051183d23SDavid Ahern 
265151183d23SDavid Ahern 		if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
265251183d23SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid header for neighbor dump request");
265351183d23SDavid Ahern 			return -EINVAL;
265451183d23SDavid Ahern 		}
265551183d23SDavid Ahern 
265651183d23SDavid Ahern 		ndm = nlmsg_data(nlh);
265751183d23SDavid Ahern 		if (ndm->ndm_pad1  || ndm->ndm_pad2  || ndm->ndm_ifindex ||
2658c0fde870SDavid Ahern 		    ndm->ndm_state || ndm->ndm_type) {
265951183d23SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor dump request");
266051183d23SDavid Ahern 			return -EINVAL;
266151183d23SDavid Ahern 		}
266251183d23SDavid Ahern 
2663c0fde870SDavid Ahern 		if (ndm->ndm_flags & ~NTF_PROXY) {
2664c0fde870SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor dump request");
2665c0fde870SDavid Ahern 			return -EINVAL;
2666c0fde870SDavid Ahern 		}
2667c0fde870SDavid Ahern 
26688cb08174SJohannes Berg 		err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg),
26698cb08174SJohannes Berg 						    tb, NDA_MAX, nda_policy,
26708cb08174SJohannes Berg 						    extack);
267151183d23SDavid Ahern 	} else {
26728cb08174SJohannes Berg 		err = nlmsg_parse_deprecated(nlh, sizeof(struct ndmsg), tb,
26738cb08174SJohannes Berg 					     NDA_MAX, nda_policy, extack);
267451183d23SDavid Ahern 	}
267551183d23SDavid Ahern 	if (err < 0)
267651183d23SDavid Ahern 		return err;
267751183d23SDavid Ahern 
267851183d23SDavid Ahern 	for (i = 0; i <= NDA_MAX; ++i) {
267951183d23SDavid Ahern 		if (!tb[i])
268051183d23SDavid Ahern 			continue;
268151183d23SDavid Ahern 
268251183d23SDavid Ahern 		/* all new attributes should require strict_check */
268351183d23SDavid Ahern 		switch (i) {
268451183d23SDavid Ahern 		case NDA_IFINDEX:
268551183d23SDavid Ahern 			filter->dev_idx = nla_get_u32(tb[i]);
268651183d23SDavid Ahern 			break;
268751183d23SDavid Ahern 		case NDA_MASTER:
268851183d23SDavid Ahern 			filter->master_idx = nla_get_u32(tb[i]);
268951183d23SDavid Ahern 			break;
269051183d23SDavid Ahern 		default:
269151183d23SDavid Ahern 			if (strict_check) {
269251183d23SDavid Ahern 				NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor dump request");
269351183d23SDavid Ahern 				return -EINVAL;
269451183d23SDavid Ahern 			}
269551183d23SDavid Ahern 		}
269651183d23SDavid Ahern 	}
269751183d23SDavid Ahern 
269851183d23SDavid Ahern 	return 0;
269951183d23SDavid Ahern }
270051183d23SDavid Ahern 
2701c8822a4eSThomas Graf static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
27021da177e4SLinus Torvalds {
27036f52f80eSDavid Ahern 	const struct nlmsghdr *nlh = cb->nlh;
27046f52f80eSDavid Ahern 	struct neigh_dump_filter filter = {};
27051da177e4SLinus Torvalds 	struct neigh_table *tbl;
27061da177e4SLinus Torvalds 	int t, family, s_t;
270784920c14STony Zelenoff 	int proxy = 0;
27084bd6683bSEric Dumazet 	int err;
27091da177e4SLinus Torvalds 
27106f52f80eSDavid Ahern 	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
271184920c14STony Zelenoff 
271284920c14STony Zelenoff 	/* check for full ndmsg structure presence, family member is
271384920c14STony Zelenoff 	 * the same for both structures
271484920c14STony Zelenoff 	 */
27156f52f80eSDavid Ahern 	if (nlmsg_len(nlh) >= sizeof(struct ndmsg) &&
27166f52f80eSDavid Ahern 	    ((struct ndmsg *)nlmsg_data(nlh))->ndm_flags == NTF_PROXY)
271784920c14STony Zelenoff 		proxy = 1;
271884920c14STony Zelenoff 
271951183d23SDavid Ahern 	err = neigh_valid_dump_req(nlh, cb->strict_check, &filter, cb->extack);
272051183d23SDavid Ahern 	if (err < 0 && cb->strict_check)
272151183d23SDavid Ahern 		return err;
272251183d23SDavid Ahern 
27231da177e4SLinus Torvalds 	s_t = cb->args[0];
27241da177e4SLinus Torvalds 
2725d7480fd3SWANG Cong 	for (t = 0; t < NEIGH_NR_TABLES; t++) {
2726d7480fd3SWANG Cong 		tbl = neigh_tables[t];
2727d7480fd3SWANG Cong 
2728d7480fd3SWANG Cong 		if (!tbl)
2729d7480fd3SWANG Cong 			continue;
27301da177e4SLinus Torvalds 		if (t < s_t || (family && tbl->family != family))
27311da177e4SLinus Torvalds 			continue;
27321da177e4SLinus Torvalds 		if (t > s_t)
27331da177e4SLinus Torvalds 			memset(&cb->args[1], 0, sizeof(cb->args) -
27341da177e4SLinus Torvalds 						sizeof(cb->args[0]));
273584920c14STony Zelenoff 		if (proxy)
27366f52f80eSDavid Ahern 			err = pneigh_dump_table(tbl, skb, cb, &filter);
273784920c14STony Zelenoff 		else
27386f52f80eSDavid Ahern 			err = neigh_dump_table(tbl, skb, cb, &filter);
27394bd6683bSEric Dumazet 		if (err < 0)
27404bd6683bSEric Dumazet 			break;
27411da177e4SLinus Torvalds 	}
27421da177e4SLinus Torvalds 
27431da177e4SLinus Torvalds 	cb->args[0] = t;
27441da177e4SLinus Torvalds 	return skb->len;
27451da177e4SLinus Torvalds }
27461da177e4SLinus Torvalds 
274782cbb5c6SRoopa Prabhu static int neigh_valid_get_req(const struct nlmsghdr *nlh,
274882cbb5c6SRoopa Prabhu 			       struct neigh_table **tbl,
274982cbb5c6SRoopa Prabhu 			       void **dst, int *dev_idx, u8 *ndm_flags,
275082cbb5c6SRoopa Prabhu 			       struct netlink_ext_ack *extack)
275182cbb5c6SRoopa Prabhu {
275282cbb5c6SRoopa Prabhu 	struct nlattr *tb[NDA_MAX + 1];
275382cbb5c6SRoopa Prabhu 	struct ndmsg *ndm;
275482cbb5c6SRoopa Prabhu 	int err, i;
275582cbb5c6SRoopa Prabhu 
275682cbb5c6SRoopa Prabhu 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
275782cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid header for neighbor get request");
275882cbb5c6SRoopa Prabhu 		return -EINVAL;
275982cbb5c6SRoopa Prabhu 	}
276082cbb5c6SRoopa Prabhu 
276182cbb5c6SRoopa Prabhu 	ndm = nlmsg_data(nlh);
276282cbb5c6SRoopa Prabhu 	if (ndm->ndm_pad1  || ndm->ndm_pad2  || ndm->ndm_state ||
276382cbb5c6SRoopa Prabhu 	    ndm->ndm_type) {
276482cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor get request");
276582cbb5c6SRoopa Prabhu 		return -EINVAL;
276682cbb5c6SRoopa Prabhu 	}
276782cbb5c6SRoopa Prabhu 
276882cbb5c6SRoopa Prabhu 	if (ndm->ndm_flags & ~NTF_PROXY) {
276982cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor get request");
277082cbb5c6SRoopa Prabhu 		return -EINVAL;
277182cbb5c6SRoopa Prabhu 	}
277282cbb5c6SRoopa Prabhu 
27738cb08174SJohannes Berg 	err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb,
27748cb08174SJohannes Berg 					    NDA_MAX, nda_policy, extack);
277582cbb5c6SRoopa Prabhu 	if (err < 0)
277682cbb5c6SRoopa Prabhu 		return err;
277782cbb5c6SRoopa Prabhu 
277882cbb5c6SRoopa Prabhu 	*ndm_flags = ndm->ndm_flags;
277982cbb5c6SRoopa Prabhu 	*dev_idx = ndm->ndm_ifindex;
278082cbb5c6SRoopa Prabhu 	*tbl = neigh_find_table(ndm->ndm_family);
278182cbb5c6SRoopa Prabhu 	if (*tbl == NULL) {
278282cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
278382cbb5c6SRoopa Prabhu 		return -EAFNOSUPPORT;
278482cbb5c6SRoopa Prabhu 	}
278582cbb5c6SRoopa Prabhu 
278682cbb5c6SRoopa Prabhu 	for (i = 0; i <= NDA_MAX; ++i) {
278782cbb5c6SRoopa Prabhu 		if (!tb[i])
278882cbb5c6SRoopa Prabhu 			continue;
278982cbb5c6SRoopa Prabhu 
279082cbb5c6SRoopa Prabhu 		switch (i) {
279182cbb5c6SRoopa Prabhu 		case NDA_DST:
279282cbb5c6SRoopa Prabhu 			if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
279382cbb5c6SRoopa Prabhu 				NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
279482cbb5c6SRoopa Prabhu 				return -EINVAL;
279582cbb5c6SRoopa Prabhu 			}
279682cbb5c6SRoopa Prabhu 			*dst = nla_data(tb[i]);
279782cbb5c6SRoopa Prabhu 			break;
279882cbb5c6SRoopa Prabhu 		default:
279982cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request");
280082cbb5c6SRoopa Prabhu 			return -EINVAL;
280182cbb5c6SRoopa Prabhu 		}
280282cbb5c6SRoopa Prabhu 	}
280382cbb5c6SRoopa Prabhu 
280482cbb5c6SRoopa Prabhu 	return 0;
280582cbb5c6SRoopa Prabhu }
280682cbb5c6SRoopa Prabhu 
280782cbb5c6SRoopa Prabhu static inline size_t neigh_nlmsg_size(void)
280882cbb5c6SRoopa Prabhu {
280982cbb5c6SRoopa Prabhu 	return NLMSG_ALIGN(sizeof(struct ndmsg))
281082cbb5c6SRoopa Prabhu 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
281182cbb5c6SRoopa Prabhu 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
281282cbb5c6SRoopa Prabhu 	       + nla_total_size(sizeof(struct nda_cacheinfo))
281382cbb5c6SRoopa Prabhu 	       + nla_total_size(4)  /* NDA_PROBES */
281482cbb5c6SRoopa Prabhu 	       + nla_total_size(1); /* NDA_PROTOCOL */
281582cbb5c6SRoopa Prabhu }
281682cbb5c6SRoopa Prabhu 
281782cbb5c6SRoopa Prabhu static int neigh_get_reply(struct net *net, struct neighbour *neigh,
281882cbb5c6SRoopa Prabhu 			   u32 pid, u32 seq)
281982cbb5c6SRoopa Prabhu {
282082cbb5c6SRoopa Prabhu 	struct sk_buff *skb;
282182cbb5c6SRoopa Prabhu 	int err = 0;
282282cbb5c6SRoopa Prabhu 
282382cbb5c6SRoopa Prabhu 	skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL);
282482cbb5c6SRoopa Prabhu 	if (!skb)
282582cbb5c6SRoopa Prabhu 		return -ENOBUFS;
282682cbb5c6SRoopa Prabhu 
282782cbb5c6SRoopa Prabhu 	err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0);
282882cbb5c6SRoopa Prabhu 	if (err) {
282982cbb5c6SRoopa Prabhu 		kfree_skb(skb);
283082cbb5c6SRoopa Prabhu 		goto errout;
283182cbb5c6SRoopa Prabhu 	}
283282cbb5c6SRoopa Prabhu 
283382cbb5c6SRoopa Prabhu 	err = rtnl_unicast(skb, net, pid);
283482cbb5c6SRoopa Prabhu errout:
283582cbb5c6SRoopa Prabhu 	return err;
283682cbb5c6SRoopa Prabhu }
283782cbb5c6SRoopa Prabhu 
283882cbb5c6SRoopa Prabhu static inline size_t pneigh_nlmsg_size(void)
283982cbb5c6SRoopa Prabhu {
284082cbb5c6SRoopa Prabhu 	return NLMSG_ALIGN(sizeof(struct ndmsg))
2841463561e6SColin Ian King 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
284282cbb5c6SRoopa Prabhu 	       + nla_total_size(1); /* NDA_PROTOCOL */
284382cbb5c6SRoopa Prabhu }
284482cbb5c6SRoopa Prabhu 
284582cbb5c6SRoopa Prabhu static int pneigh_get_reply(struct net *net, struct pneigh_entry *neigh,
284682cbb5c6SRoopa Prabhu 			    u32 pid, u32 seq, struct neigh_table *tbl)
284782cbb5c6SRoopa Prabhu {
284882cbb5c6SRoopa Prabhu 	struct sk_buff *skb;
284982cbb5c6SRoopa Prabhu 	int err = 0;
285082cbb5c6SRoopa Prabhu 
285182cbb5c6SRoopa Prabhu 	skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL);
285282cbb5c6SRoopa Prabhu 	if (!skb)
285382cbb5c6SRoopa Prabhu 		return -ENOBUFS;
285482cbb5c6SRoopa Prabhu 
285582cbb5c6SRoopa Prabhu 	err = pneigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0, tbl);
285682cbb5c6SRoopa Prabhu 	if (err) {
285782cbb5c6SRoopa Prabhu 		kfree_skb(skb);
285882cbb5c6SRoopa Prabhu 		goto errout;
285982cbb5c6SRoopa Prabhu 	}
286082cbb5c6SRoopa Prabhu 
286182cbb5c6SRoopa Prabhu 	err = rtnl_unicast(skb, net, pid);
286282cbb5c6SRoopa Prabhu errout:
286382cbb5c6SRoopa Prabhu 	return err;
286482cbb5c6SRoopa Prabhu }
286582cbb5c6SRoopa Prabhu 
286682cbb5c6SRoopa Prabhu static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
286782cbb5c6SRoopa Prabhu 		     struct netlink_ext_ack *extack)
286882cbb5c6SRoopa Prabhu {
286982cbb5c6SRoopa Prabhu 	struct net *net = sock_net(in_skb->sk);
287082cbb5c6SRoopa Prabhu 	struct net_device *dev = NULL;
287182cbb5c6SRoopa Prabhu 	struct neigh_table *tbl = NULL;
287282cbb5c6SRoopa Prabhu 	struct neighbour *neigh;
287382cbb5c6SRoopa Prabhu 	void *dst = NULL;
287482cbb5c6SRoopa Prabhu 	u8 ndm_flags = 0;
287582cbb5c6SRoopa Prabhu 	int dev_idx = 0;
287682cbb5c6SRoopa Prabhu 	int err;
287782cbb5c6SRoopa Prabhu 
287882cbb5c6SRoopa Prabhu 	err = neigh_valid_get_req(nlh, &tbl, &dst, &dev_idx, &ndm_flags,
287982cbb5c6SRoopa Prabhu 				  extack);
288082cbb5c6SRoopa Prabhu 	if (err < 0)
288182cbb5c6SRoopa Prabhu 		return err;
288282cbb5c6SRoopa Prabhu 
288382cbb5c6SRoopa Prabhu 	if (dev_idx) {
288482cbb5c6SRoopa Prabhu 		dev = __dev_get_by_index(net, dev_idx);
288582cbb5c6SRoopa Prabhu 		if (!dev) {
288682cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Unknown device ifindex");
288782cbb5c6SRoopa Prabhu 			return -ENODEV;
288882cbb5c6SRoopa Prabhu 		}
288982cbb5c6SRoopa Prabhu 	}
289082cbb5c6SRoopa Prabhu 
289182cbb5c6SRoopa Prabhu 	if (!dst) {
289282cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Network address not specified");
289382cbb5c6SRoopa Prabhu 		return -EINVAL;
289482cbb5c6SRoopa Prabhu 	}
289582cbb5c6SRoopa Prabhu 
289682cbb5c6SRoopa Prabhu 	if (ndm_flags & NTF_PROXY) {
289782cbb5c6SRoopa Prabhu 		struct pneigh_entry *pn;
289882cbb5c6SRoopa Prabhu 
289982cbb5c6SRoopa Prabhu 		pn = pneigh_lookup(tbl, net, dst, dev, 0);
290082cbb5c6SRoopa Prabhu 		if (!pn) {
290182cbb5c6SRoopa Prabhu 			NL_SET_ERR_MSG(extack, "Proxy neighbour entry not found");
290282cbb5c6SRoopa Prabhu 			return -ENOENT;
290382cbb5c6SRoopa Prabhu 		}
290482cbb5c6SRoopa Prabhu 		return pneigh_get_reply(net, pn, NETLINK_CB(in_skb).portid,
290582cbb5c6SRoopa Prabhu 					nlh->nlmsg_seq, tbl);
290682cbb5c6SRoopa Prabhu 	}
290782cbb5c6SRoopa Prabhu 
290882cbb5c6SRoopa Prabhu 	if (!dev) {
290982cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "No device specified");
291082cbb5c6SRoopa Prabhu 		return -EINVAL;
291182cbb5c6SRoopa Prabhu 	}
291282cbb5c6SRoopa Prabhu 
291382cbb5c6SRoopa Prabhu 	neigh = neigh_lookup(tbl, dst, dev);
291482cbb5c6SRoopa Prabhu 	if (!neigh) {
291582cbb5c6SRoopa Prabhu 		NL_SET_ERR_MSG(extack, "Neighbour entry not found");
291682cbb5c6SRoopa Prabhu 		return -ENOENT;
291782cbb5c6SRoopa Prabhu 	}
291882cbb5c6SRoopa Prabhu 
291982cbb5c6SRoopa Prabhu 	err = neigh_get_reply(net, neigh, NETLINK_CB(in_skb).portid,
292082cbb5c6SRoopa Prabhu 			      nlh->nlmsg_seq);
292182cbb5c6SRoopa Prabhu 
292282cbb5c6SRoopa Prabhu 	neigh_release(neigh);
292382cbb5c6SRoopa Prabhu 
292482cbb5c6SRoopa Prabhu 	return err;
292582cbb5c6SRoopa Prabhu }
292682cbb5c6SRoopa Prabhu 
29271da177e4SLinus Torvalds void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
29281da177e4SLinus Torvalds {
29291da177e4SLinus Torvalds 	int chain;
2930d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
29311da177e4SLinus Torvalds 
2932d6bf7817SEric Dumazet 	rcu_read_lock_bh();
2933d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
2934d6bf7817SEric Dumazet 
2935767e97e1SEric Dumazet 	read_lock(&tbl->lock); /* avoid resizes */
2936cd089336SDavid S. Miller 	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
29371da177e4SLinus Torvalds 		struct neighbour *n;
29381da177e4SLinus Torvalds 
2939767e97e1SEric Dumazet 		for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
2940767e97e1SEric Dumazet 		     n != NULL;
2941767e97e1SEric Dumazet 		     n = rcu_dereference_bh(n->next))
29421da177e4SLinus Torvalds 			cb(n, cookie);
29431da177e4SLinus Torvalds 	}
2944d6bf7817SEric Dumazet 	read_unlock(&tbl->lock);
2945d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
29461da177e4SLinus Torvalds }
29471da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_for_each);
29481da177e4SLinus Torvalds 
29491da177e4SLinus Torvalds /* The tbl->lock must be held as a writer and BH disabled. */
29501da177e4SLinus Torvalds void __neigh_for_each_release(struct neigh_table *tbl,
29511da177e4SLinus Torvalds 			      int (*cb)(struct neighbour *))
29521da177e4SLinus Torvalds {
29531da177e4SLinus Torvalds 	int chain;
2954d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
29551da177e4SLinus Torvalds 
2956d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
2957d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
2958cd089336SDavid S. Miller 	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
2959767e97e1SEric Dumazet 		struct neighbour *n;
2960767e97e1SEric Dumazet 		struct neighbour __rcu **np;
29611da177e4SLinus Torvalds 
2962d6bf7817SEric Dumazet 		np = &nht->hash_buckets[chain];
2963767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
2964767e97e1SEric Dumazet 					lockdep_is_held(&tbl->lock))) != NULL) {
29651da177e4SLinus Torvalds 			int release;
29661da177e4SLinus Torvalds 
29671da177e4SLinus Torvalds 			write_lock(&n->lock);
29681da177e4SLinus Torvalds 			release = cb(n);
29691da177e4SLinus Torvalds 			if (release) {
2970767e97e1SEric Dumazet 				rcu_assign_pointer(*np,
2971767e97e1SEric Dumazet 					rcu_dereference_protected(n->next,
2972767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
297358956317SDavid Ahern 				neigh_mark_dead(n);
29741da177e4SLinus Torvalds 			} else
29751da177e4SLinus Torvalds 				np = &n->next;
29761da177e4SLinus Torvalds 			write_unlock(&n->lock);
29774f494554SThomas Graf 			if (release)
29784f494554SThomas Graf 				neigh_cleanup_and_release(n);
29791da177e4SLinus Torvalds 		}
29801da177e4SLinus Torvalds 	}
2981ecbb4169SAlexey Kuznetsov }
29821da177e4SLinus Torvalds EXPORT_SYMBOL(__neigh_for_each_release);
29831da177e4SLinus Torvalds 
2984b79bda3dSEric W. Biederman int neigh_xmit(int index, struct net_device *dev,
29854fd3d7d9SEric W. Biederman 	       const void *addr, struct sk_buff *skb)
29864fd3d7d9SEric W. Biederman {
2987b79bda3dSEric W. Biederman 	int err = -EAFNOSUPPORT;
2988b79bda3dSEric W. Biederman 	if (likely(index < NEIGH_NR_TABLES)) {
29894fd3d7d9SEric W. Biederman 		struct neigh_table *tbl;
29904fd3d7d9SEric W. Biederman 		struct neighbour *neigh;
29914fd3d7d9SEric W. Biederman 
2992b79bda3dSEric W. Biederman 		tbl = neigh_tables[index];
29934fd3d7d9SEric W. Biederman 		if (!tbl)
29944fd3d7d9SEric W. Biederman 			goto out;
2995b560f03dSDavid Barroso 		rcu_read_lock_bh();
29964b2a2bfeSDavid Ahern 		if (index == NEIGH_ARP_TABLE) {
29974b2a2bfeSDavid Ahern 			u32 key = *((u32 *)addr);
29984b2a2bfeSDavid Ahern 
29994b2a2bfeSDavid Ahern 			neigh = __ipv4_neigh_lookup_noref(dev, key);
30004b2a2bfeSDavid Ahern 		} else {
30014fd3d7d9SEric W. Biederman 			neigh = __neigh_lookup_noref(tbl, addr, dev);
30024b2a2bfeSDavid Ahern 		}
30034fd3d7d9SEric W. Biederman 		if (!neigh)
30044fd3d7d9SEric W. Biederman 			neigh = __neigh_create(tbl, addr, dev, false);
30054fd3d7d9SEric W. Biederman 		err = PTR_ERR(neigh);
3006b560f03dSDavid Barroso 		if (IS_ERR(neigh)) {
3007b560f03dSDavid Barroso 			rcu_read_unlock_bh();
30084fd3d7d9SEric W. Biederman 			goto out_kfree_skb;
3009b560f03dSDavid Barroso 		}
30104fd3d7d9SEric W. Biederman 		err = neigh->output(neigh, skb);
3011b560f03dSDavid Barroso 		rcu_read_unlock_bh();
30124fd3d7d9SEric W. Biederman 	}
3013b79bda3dSEric W. Biederman 	else if (index == NEIGH_LINK_TABLE) {
3014b79bda3dSEric W. Biederman 		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
3015b79bda3dSEric W. Biederman 				      addr, NULL, skb->len);
3016b79bda3dSEric W. Biederman 		if (err < 0)
3017b79bda3dSEric W. Biederman 			goto out_kfree_skb;
3018b79bda3dSEric W. Biederman 		err = dev_queue_xmit(skb);
3019b79bda3dSEric W. Biederman 	}
30204fd3d7d9SEric W. Biederman out:
30214fd3d7d9SEric W. Biederman 	return err;
30224fd3d7d9SEric W. Biederman out_kfree_skb:
30234fd3d7d9SEric W. Biederman 	kfree_skb(skb);
30244fd3d7d9SEric W. Biederman 	goto out;
30254fd3d7d9SEric W. Biederman }
30264fd3d7d9SEric W. Biederman EXPORT_SYMBOL(neigh_xmit);
30274fd3d7d9SEric W. Biederman 
30281da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
30291da177e4SLinus Torvalds 
30301da177e4SLinus Torvalds static struct neighbour *neigh_get_first(struct seq_file *seq)
30311da177e4SLinus Torvalds {
30321da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
30331218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
3034d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = state->nht;
30351da177e4SLinus Torvalds 	struct neighbour *n = NULL;
3036f530eed6SColin Ian King 	int bucket;
30371da177e4SLinus Torvalds 
30381da177e4SLinus Torvalds 	state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
3039cd089336SDavid S. Miller 	for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
3040767e97e1SEric Dumazet 		n = rcu_dereference_bh(nht->hash_buckets[bucket]);
30411da177e4SLinus Torvalds 
30421da177e4SLinus Torvalds 		while (n) {
3043878628fbSYOSHIFUJI Hideaki 			if (!net_eq(dev_net(n->dev), net))
3044426b5303SEric W. Biederman 				goto next;
30451da177e4SLinus Torvalds 			if (state->neigh_sub_iter) {
30461da177e4SLinus Torvalds 				loff_t fakep = 0;
30471da177e4SLinus Torvalds 				void *v;
30481da177e4SLinus Torvalds 
30491da177e4SLinus Torvalds 				v = state->neigh_sub_iter(state, n, &fakep);
30501da177e4SLinus Torvalds 				if (!v)
30511da177e4SLinus Torvalds 					goto next;
30521da177e4SLinus Torvalds 			}
30531da177e4SLinus Torvalds 			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
30541da177e4SLinus Torvalds 				break;
30551da177e4SLinus Torvalds 			if (n->nud_state & ~NUD_NOARP)
30561da177e4SLinus Torvalds 				break;
30571da177e4SLinus Torvalds next:
3058767e97e1SEric Dumazet 			n = rcu_dereference_bh(n->next);
30591da177e4SLinus Torvalds 		}
30601da177e4SLinus Torvalds 
30611da177e4SLinus Torvalds 		if (n)
30621da177e4SLinus Torvalds 			break;
30631da177e4SLinus Torvalds 	}
30641da177e4SLinus Torvalds 	state->bucket = bucket;
30651da177e4SLinus Torvalds 
30661da177e4SLinus Torvalds 	return n;
30671da177e4SLinus Torvalds }
30681da177e4SLinus Torvalds 
30691da177e4SLinus Torvalds static struct neighbour *neigh_get_next(struct seq_file *seq,
30701da177e4SLinus Torvalds 					struct neighbour *n,
30711da177e4SLinus Torvalds 					loff_t *pos)
30721da177e4SLinus Torvalds {
30731da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
30741218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
3075d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = state->nht;
30761da177e4SLinus Torvalds 
30771da177e4SLinus Torvalds 	if (state->neigh_sub_iter) {
30781da177e4SLinus Torvalds 		void *v = state->neigh_sub_iter(state, n, pos);
30791da177e4SLinus Torvalds 		if (v)
30801da177e4SLinus Torvalds 			return n;
30811da177e4SLinus Torvalds 	}
3082767e97e1SEric Dumazet 	n = rcu_dereference_bh(n->next);
30831da177e4SLinus Torvalds 
30841da177e4SLinus Torvalds 	while (1) {
30851da177e4SLinus Torvalds 		while (n) {
3086878628fbSYOSHIFUJI Hideaki 			if (!net_eq(dev_net(n->dev), net))
3087426b5303SEric W. Biederman 				goto next;
30881da177e4SLinus Torvalds 			if (state->neigh_sub_iter) {
30891da177e4SLinus Torvalds 				void *v = state->neigh_sub_iter(state, n, pos);
30901da177e4SLinus Torvalds 				if (v)
30911da177e4SLinus Torvalds 					return n;
30921da177e4SLinus Torvalds 				goto next;
30931da177e4SLinus Torvalds 			}
30941da177e4SLinus Torvalds 			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
30951da177e4SLinus Torvalds 				break;
30961da177e4SLinus Torvalds 
30971da177e4SLinus Torvalds 			if (n->nud_state & ~NUD_NOARP)
30981da177e4SLinus Torvalds 				break;
30991da177e4SLinus Torvalds next:
3100767e97e1SEric Dumazet 			n = rcu_dereference_bh(n->next);
31011da177e4SLinus Torvalds 		}
31021da177e4SLinus Torvalds 
31031da177e4SLinus Torvalds 		if (n)
31041da177e4SLinus Torvalds 			break;
31051da177e4SLinus Torvalds 
3106cd089336SDavid S. Miller 		if (++state->bucket >= (1 << nht->hash_shift))
31071da177e4SLinus Torvalds 			break;
31081da177e4SLinus Torvalds 
3109767e97e1SEric Dumazet 		n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
31101da177e4SLinus Torvalds 	}
31111da177e4SLinus Torvalds 
31121da177e4SLinus Torvalds 	if (n && pos)
31131da177e4SLinus Torvalds 		--(*pos);
31141da177e4SLinus Torvalds 	return n;
31151da177e4SLinus Torvalds }
31161da177e4SLinus Torvalds 
31171da177e4SLinus Torvalds static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
31181da177e4SLinus Torvalds {
31191da177e4SLinus Torvalds 	struct neighbour *n = neigh_get_first(seq);
31201da177e4SLinus Torvalds 
31211da177e4SLinus Torvalds 	if (n) {
3122745e2031SChris Larson 		--(*pos);
31231da177e4SLinus Torvalds 		while (*pos) {
31241da177e4SLinus Torvalds 			n = neigh_get_next(seq, n, pos);
31251da177e4SLinus Torvalds 			if (!n)
31261da177e4SLinus Torvalds 				break;
31271da177e4SLinus Torvalds 		}
31281da177e4SLinus Torvalds 	}
31291da177e4SLinus Torvalds 	return *pos ? NULL : n;
31301da177e4SLinus Torvalds }
31311da177e4SLinus Torvalds 
31321da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
31331da177e4SLinus Torvalds {
31341da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
31351218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
31361da177e4SLinus Torvalds 	struct neigh_table *tbl = state->tbl;
31371da177e4SLinus Torvalds 	struct pneigh_entry *pn = NULL;
31381da177e4SLinus Torvalds 	int bucket = state->bucket;
31391da177e4SLinus Torvalds 
31401da177e4SLinus Torvalds 	state->flags |= NEIGH_SEQ_IS_PNEIGH;
31411da177e4SLinus Torvalds 	for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
31421da177e4SLinus Torvalds 		pn = tbl->phash_buckets[bucket];
3143878628fbSYOSHIFUJI Hideaki 		while (pn && !net_eq(pneigh_net(pn), net))
3144426b5303SEric W. Biederman 			pn = pn->next;
31451da177e4SLinus Torvalds 		if (pn)
31461da177e4SLinus Torvalds 			break;
31471da177e4SLinus Torvalds 	}
31481da177e4SLinus Torvalds 	state->bucket = bucket;
31491da177e4SLinus Torvalds 
31501da177e4SLinus Torvalds 	return pn;
31511da177e4SLinus Torvalds }
31521da177e4SLinus Torvalds 
31531da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
31541da177e4SLinus Torvalds 					    struct pneigh_entry *pn,
31551da177e4SLinus Torvalds 					    loff_t *pos)
31561da177e4SLinus Torvalds {
31571da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
31581218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
31591da177e4SLinus Torvalds 	struct neigh_table *tbl = state->tbl;
31601da177e4SLinus Torvalds 
3161df07a94cSJorge Boncompte [DTI2] 	do {
31621da177e4SLinus Torvalds 		pn = pn->next;
3163df07a94cSJorge Boncompte [DTI2] 	} while (pn && !net_eq(pneigh_net(pn), net));
3164df07a94cSJorge Boncompte [DTI2] 
31651da177e4SLinus Torvalds 	while (!pn) {
31661da177e4SLinus Torvalds 		if (++state->bucket > PNEIGH_HASHMASK)
31671da177e4SLinus Torvalds 			break;
31681da177e4SLinus Torvalds 		pn = tbl->phash_buckets[state->bucket];
3169878628fbSYOSHIFUJI Hideaki 		while (pn && !net_eq(pneigh_net(pn), net))
3170426b5303SEric W. Biederman 			pn = pn->next;
31711da177e4SLinus Torvalds 		if (pn)
31721da177e4SLinus Torvalds 			break;
31731da177e4SLinus Torvalds 	}
31741da177e4SLinus Torvalds 
31751da177e4SLinus Torvalds 	if (pn && pos)
31761da177e4SLinus Torvalds 		--(*pos);
31771da177e4SLinus Torvalds 
31781da177e4SLinus Torvalds 	return pn;
31791da177e4SLinus Torvalds }
31801da177e4SLinus Torvalds 
31811da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
31821da177e4SLinus Torvalds {
31831da177e4SLinus Torvalds 	struct pneigh_entry *pn = pneigh_get_first(seq);
31841da177e4SLinus Torvalds 
31851da177e4SLinus Torvalds 	if (pn) {
3186745e2031SChris Larson 		--(*pos);
31871da177e4SLinus Torvalds 		while (*pos) {
31881da177e4SLinus Torvalds 			pn = pneigh_get_next(seq, pn, pos);
31891da177e4SLinus Torvalds 			if (!pn)
31901da177e4SLinus Torvalds 				break;
31911da177e4SLinus Torvalds 		}
31921da177e4SLinus Torvalds 	}
31931da177e4SLinus Torvalds 	return *pos ? NULL : pn;
31941da177e4SLinus Torvalds }
31951da177e4SLinus Torvalds 
31961da177e4SLinus Torvalds static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
31971da177e4SLinus Torvalds {
31981da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
31991da177e4SLinus Torvalds 	void *rc;
3200745e2031SChris Larson 	loff_t idxpos = *pos;
32011da177e4SLinus Torvalds 
3202745e2031SChris Larson 	rc = neigh_get_idx(seq, &idxpos);
32031da177e4SLinus Torvalds 	if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
3204745e2031SChris Larson 		rc = pneigh_get_idx(seq, &idxpos);
32051da177e4SLinus Torvalds 
32061da177e4SLinus Torvalds 	return rc;
32071da177e4SLinus Torvalds }
32081da177e4SLinus Torvalds 
32091da177e4SLinus Torvalds void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags)
3210f3e92cb8SEric Dumazet 	__acquires(tbl->lock)
3211d6bf7817SEric Dumazet 	__acquires(rcu_bh)
32121da177e4SLinus Torvalds {
32131da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
32141da177e4SLinus Torvalds 
32151da177e4SLinus Torvalds 	state->tbl = tbl;
32161da177e4SLinus Torvalds 	state->bucket = 0;
32171da177e4SLinus Torvalds 	state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
32181da177e4SLinus Torvalds 
3219d6bf7817SEric Dumazet 	rcu_read_lock_bh();
3220d6bf7817SEric Dumazet 	state->nht = rcu_dereference_bh(tbl->nht);
3221f3e92cb8SEric Dumazet 	read_lock(&tbl->lock);
3222767e97e1SEric Dumazet 
3223745e2031SChris Larson 	return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
32241da177e4SLinus Torvalds }
32251da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_start);
32261da177e4SLinus Torvalds 
32271da177e4SLinus Torvalds void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
32281da177e4SLinus Torvalds {
32291da177e4SLinus Torvalds 	struct neigh_seq_state *state;
32301da177e4SLinus Torvalds 	void *rc;
32311da177e4SLinus Torvalds 
32321da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN) {
3233bff69732SChris Larson 		rc = neigh_get_first(seq);
32341da177e4SLinus Torvalds 		goto out;
32351da177e4SLinus Torvalds 	}
32361da177e4SLinus Torvalds 
32371da177e4SLinus Torvalds 	state = seq->private;
32381da177e4SLinus Torvalds 	if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
32391da177e4SLinus Torvalds 		rc = neigh_get_next(seq, v, NULL);
32401da177e4SLinus Torvalds 		if (rc)
32411da177e4SLinus Torvalds 			goto out;
32421da177e4SLinus Torvalds 		if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
32431da177e4SLinus Torvalds 			rc = pneigh_get_first(seq);
32441da177e4SLinus Torvalds 	} else {
32451da177e4SLinus Torvalds 		BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
32461da177e4SLinus Torvalds 		rc = pneigh_get_next(seq, v, NULL);
32471da177e4SLinus Torvalds 	}
32481da177e4SLinus Torvalds out:
32491da177e4SLinus Torvalds 	++(*pos);
32501da177e4SLinus Torvalds 	return rc;
32511da177e4SLinus Torvalds }
32521da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_next);
32531da177e4SLinus Torvalds 
32541da177e4SLinus Torvalds void neigh_seq_stop(struct seq_file *seq, void *v)
3255f3e92cb8SEric Dumazet 	__releases(tbl->lock)
3256d6bf7817SEric Dumazet 	__releases(rcu_bh)
32571da177e4SLinus Torvalds {
3258f3e92cb8SEric Dumazet 	struct neigh_seq_state *state = seq->private;
3259f3e92cb8SEric Dumazet 	struct neigh_table *tbl = state->tbl;
3260f3e92cb8SEric Dumazet 
3261f3e92cb8SEric Dumazet 	read_unlock(&tbl->lock);
3262d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
32631da177e4SLinus Torvalds }
32641da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_stop);
32651da177e4SLinus Torvalds 
32661da177e4SLinus Torvalds /* statistics via seq_file */
32671da177e4SLinus Torvalds 
32681da177e4SLinus Torvalds static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
32691da177e4SLinus Torvalds {
327071a5053aSChristoph Hellwig 	struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
32711da177e4SLinus Torvalds 	int cpu;
32721da177e4SLinus Torvalds 
32731da177e4SLinus Torvalds 	if (*pos == 0)
32741da177e4SLinus Torvalds 		return SEQ_START_TOKEN;
32751da177e4SLinus Torvalds 
32760f23174aSRusty Russell 	for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
32771da177e4SLinus Torvalds 		if (!cpu_possible(cpu))
32781da177e4SLinus Torvalds 			continue;
32791da177e4SLinus Torvalds 		*pos = cpu+1;
32801da177e4SLinus Torvalds 		return per_cpu_ptr(tbl->stats, cpu);
32811da177e4SLinus Torvalds 	}
32821da177e4SLinus Torvalds 	return NULL;
32831da177e4SLinus Torvalds }
32841da177e4SLinus Torvalds 
32851da177e4SLinus Torvalds static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
32861da177e4SLinus Torvalds {
328771a5053aSChristoph Hellwig 	struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
32881da177e4SLinus Torvalds 	int cpu;
32891da177e4SLinus Torvalds 
32900f23174aSRusty Russell 	for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
32911da177e4SLinus Torvalds 		if (!cpu_possible(cpu))
32921da177e4SLinus Torvalds 			continue;
32931da177e4SLinus Torvalds 		*pos = cpu+1;
32941da177e4SLinus Torvalds 		return per_cpu_ptr(tbl->stats, cpu);
32951da177e4SLinus Torvalds 	}
32961da177e4SLinus Torvalds 	return NULL;
32971da177e4SLinus Torvalds }
32981da177e4SLinus Torvalds 
32991da177e4SLinus Torvalds static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
33001da177e4SLinus Torvalds {
33011da177e4SLinus Torvalds 
33021da177e4SLinus Torvalds }
33031da177e4SLinus Torvalds 
33041da177e4SLinus Torvalds static int neigh_stat_seq_show(struct seq_file *seq, void *v)
33051da177e4SLinus Torvalds {
330671a5053aSChristoph Hellwig 	struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
33071da177e4SLinus Torvalds 	struct neigh_statistics *st = v;
33081da177e4SLinus Torvalds 
33091da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN) {
3310fb811395SRick 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");
33111da177e4SLinus Torvalds 		return 0;
33121da177e4SLinus Torvalds 	}
33131da177e4SLinus Torvalds 
33141da177e4SLinus Torvalds 	seq_printf(seq, "%08x  %08lx %08lx %08lx  %08lx %08lx  %08lx  "
3315fb811395SRick Jones 			"%08lx %08lx  %08lx %08lx %08lx %08lx\n",
33161da177e4SLinus Torvalds 		   atomic_read(&tbl->entries),
33171da177e4SLinus Torvalds 
33181da177e4SLinus Torvalds 		   st->allocs,
33191da177e4SLinus Torvalds 		   st->destroys,
33201da177e4SLinus Torvalds 		   st->hash_grows,
33211da177e4SLinus Torvalds 
33221da177e4SLinus Torvalds 		   st->lookups,
33231da177e4SLinus Torvalds 		   st->hits,
33241da177e4SLinus Torvalds 
33251da177e4SLinus Torvalds 		   st->res_failed,
33261da177e4SLinus Torvalds 
33271da177e4SLinus Torvalds 		   st->rcv_probes_mcast,
33281da177e4SLinus Torvalds 		   st->rcv_probes_ucast,
33291da177e4SLinus Torvalds 
33301da177e4SLinus Torvalds 		   st->periodic_gc_runs,
33319a6d276eSNeil Horman 		   st->forced_gc_runs,
3332fb811395SRick Jones 		   st->unres_discards,
3333fb811395SRick Jones 		   st->table_fulls
33341da177e4SLinus Torvalds 		   );
33351da177e4SLinus Torvalds 
33361da177e4SLinus Torvalds 	return 0;
33371da177e4SLinus Torvalds }
33381da177e4SLinus Torvalds 
3339f690808eSStephen Hemminger static const struct seq_operations neigh_stat_seq_ops = {
33401da177e4SLinus Torvalds 	.start	= neigh_stat_seq_start,
33411da177e4SLinus Torvalds 	.next	= neigh_stat_seq_next,
33421da177e4SLinus Torvalds 	.stop	= neigh_stat_seq_stop,
33431da177e4SLinus Torvalds 	.show	= neigh_stat_seq_show,
33441da177e4SLinus Torvalds };
33451da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */
33461da177e4SLinus Torvalds 
33477b8f7a40SRoopa Prabhu static void __neigh_notify(struct neighbour *n, int type, int flags,
33487b8f7a40SRoopa Prabhu 			   u32 pid)
33491da177e4SLinus Torvalds {
3350c346dca1SYOSHIFUJI Hideaki 	struct net *net = dev_net(n->dev);
33518b8aec50SThomas Graf 	struct sk_buff *skb;
3352b8673311SThomas Graf 	int err = -ENOBUFS;
33531da177e4SLinus Torvalds 
3354339bf98fSThomas Graf 	skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
33558b8aec50SThomas Graf 	if (skb == NULL)
3356b8673311SThomas Graf 		goto errout;
33571da177e4SLinus Torvalds 
33587b8f7a40SRoopa Prabhu 	err = neigh_fill_info(skb, n, pid, 0, type, flags);
335926932566SPatrick McHardy 	if (err < 0) {
336026932566SPatrick McHardy 		/* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
336126932566SPatrick McHardy 		WARN_ON(err == -EMSGSIZE);
336226932566SPatrick McHardy 		kfree_skb(skb);
336326932566SPatrick McHardy 		goto errout;
336426932566SPatrick McHardy 	}
33651ce85fe4SPablo Neira Ayuso 	rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
33661ce85fe4SPablo Neira Ayuso 	return;
3367b8673311SThomas Graf errout:
3368b8673311SThomas Graf 	if (err < 0)
3369426b5303SEric W. Biederman 		rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
3370b8673311SThomas Graf }
3371b8673311SThomas Graf 
3372b8673311SThomas Graf void neigh_app_ns(struct neighbour *n)
3373b8673311SThomas Graf {
33747b8f7a40SRoopa Prabhu 	__neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST, 0);
33758b8aec50SThomas Graf }
33760a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_app_ns);
33771da177e4SLinus Torvalds 
33781da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL
3379b93196dcSCong Wang static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
33801da177e4SLinus Torvalds 
3381fe2c6338SJoe Perches static int proc_unres_qlen(struct ctl_table *ctl, int write,
3382fe2c6338SJoe Perches 			   void __user *buffer, size_t *lenp, loff_t *ppos)
33838b5c171bSEric Dumazet {
33848b5c171bSEric Dumazet 	int size, ret;
3385fe2c6338SJoe Perches 	struct ctl_table tmp = *ctl;
33868b5c171bSEric Dumazet 
3387eec4844fSMatteo Croce 	tmp.extra1 = SYSCTL_ZERO;
3388ce46cc64SShan Wei 	tmp.extra2 = &unres_qlen_max;
33898b5c171bSEric Dumazet 	tmp.data = &size;
3390ce46cc64SShan Wei 
3391ce46cc64SShan Wei 	size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN);
3392ce46cc64SShan Wei 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
3393ce46cc64SShan Wei 
33948b5c171bSEric Dumazet 	if (write && !ret)
33958b5c171bSEric Dumazet 		*(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
33968b5c171bSEric Dumazet 	return ret;
33978b5c171bSEric Dumazet }
33988b5c171bSEric Dumazet 
33991d4c8c29SJiri Pirko static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
34001d4c8c29SJiri Pirko 						   int family)
34011d4c8c29SJiri Pirko {
3402bba24896SJiri Pirko 	switch (family) {
3403bba24896SJiri Pirko 	case AF_INET:
34041d4c8c29SJiri Pirko 		return __in_dev_arp_parms_get_rcu(dev);
3405bba24896SJiri Pirko 	case AF_INET6:
3406bba24896SJiri Pirko 		return __in6_dev_nd_parms_get_rcu(dev);
3407bba24896SJiri Pirko 	}
34081d4c8c29SJiri Pirko 	return NULL;
34091d4c8c29SJiri Pirko }
34101d4c8c29SJiri Pirko 
34111d4c8c29SJiri Pirko static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
34121d4c8c29SJiri Pirko 				  int index)
34131d4c8c29SJiri Pirko {
34141d4c8c29SJiri Pirko 	struct net_device *dev;
34151d4c8c29SJiri Pirko 	int family = neigh_parms_family(p);
34161d4c8c29SJiri Pirko 
34171d4c8c29SJiri Pirko 	rcu_read_lock();
34181d4c8c29SJiri Pirko 	for_each_netdev_rcu(net, dev) {
34191d4c8c29SJiri Pirko 		struct neigh_parms *dst_p =
34201d4c8c29SJiri Pirko 				neigh_get_dev_parms_rcu(dev, family);
34211d4c8c29SJiri Pirko 
34221d4c8c29SJiri Pirko 		if (dst_p && !test_bit(index, dst_p->data_state))
34231d4c8c29SJiri Pirko 			dst_p->data[index] = p->data[index];
34241d4c8c29SJiri Pirko 	}
34251d4c8c29SJiri Pirko 	rcu_read_unlock();
34261d4c8c29SJiri Pirko }
34271d4c8c29SJiri Pirko 
34281d4c8c29SJiri Pirko static void neigh_proc_update(struct ctl_table *ctl, int write)
34291d4c8c29SJiri Pirko {
34301d4c8c29SJiri Pirko 	struct net_device *dev = ctl->extra1;
34311d4c8c29SJiri Pirko 	struct neigh_parms *p = ctl->extra2;
343277d47afbSJiri Pirko 	struct net *net = neigh_parms_net(p);
34331d4c8c29SJiri Pirko 	int index = (int *) ctl->data - p->data;
34341d4c8c29SJiri Pirko 
34351d4c8c29SJiri Pirko 	if (!write)
34361d4c8c29SJiri Pirko 		return;
34371d4c8c29SJiri Pirko 
34381d4c8c29SJiri Pirko 	set_bit(index, p->data_state);
34397627ae60SMarcus Huewe 	if (index == NEIGH_VAR_DELAY_PROBE_TIME)
34402a4501aeSIdo Schimmel 		call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
34411d4c8c29SJiri Pirko 	if (!dev) /* NULL dev means this is default value */
34421d4c8c29SJiri Pirko 		neigh_copy_dflt_parms(net, p, index);
34431d4c8c29SJiri Pirko }
34441d4c8c29SJiri Pirko 
34451f9248e5SJiri Pirko static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
34461f9248e5SJiri Pirko 					   void __user *buffer,
34471f9248e5SJiri Pirko 					   size_t *lenp, loff_t *ppos)
34481f9248e5SJiri Pirko {
34491f9248e5SJiri Pirko 	struct ctl_table tmp = *ctl;
34501d4c8c29SJiri Pirko 	int ret;
34511f9248e5SJiri Pirko 
3452eec4844fSMatteo Croce 	tmp.extra1 = SYSCTL_ZERO;
3453eec4844fSMatteo Croce 	tmp.extra2 = SYSCTL_INT_MAX;
34541f9248e5SJiri Pirko 
34551d4c8c29SJiri Pirko 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
34561d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
34571d4c8c29SJiri Pirko 	return ret;
34581f9248e5SJiri Pirko }
34591f9248e5SJiri Pirko 
3460cb5b09c1SJiri Pirko int neigh_proc_dointvec(struct ctl_table *ctl, int write,
3461cb5b09c1SJiri Pirko 			void __user *buffer, size_t *lenp, loff_t *ppos)
3462cb5b09c1SJiri Pirko {
34631d4c8c29SJiri Pirko 	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
34641d4c8c29SJiri Pirko 
34651d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
34661d4c8c29SJiri Pirko 	return ret;
3467cb5b09c1SJiri Pirko }
3468cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec);
3469cb5b09c1SJiri Pirko 
3470cb5b09c1SJiri Pirko int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write,
3471cb5b09c1SJiri Pirko 				void __user *buffer,
3472cb5b09c1SJiri Pirko 				size_t *lenp, loff_t *ppos)
3473cb5b09c1SJiri Pirko {
34741d4c8c29SJiri Pirko 	int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
34751d4c8c29SJiri Pirko 
34761d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
34771d4c8c29SJiri Pirko 	return ret;
3478cb5b09c1SJiri Pirko }
3479cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
3480cb5b09c1SJiri Pirko 
3481cb5b09c1SJiri Pirko static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write,
3482cb5b09c1SJiri Pirko 					      void __user *buffer,
3483cb5b09c1SJiri Pirko 					      size_t *lenp, loff_t *ppos)
3484cb5b09c1SJiri Pirko {
34851d4c8c29SJiri Pirko 	int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
34861d4c8c29SJiri Pirko 
34871d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
34881d4c8c29SJiri Pirko 	return ret;
3489cb5b09c1SJiri Pirko }
3490cb5b09c1SJiri Pirko 
3491cb5b09c1SJiri Pirko int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
3492cb5b09c1SJiri Pirko 				   void __user *buffer,
3493cb5b09c1SJiri Pirko 				   size_t *lenp, loff_t *ppos)
3494cb5b09c1SJiri Pirko {
34951d4c8c29SJiri Pirko 	int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
34961d4c8c29SJiri Pirko 
34971d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
34981d4c8c29SJiri Pirko 	return ret;
3499cb5b09c1SJiri Pirko }
3500cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
3501cb5b09c1SJiri Pirko 
3502cb5b09c1SJiri Pirko static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
3503cb5b09c1SJiri Pirko 					  void __user *buffer,
3504cb5b09c1SJiri Pirko 					  size_t *lenp, loff_t *ppos)
3505cb5b09c1SJiri Pirko {
35061d4c8c29SJiri Pirko 	int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
35071d4c8c29SJiri Pirko 
35081d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
35091d4c8c29SJiri Pirko 	return ret;
3510cb5b09c1SJiri Pirko }
3511cb5b09c1SJiri Pirko 
35124bf6980dSJean-Francois Remy static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write,
35134bf6980dSJean-Francois Remy 					  void __user *buffer,
35144bf6980dSJean-Francois Remy 					  size_t *lenp, loff_t *ppos)
35154bf6980dSJean-Francois Remy {
35164bf6980dSJean-Francois Remy 	struct neigh_parms *p = ctl->extra2;
35174bf6980dSJean-Francois Remy 	int ret;
35184bf6980dSJean-Francois Remy 
35194bf6980dSJean-Francois Remy 	if (strcmp(ctl->procname, "base_reachable_time") == 0)
35204bf6980dSJean-Francois Remy 		ret = neigh_proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
35214bf6980dSJean-Francois Remy 	else if (strcmp(ctl->procname, "base_reachable_time_ms") == 0)
35224bf6980dSJean-Francois Remy 		ret = neigh_proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
35234bf6980dSJean-Francois Remy 	else
35244bf6980dSJean-Francois Remy 		ret = -1;
35254bf6980dSJean-Francois Remy 
35264bf6980dSJean-Francois Remy 	if (write && ret == 0) {
35274bf6980dSJean-Francois Remy 		/* update reachable_time as well, otherwise, the change will
35284bf6980dSJean-Francois Remy 		 * only be effective after the next time neigh_periodic_work
35294bf6980dSJean-Francois Remy 		 * decides to recompute it
35304bf6980dSJean-Francois Remy 		 */
35314bf6980dSJean-Francois Remy 		p->reachable_time =
35324bf6980dSJean-Francois Remy 			neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
35334bf6980dSJean-Francois Remy 	}
35344bf6980dSJean-Francois Remy 	return ret;
35354bf6980dSJean-Francois Remy }
35364bf6980dSJean-Francois Remy 
35371f9248e5SJiri Pirko #define NEIGH_PARMS_DATA_OFFSET(index)	\
35381f9248e5SJiri Pirko 	(&((struct neigh_parms *) 0)->data[index])
35391f9248e5SJiri Pirko 
35401f9248e5SJiri Pirko #define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \
35411f9248e5SJiri Pirko 	[NEIGH_VAR_ ## attr] = { \
35421f9248e5SJiri Pirko 		.procname	= name, \
35431f9248e5SJiri Pirko 		.data		= NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \
35441f9248e5SJiri Pirko 		.maxlen		= sizeof(int), \
35451f9248e5SJiri Pirko 		.mode		= mval, \
35461f9248e5SJiri Pirko 		.proc_handler	= proc, \
35471f9248e5SJiri Pirko 	}
35481f9248e5SJiri Pirko 
35491f9248e5SJiri Pirko #define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \
35501f9248e5SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax)
35511f9248e5SJiri Pirko 
35521f9248e5SJiri Pirko #define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \
3553cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies)
35541f9248e5SJiri Pirko 
35551f9248e5SJiri Pirko #define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
3556cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)
35571f9248e5SJiri Pirko 
35581f9248e5SJiri Pirko #define NEIGH_SYSCTL_MS_JIFFIES_ENTRY(attr, name) \
3559cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
35601f9248e5SJiri Pirko 
35611f9248e5SJiri Pirko #define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \
3562cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
35631f9248e5SJiri Pirko 
35641f9248e5SJiri Pirko #define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \
3565cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_unres_qlen)
356654716e3bSEric W. Biederman 
35671da177e4SLinus Torvalds static struct neigh_sysctl_table {
35681da177e4SLinus Torvalds 	struct ctl_table_header *sysctl_header;
35698b5c171bSEric Dumazet 	struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
3570ab32ea5dSBrian Haley } neigh_sysctl_template __read_mostly = {
35711da177e4SLinus Torvalds 	.neigh_vars = {
35721f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"),
35731f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"),
35741f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"),
35758da86466SYOSHIFUJI Hideaki/吉藤英明 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_REPROBES, "mcast_resolicit"),
35761f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),
35771f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),
35781f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"),
35791f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"),
35801f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"),
35811f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"),
35821f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"),
35831f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"),
35841f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"),
35851f9248e5SJiri Pirko 		NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"),
35861f9248e5SJiri Pirko 		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"),
35871f9248e5SJiri Pirko 		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"),
35888b5c171bSEric Dumazet 		[NEIGH_VAR_GC_INTERVAL] = {
35891da177e4SLinus Torvalds 			.procname	= "gc_interval",
35901da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
35911da177e4SLinus Torvalds 			.mode		= 0644,
35926d9f239aSAlexey Dobriyan 			.proc_handler	= proc_dointvec_jiffies,
35931da177e4SLinus Torvalds 		},
35948b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH1] = {
35951da177e4SLinus Torvalds 			.procname	= "gc_thresh1",
35961da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
35971da177e4SLinus Torvalds 			.mode		= 0644,
3598eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3599eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3600555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
36011da177e4SLinus Torvalds 		},
36028b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH2] = {
36031da177e4SLinus Torvalds 			.procname	= "gc_thresh2",
36041da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
36051da177e4SLinus Torvalds 			.mode		= 0644,
3606eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3607eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3608555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
36091da177e4SLinus Torvalds 		},
36108b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH3] = {
36111da177e4SLinus Torvalds 			.procname	= "gc_thresh3",
36121da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
36131da177e4SLinus Torvalds 			.mode		= 0644,
3614eec4844fSMatteo Croce 			.extra1		= SYSCTL_ZERO,
3615eec4844fSMatteo Croce 			.extra2		= SYSCTL_INT_MAX,
3616555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
36171da177e4SLinus Torvalds 		},
3618c3bac5a7SPavel Emelyanov 		{},
36191da177e4SLinus Torvalds 	},
36201da177e4SLinus Torvalds };
36211da177e4SLinus Torvalds 
36221da177e4SLinus Torvalds int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
362373af614aSJiri Pirko 			  proc_handler *handler)
36241da177e4SLinus Torvalds {
36251f9248e5SJiri Pirko 	int i;
36263c607bbbSPavel Emelyanov 	struct neigh_sysctl_table *t;
36271f9248e5SJiri Pirko 	const char *dev_name_source;
36288f40a1f9SEric W. Biederman 	char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
362973af614aSJiri Pirko 	char *p_name;
36301da177e4SLinus Torvalds 
36313c607bbbSPavel Emelyanov 	t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
36321da177e4SLinus Torvalds 	if (!t)
36333c607bbbSPavel Emelyanov 		goto err;
36343c607bbbSPavel Emelyanov 
3635b194c1f1SJiri Pirko 	for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
36361f9248e5SJiri Pirko 		t->neigh_vars[i].data += (long) p;
3637cb5b09c1SJiri Pirko 		t->neigh_vars[i].extra1 = dev;
36381d4c8c29SJiri Pirko 		t->neigh_vars[i].extra2 = p;
3639cb5b09c1SJiri Pirko 	}
36401da177e4SLinus Torvalds 
36411da177e4SLinus Torvalds 	if (dev) {
36421da177e4SLinus Torvalds 		dev_name_source = dev->name;
3643d12af679SEric W. Biederman 		/* Terminate the table early */
36448b5c171bSEric Dumazet 		memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
36458b5c171bSEric Dumazet 		       sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
36461da177e4SLinus Torvalds 	} else {
36479ecf07a1SMathias Krause 		struct neigh_table *tbl = p->tbl;
36488f40a1f9SEric W. Biederman 		dev_name_source = "default";
36499ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = &tbl->gc_interval;
36509ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = &tbl->gc_thresh1;
36519ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = &tbl->gc_thresh2;
36529ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = &tbl->gc_thresh3;
36531da177e4SLinus Torvalds 	}
36541da177e4SLinus Torvalds 
3655f8572d8fSEric W. Biederman 	if (handler) {
36561da177e4SLinus Torvalds 		/* RetransTime */
36578b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
36581da177e4SLinus Torvalds 		/* ReachableTime */
36598b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
36601da177e4SLinus Torvalds 		/* RetransTime (in milliseconds)*/
36618b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
36621da177e4SLinus Torvalds 		/* ReachableTime (in milliseconds) */
36638b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
36644bf6980dSJean-Francois Remy 	} else {
36654bf6980dSJean-Francois Remy 		/* Those handlers will update p->reachable_time after
36664bf6980dSJean-Francois Remy 		 * base_reachable_time(_ms) is set to ensure the new timer starts being
36674bf6980dSJean-Francois Remy 		 * applied after the next neighbour update instead of waiting for
36684bf6980dSJean-Francois Remy 		 * neigh_periodic_work to update its value (can be multiple minutes)
36694bf6980dSJean-Francois Remy 		 * So any handler that replaces them should do this as well
36704bf6980dSJean-Francois Remy 		 */
36714bf6980dSJean-Francois Remy 		/* ReachableTime */
36724bf6980dSJean-Francois Remy 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler =
36734bf6980dSJean-Francois Remy 			neigh_proc_base_reachable_time;
36744bf6980dSJean-Francois Remy 		/* ReachableTime (in milliseconds) */
36754bf6980dSJean-Francois Remy 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler =
36764bf6980dSJean-Francois Remy 			neigh_proc_base_reachable_time;
36771da177e4SLinus Torvalds 	}
36781da177e4SLinus Torvalds 
3679464dc801SEric W. Biederman 	/* Don't export sysctls to unprivileged users */
3680464dc801SEric W. Biederman 	if (neigh_parms_net(p)->user_ns != &init_user_ns)
3681464dc801SEric W. Biederman 		t->neigh_vars[0].procname = NULL;
3682464dc801SEric W. Biederman 
368373af614aSJiri Pirko 	switch (neigh_parms_family(p)) {
368473af614aSJiri Pirko 	case AF_INET:
368573af614aSJiri Pirko 	      p_name = "ipv4";
368673af614aSJiri Pirko 	      break;
368773af614aSJiri Pirko 	case AF_INET6:
368873af614aSJiri Pirko 	      p_name = "ipv6";
368973af614aSJiri Pirko 	      break;
369073af614aSJiri Pirko 	default:
369173af614aSJiri Pirko 	      BUG();
369273af614aSJiri Pirko 	}
369373af614aSJiri Pirko 
36948f40a1f9SEric W. Biederman 	snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
36958f40a1f9SEric W. Biederman 		p_name, dev_name_source);
36964ab438fcSDenis V. Lunev 	t->sysctl_header =
36978f40a1f9SEric W. Biederman 		register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
36983c607bbbSPavel Emelyanov 	if (!t->sysctl_header)
36998f40a1f9SEric W. Biederman 		goto free;
37003c607bbbSPavel Emelyanov 
37011da177e4SLinus Torvalds 	p->sysctl_table = t;
37021da177e4SLinus Torvalds 	return 0;
37031da177e4SLinus Torvalds 
37041da177e4SLinus Torvalds free:
37051da177e4SLinus Torvalds 	kfree(t);
37063c607bbbSPavel Emelyanov err:
37073c607bbbSPavel Emelyanov 	return -ENOBUFS;
37081da177e4SLinus Torvalds }
37090a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_sysctl_register);
37101da177e4SLinus Torvalds 
37111da177e4SLinus Torvalds void neigh_sysctl_unregister(struct neigh_parms *p)
37121da177e4SLinus Torvalds {
37131da177e4SLinus Torvalds 	if (p->sysctl_table) {
37141da177e4SLinus Torvalds 		struct neigh_sysctl_table *t = p->sysctl_table;
37151da177e4SLinus Torvalds 		p->sysctl_table = NULL;
37165dd3df10SEric W. Biederman 		unregister_net_sysctl_table(t->sysctl_header);
37171da177e4SLinus Torvalds 		kfree(t);
37181da177e4SLinus Torvalds 	}
37191da177e4SLinus Torvalds }
37200a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_sysctl_unregister);
37211da177e4SLinus Torvalds 
37221da177e4SLinus Torvalds #endif	/* CONFIG_SYSCTL */
37231da177e4SLinus Torvalds 
3724c8822a4eSThomas Graf static int __init neigh_init(void)
3725c8822a4eSThomas Graf {
3726b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0);
3727b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0);
372882cbb5c6SRoopa Prabhu 	rtnl_register(PF_UNSPEC, RTM_GETNEIGH, neigh_get, neigh_dump_info, 0);
3729c8822a4eSThomas Graf 
3730c7ac8679SGreg Rose 	rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
3731b97bac64SFlorian Westphal 		      0);
3732b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, 0);
3733c8822a4eSThomas Graf 
3734c8822a4eSThomas Graf 	return 0;
3735c8822a4eSThomas Graf }
3736c8822a4eSThomas Graf 
3737c8822a4eSThomas Graf subsys_initcall(neigh_init);
3738