xref: /openbmc/linux/net/core/neighbour.c (revision 9c29a2f5)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *	Generic address resolution entity
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *	Authors:
51da177e4SLinus Torvalds  *	Pedro Roque		<roque@di.fc.ul.pt>
61da177e4SLinus Torvalds  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  *	This program is free software; you can redistribute it and/or
91da177e4SLinus Torvalds  *      modify it under the terms of the GNU General Public License
101da177e4SLinus Torvalds  *      as published by the Free Software Foundation; either version
111da177e4SLinus Torvalds  *      2 of the License, or (at your option) any later version.
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  *	Fixes:
141da177e4SLinus Torvalds  *	Vitaly E. Lavrov	releasing NULL neighbor in neigh_add.
151da177e4SLinus Torvalds  *	Harald Welte		Add neighbour cache statistics like rtstat
161da177e4SLinus Torvalds  */
171da177e4SLinus Torvalds 
18e005d193SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19e005d193SJoe Perches 
205a0e3ad6STejun Heo #include <linux/slab.h>
211da177e4SLinus Torvalds #include <linux/types.h>
221da177e4SLinus Torvalds #include <linux/kernel.h>
231da177e4SLinus Torvalds #include <linux/module.h>
241da177e4SLinus Torvalds #include <linux/socket.h>
251da177e4SLinus Torvalds #include <linux/netdevice.h>
261da177e4SLinus Torvalds #include <linux/proc_fs.h>
271da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL
281da177e4SLinus Torvalds #include <linux/sysctl.h>
291da177e4SLinus Torvalds #endif
301da177e4SLinus Torvalds #include <linux/times.h>
31457c4cbcSEric W. Biederman #include <net/net_namespace.h>
321da177e4SLinus Torvalds #include <net/neighbour.h>
331da177e4SLinus Torvalds #include <net/dst.h>
341da177e4SLinus Torvalds #include <net/sock.h>
358d71740cSTom Tucker #include <net/netevent.h>
36a14a49d2SThomas Graf #include <net/netlink.h>
371da177e4SLinus Torvalds #include <linux/rtnetlink.h>
381da177e4SLinus Torvalds #include <linux/random.h>
39543537bdSPaulo Marques #include <linux/string.h>
40c3609d51Svignesh babu #include <linux/log2.h>
411d4c8c29SJiri Pirko #include <linux/inetdevice.h>
42bba24896SJiri Pirko #include <net/addrconf.h>
431da177e4SLinus Torvalds 
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 
1047b8f7a40SRoopa Prabhu 	__neigh_notify(neigh, RTM_DELNEIGH, 0, 0);
10553f800e3SIdo Schimmel 	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
1064f494554SThomas Graf 	neigh_release(neigh);
1074f494554SThomas Graf }
1084f494554SThomas Graf 
1091da177e4SLinus Torvalds /*
1101da177e4SLinus Torvalds  * It is random distribution in the interval (1/2)*base...(3/2)*base.
1111da177e4SLinus Torvalds  * It corresponds to default IPv6 settings and is not overridable,
1121da177e4SLinus Torvalds  * because it is really reasonable choice.
1131da177e4SLinus Torvalds  */
1141da177e4SLinus Torvalds 
1151da177e4SLinus Torvalds unsigned long neigh_rand_reach_time(unsigned long base)
1161da177e4SLinus Torvalds {
11763862b5bSAruna-Hewapathirane 	return base ? (prandom_u32() % base) + (base >> 1) : 0;
1181da177e4SLinus Torvalds }
1190a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_rand_reach_time);
1201da177e4SLinus Torvalds 
12158956317SDavid Ahern static void neigh_mark_dead(struct neighbour *n)
12258956317SDavid Ahern {
12358956317SDavid Ahern 	n->dead = 1;
12458956317SDavid Ahern 	if (!list_empty(&n->gc_list)) {
12558956317SDavid Ahern 		list_del_init(&n->gc_list);
12658956317SDavid Ahern 		atomic_dec(&n->tbl->gc_entries);
12758956317SDavid Ahern 	}
12858956317SDavid Ahern }
12958956317SDavid Ahern 
1309c29a2f5SDavid Ahern static void neigh_update_gc_list(struct neighbour *n)
13158956317SDavid Ahern {
1329c29a2f5SDavid Ahern 	bool on_gc_list, new_is_perm;
13358956317SDavid Ahern 
1349c29a2f5SDavid Ahern 	write_lock_bh(&n->tbl->lock);
1359c29a2f5SDavid Ahern 	write_lock(&n->lock);
13658956317SDavid Ahern 
13758956317SDavid Ahern 	/* remove from the gc list if new state is permanent;
13858956317SDavid Ahern 	 * add to the gc list if new state is not permanent
13958956317SDavid Ahern 	 */
1409c29a2f5SDavid Ahern 	new_is_perm = n->nud_state & NUD_PERMANENT;
1419c29a2f5SDavid Ahern 	on_gc_list = !list_empty(&n->gc_list);
1428cc196d6SDavid Ahern 
1439c29a2f5SDavid Ahern 	if (new_is_perm && on_gc_list) {
1449c29a2f5SDavid Ahern 		list_del_init(&n->gc_list);
14558956317SDavid Ahern 		atomic_dec(&n->tbl->gc_entries);
14658956317SDavid Ahern 	} else if (!new_is_perm && !on_gc_list) {
14758956317SDavid Ahern 		/* add entries to the tail; cleaning removes from the front */
14858956317SDavid Ahern 		list_add_tail(&n->gc_list, &n->tbl->gc_list);
14958956317SDavid Ahern 		atomic_inc(&n->tbl->gc_entries);
15058956317SDavid Ahern 	}
1519c29a2f5SDavid Ahern 
1529c29a2f5SDavid Ahern 	write_unlock(&n->lock);
1539c29a2f5SDavid Ahern 	write_unlock_bh(&n->tbl->lock);
15458956317SDavid Ahern }
1551da177e4SLinus Torvalds 
156f6a6f203SRoopa Prabhu static bool neigh_del(struct neighbour *n, __u8 state, __u8 flags,
1575071034eSSowmini Varadhan 		      struct neighbour __rcu **np, struct neigh_table *tbl)
1585071034eSSowmini Varadhan {
1595071034eSSowmini Varadhan 	bool retval = false;
1605071034eSSowmini Varadhan 
1615071034eSSowmini Varadhan 	write_lock(&n->lock);
162f6a6f203SRoopa Prabhu 	if (refcount_read(&n->refcnt) == 1 && !(n->nud_state & state) &&
163f6a6f203SRoopa Prabhu 	    !(n->flags & flags)) {
1645071034eSSowmini Varadhan 		struct neighbour *neigh;
1655071034eSSowmini Varadhan 
1665071034eSSowmini Varadhan 		neigh = rcu_dereference_protected(n->next,
1675071034eSSowmini Varadhan 						  lockdep_is_held(&tbl->lock));
1685071034eSSowmini Varadhan 		rcu_assign_pointer(*np, neigh);
16958956317SDavid Ahern 		neigh_mark_dead(n);
1705071034eSSowmini Varadhan 		retval = true;
1715071034eSSowmini Varadhan 	}
1725071034eSSowmini Varadhan 	write_unlock(&n->lock);
1735071034eSSowmini Varadhan 	if (retval)
1745071034eSSowmini Varadhan 		neigh_cleanup_and_release(n);
1755071034eSSowmini Varadhan 	return retval;
1765071034eSSowmini Varadhan }
1775071034eSSowmini Varadhan 
1785071034eSSowmini Varadhan bool neigh_remove_one(struct neighbour *ndel, struct neigh_table *tbl)
1795071034eSSowmini Varadhan {
1805071034eSSowmini Varadhan 	struct neigh_hash_table *nht;
1815071034eSSowmini Varadhan 	void *pkey = ndel->primary_key;
1825071034eSSowmini Varadhan 	u32 hash_val;
1835071034eSSowmini Varadhan 	struct neighbour *n;
1845071034eSSowmini Varadhan 	struct neighbour __rcu **np;
1855071034eSSowmini Varadhan 
1865071034eSSowmini Varadhan 	nht = rcu_dereference_protected(tbl->nht,
1875071034eSSowmini Varadhan 					lockdep_is_held(&tbl->lock));
1885071034eSSowmini Varadhan 	hash_val = tbl->hash(pkey, ndel->dev, nht->hash_rnd);
1895071034eSSowmini Varadhan 	hash_val = hash_val >> (32 - nht->hash_shift);
1905071034eSSowmini Varadhan 
1915071034eSSowmini Varadhan 	np = &nht->hash_buckets[hash_val];
1925071034eSSowmini Varadhan 	while ((n = rcu_dereference_protected(*np,
1935071034eSSowmini Varadhan 					      lockdep_is_held(&tbl->lock)))) {
1945071034eSSowmini Varadhan 		if (n == ndel)
195f6a6f203SRoopa Prabhu 			return neigh_del(n, 0, 0, np, tbl);
1965071034eSSowmini Varadhan 		np = &n->next;
1975071034eSSowmini Varadhan 	}
1985071034eSSowmini Varadhan 	return false;
1995071034eSSowmini Varadhan }
2005071034eSSowmini Varadhan 
2011da177e4SLinus Torvalds static int neigh_forced_gc(struct neigh_table *tbl)
2021da177e4SLinus Torvalds {
20358956317SDavid Ahern 	int max_clean = atomic_read(&tbl->gc_entries) - tbl->gc_thresh2;
20458956317SDavid Ahern 	unsigned long tref = jiffies - 5 * HZ;
20558956317SDavid Ahern 	u8 flags = NTF_EXT_LEARNED;
20658956317SDavid Ahern 	struct neighbour *n, *tmp;
20758956317SDavid Ahern 	u8 state = NUD_PERMANENT;
2081da177e4SLinus Torvalds 	int shrunk = 0;
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
2131da177e4SLinus Torvalds 
21458956317SDavid Ahern 	list_for_each_entry_safe(n, tmp, &tbl->gc_list, gc_list) {
21558956317SDavid Ahern 		if (refcount_read(&n->refcnt) == 1) {
21658956317SDavid Ahern 			bool remove = false;
21758956317SDavid Ahern 
21858956317SDavid Ahern 			write_lock(&n->lock);
21958956317SDavid Ahern 			if (!(n->nud_state & state) && !(n->flags & flags) &&
22058956317SDavid Ahern 			    time_after(tref, n->updated))
22158956317SDavid Ahern 				remove = true;
22258956317SDavid Ahern 			write_unlock(&n->lock);
22358956317SDavid Ahern 
22458956317SDavid Ahern 			if (remove && neigh_remove_one(n, tbl))
22558956317SDavid Ahern 				shrunk++;
22658956317SDavid Ahern 			if (shrunk >= max_clean)
22758956317SDavid Ahern 				break;
2281da177e4SLinus Torvalds 		}
2291da177e4SLinus Torvalds 	}
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds 	tbl->last_flush = jiffies;
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds 	return shrunk;
2361da177e4SLinus Torvalds }
2371da177e4SLinus Torvalds 
238a43d8994SPavel Emelyanov static void neigh_add_timer(struct neighbour *n, unsigned long when)
239a43d8994SPavel Emelyanov {
240a43d8994SPavel Emelyanov 	neigh_hold(n);
241a43d8994SPavel Emelyanov 	if (unlikely(mod_timer(&n->timer, when))) {
242a43d8994SPavel Emelyanov 		printk("NEIGH: BUG, double timer add, state is %x\n",
243a43d8994SPavel Emelyanov 		       n->nud_state);
244a43d8994SPavel Emelyanov 		dump_stack();
245a43d8994SPavel Emelyanov 	}
246a43d8994SPavel Emelyanov }
247a43d8994SPavel Emelyanov 
2481da177e4SLinus Torvalds static int neigh_del_timer(struct neighbour *n)
2491da177e4SLinus Torvalds {
2501da177e4SLinus Torvalds 	if ((n->nud_state & NUD_IN_TIMER) &&
2511da177e4SLinus Torvalds 	    del_timer(&n->timer)) {
2521da177e4SLinus Torvalds 		neigh_release(n);
2531da177e4SLinus Torvalds 		return 1;
2541da177e4SLinus Torvalds 	}
2551da177e4SLinus Torvalds 	return 0;
2561da177e4SLinus Torvalds }
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds static void pneigh_queue_purge(struct sk_buff_head *list)
2591da177e4SLinus Torvalds {
2601da177e4SLinus Torvalds 	struct sk_buff *skb;
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds 	while ((skb = skb_dequeue(list)) != NULL) {
2631da177e4SLinus Torvalds 		dev_put(skb->dev);
2641da177e4SLinus Torvalds 		kfree_skb(skb);
2651da177e4SLinus Torvalds 	}
2661da177e4SLinus Torvalds }
2671da177e4SLinus Torvalds 
268859bd2efSDavid Ahern static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev,
269859bd2efSDavid Ahern 			    bool skip_perm)
2701da177e4SLinus Torvalds {
2711da177e4SLinus Torvalds 	int i;
272d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
2731da177e4SLinus Torvalds 
274d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
275d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
276d6bf7817SEric Dumazet 
277cd089336SDavid S. Miller 	for (i = 0; i < (1 << nht->hash_shift); i++) {
278767e97e1SEric Dumazet 		struct neighbour *n;
279767e97e1SEric Dumazet 		struct neighbour __rcu **np = &nht->hash_buckets[i];
2801da177e4SLinus Torvalds 
281767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
282767e97e1SEric Dumazet 					lockdep_is_held(&tbl->lock))) != NULL) {
2831da177e4SLinus Torvalds 			if (dev && n->dev != dev) {
2841da177e4SLinus Torvalds 				np = &n->next;
2851da177e4SLinus Torvalds 				continue;
2861da177e4SLinus Torvalds 			}
287859bd2efSDavid Ahern 			if (skip_perm && n->nud_state & NUD_PERMANENT) {
288859bd2efSDavid Ahern 				np = &n->next;
289859bd2efSDavid Ahern 				continue;
290859bd2efSDavid Ahern 			}
291767e97e1SEric Dumazet 			rcu_assign_pointer(*np,
292767e97e1SEric Dumazet 				   rcu_dereference_protected(n->next,
293767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
2941da177e4SLinus Torvalds 			write_lock(&n->lock);
2951da177e4SLinus Torvalds 			neigh_del_timer(n);
29658956317SDavid Ahern 			neigh_mark_dead(n);
2979f237430SReshetova, Elena 			if (refcount_read(&n->refcnt) != 1) {
2981da177e4SLinus Torvalds 				/* The most unpleasant situation.
2991da177e4SLinus Torvalds 				   We must destroy neighbour entry,
3001da177e4SLinus Torvalds 				   but someone still uses it.
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds 				   The destroy will be delayed until
3031da177e4SLinus Torvalds 				   the last user releases us, but
3041da177e4SLinus Torvalds 				   we must kill timers etc. and move
3051da177e4SLinus Torvalds 				   it to safe state.
3061da177e4SLinus Torvalds 				 */
307c9ab4d85SEric Dumazet 				__skb_queue_purge(&n->arp_queue);
3088b5c171bSEric Dumazet 				n->arp_queue_len_bytes = 0;
3091da177e4SLinus Torvalds 				n->output = neigh_blackhole;
3101da177e4SLinus Torvalds 				if (n->nud_state & NUD_VALID)
3111da177e4SLinus Torvalds 					n->nud_state = NUD_NOARP;
3121da177e4SLinus Torvalds 				else
3131da177e4SLinus Torvalds 					n->nud_state = NUD_NONE;
314d5d427cdSJoe Perches 				neigh_dbg(2, "neigh %p is stray\n", n);
3151da177e4SLinus Torvalds 			}
3161da177e4SLinus Torvalds 			write_unlock(&n->lock);
3174f494554SThomas Graf 			neigh_cleanup_and_release(n);
3181da177e4SLinus Torvalds 		}
3191da177e4SLinus Torvalds 	}
32049636bb1SHerbert Xu }
3211da177e4SLinus Torvalds 
32249636bb1SHerbert Xu void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
32349636bb1SHerbert Xu {
32449636bb1SHerbert Xu 	write_lock_bh(&tbl->lock);
325859bd2efSDavid Ahern 	neigh_flush_dev(tbl, dev, false);
32649636bb1SHerbert Xu 	write_unlock_bh(&tbl->lock);
32749636bb1SHerbert Xu }
3280a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_changeaddr);
32949636bb1SHerbert Xu 
330859bd2efSDavid Ahern static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
331859bd2efSDavid Ahern 			  bool skip_perm)
33249636bb1SHerbert Xu {
33349636bb1SHerbert Xu 	write_lock_bh(&tbl->lock);
334859bd2efSDavid Ahern 	neigh_flush_dev(tbl, dev, skip_perm);
33553b76cdfSWolfgang Bumiller 	pneigh_ifdown_and_unlock(tbl, dev);
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds 	del_timer_sync(&tbl->proxy_timer);
3381da177e4SLinus Torvalds 	pneigh_queue_purge(&tbl->proxy_queue);
3391da177e4SLinus Torvalds 	return 0;
3401da177e4SLinus Torvalds }
341859bd2efSDavid Ahern 
342859bd2efSDavid Ahern int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev)
343859bd2efSDavid Ahern {
344859bd2efSDavid Ahern 	__neigh_ifdown(tbl, dev, true);
345859bd2efSDavid Ahern 	return 0;
346859bd2efSDavid Ahern }
347859bd2efSDavid Ahern EXPORT_SYMBOL(neigh_carrier_down);
348859bd2efSDavid Ahern 
349859bd2efSDavid Ahern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
350859bd2efSDavid Ahern {
351859bd2efSDavid Ahern 	__neigh_ifdown(tbl, dev, false);
352859bd2efSDavid Ahern 	return 0;
353859bd2efSDavid Ahern }
3540a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_ifdown);
3551da177e4SLinus Torvalds 
35658956317SDavid Ahern static struct neighbour *neigh_alloc(struct neigh_table *tbl,
35758956317SDavid Ahern 				     struct net_device *dev,
35858956317SDavid Ahern 				     bool permanent)
3591da177e4SLinus Torvalds {
3601da177e4SLinus Torvalds 	struct neighbour *n = NULL;
3611da177e4SLinus Torvalds 	unsigned long now = jiffies;
3621da177e4SLinus Torvalds 	int entries;
3631da177e4SLinus Torvalds 
36458956317SDavid Ahern 	if (permanent)
36558956317SDavid Ahern 		goto do_alloc;
36658956317SDavid Ahern 
36758956317SDavid Ahern 	entries = atomic_inc_return(&tbl->gc_entries) - 1;
3681da177e4SLinus Torvalds 	if (entries >= tbl->gc_thresh3 ||
3691da177e4SLinus Torvalds 	    (entries >= tbl->gc_thresh2 &&
3701da177e4SLinus Torvalds 	     time_after(now, tbl->last_flush + 5 * HZ))) {
3711da177e4SLinus Torvalds 		if (!neigh_forced_gc(tbl) &&
372fb811395SRick Jones 		    entries >= tbl->gc_thresh3) {
373fb811395SRick Jones 			net_info_ratelimited("%s: neighbor table overflow!\n",
374fb811395SRick Jones 					     tbl->id);
375fb811395SRick Jones 			NEIGH_CACHE_STAT_INC(tbl, table_fulls);
3761da177e4SLinus Torvalds 			goto out_entries;
3771da177e4SLinus Torvalds 		}
378fb811395SRick Jones 	}
3791da177e4SLinus Torvalds 
38058956317SDavid Ahern do_alloc:
38108433effSYOSHIFUJI Hideaki / 吉藤英明 	n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
3821da177e4SLinus Torvalds 	if (!n)
3831da177e4SLinus Torvalds 		goto out_entries;
3841da177e4SLinus Torvalds 
385c9ab4d85SEric Dumazet 	__skb_queue_head_init(&n->arp_queue);
3861da177e4SLinus Torvalds 	rwlock_init(&n->lock);
3870ed8ddf4SEric Dumazet 	seqlock_init(&n->ha_lock);
3881da177e4SLinus Torvalds 	n->updated	  = n->used = now;
3891da177e4SLinus Torvalds 	n->nud_state	  = NUD_NONE;
3901da177e4SLinus Torvalds 	n->output	  = neigh_blackhole;
391f6b72b62SDavid S. Miller 	seqlock_init(&n->hh.hh_lock);
3921da177e4SLinus Torvalds 	n->parms	  = neigh_parms_clone(&tbl->parms);
393e99e88a9SKees Cook 	timer_setup(&n->timer, neigh_timer_handler, 0);
3941da177e4SLinus Torvalds 
3951da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, allocs);
3961da177e4SLinus Torvalds 	n->tbl		  = tbl;
3979f237430SReshetova, Elena 	refcount_set(&n->refcnt, 1);
3981da177e4SLinus Torvalds 	n->dead		  = 1;
39958956317SDavid Ahern 	INIT_LIST_HEAD(&n->gc_list);
40058956317SDavid Ahern 
40158956317SDavid Ahern 	atomic_inc(&tbl->entries);
4021da177e4SLinus Torvalds out:
4031da177e4SLinus Torvalds 	return n;
4041da177e4SLinus Torvalds 
4051da177e4SLinus Torvalds out_entries:
40658956317SDavid Ahern 	if (!permanent)
40758956317SDavid Ahern 		atomic_dec(&tbl->gc_entries);
4081da177e4SLinus Torvalds 	goto out;
4091da177e4SLinus Torvalds }
4101da177e4SLinus Torvalds 
4112c2aba6cSDavid S. Miller static void neigh_get_hash_rnd(u32 *x)
4122c2aba6cSDavid S. Miller {
413b3d0f789SJason A. Donenfeld 	*x = get_random_u32() | 1;
4142c2aba6cSDavid S. Miller }
4152c2aba6cSDavid S. Miller 
416cd089336SDavid S. Miller static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
4171da177e4SLinus Torvalds {
418cd089336SDavid S. Miller 	size_t size = (1 << shift) * sizeof(struct neighbour *);
419d6bf7817SEric Dumazet 	struct neigh_hash_table *ret;
4206193d2beSEric Dumazet 	struct neighbour __rcu **buckets;
4212c2aba6cSDavid S. Miller 	int i;
4221da177e4SLinus Torvalds 
423d6bf7817SEric Dumazet 	ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
424d6bf7817SEric Dumazet 	if (!ret)
425d6bf7817SEric Dumazet 		return NULL;
426d6bf7817SEric Dumazet 	if (size <= PAGE_SIZE)
427d6bf7817SEric Dumazet 		buckets = kzalloc(size, GFP_ATOMIC);
428d6bf7817SEric Dumazet 	else
4296193d2beSEric Dumazet 		buckets = (struct neighbour __rcu **)
430d6bf7817SEric Dumazet 			  __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
431d6bf7817SEric Dumazet 					   get_order(size));
432d6bf7817SEric Dumazet 	if (!buckets) {
433d6bf7817SEric Dumazet 		kfree(ret);
434d6bf7817SEric Dumazet 		return NULL;
4351da177e4SLinus Torvalds 	}
4366193d2beSEric Dumazet 	ret->hash_buckets = buckets;
437cd089336SDavid S. Miller 	ret->hash_shift = shift;
4382c2aba6cSDavid S. Miller 	for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
4392c2aba6cSDavid S. Miller 		neigh_get_hash_rnd(&ret->hash_rnd[i]);
4401da177e4SLinus Torvalds 	return ret;
4411da177e4SLinus Torvalds }
4421da177e4SLinus Torvalds 
443d6bf7817SEric Dumazet static void neigh_hash_free_rcu(struct rcu_head *head)
4441da177e4SLinus Torvalds {
445d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = container_of(head,
446d6bf7817SEric Dumazet 						    struct neigh_hash_table,
447d6bf7817SEric Dumazet 						    rcu);
448cd089336SDavid S. Miller 	size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
4496193d2beSEric Dumazet 	struct neighbour __rcu **buckets = nht->hash_buckets;
4501da177e4SLinus Torvalds 
4511da177e4SLinus Torvalds 	if (size <= PAGE_SIZE)
452d6bf7817SEric Dumazet 		kfree(buckets);
4531da177e4SLinus Torvalds 	else
454d6bf7817SEric Dumazet 		free_pages((unsigned long)buckets, get_order(size));
455d6bf7817SEric Dumazet 	kfree(nht);
4561da177e4SLinus Torvalds }
4571da177e4SLinus Torvalds 
458d6bf7817SEric Dumazet static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
459cd089336SDavid S. Miller 						unsigned long new_shift)
4601da177e4SLinus Torvalds {
461d6bf7817SEric Dumazet 	unsigned int i, hash;
462d6bf7817SEric Dumazet 	struct neigh_hash_table *new_nht, *old_nht;
4631da177e4SLinus Torvalds 
4641da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, hash_grows);
4651da177e4SLinus Torvalds 
466d6bf7817SEric Dumazet 	old_nht = rcu_dereference_protected(tbl->nht,
467d6bf7817SEric Dumazet 					    lockdep_is_held(&tbl->lock));
468cd089336SDavid S. Miller 	new_nht = neigh_hash_alloc(new_shift);
469d6bf7817SEric Dumazet 	if (!new_nht)
470d6bf7817SEric Dumazet 		return old_nht;
4711da177e4SLinus Torvalds 
472cd089336SDavid S. Miller 	for (i = 0; i < (1 << old_nht->hash_shift); i++) {
4731da177e4SLinus Torvalds 		struct neighbour *n, *next;
4741da177e4SLinus Torvalds 
475767e97e1SEric Dumazet 		for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
476767e97e1SEric Dumazet 						   lockdep_is_held(&tbl->lock));
477d6bf7817SEric Dumazet 		     n != NULL;
478d6bf7817SEric Dumazet 		     n = next) {
479d6bf7817SEric Dumazet 			hash = tbl->hash(n->primary_key, n->dev,
480d6bf7817SEric Dumazet 					 new_nht->hash_rnd);
4811da177e4SLinus Torvalds 
482cd089336SDavid S. Miller 			hash >>= (32 - new_nht->hash_shift);
483767e97e1SEric Dumazet 			next = rcu_dereference_protected(n->next,
484767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock));
4851da177e4SLinus Torvalds 
486767e97e1SEric Dumazet 			rcu_assign_pointer(n->next,
487767e97e1SEric Dumazet 					   rcu_dereference_protected(
488767e97e1SEric Dumazet 						new_nht->hash_buckets[hash],
489767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
490767e97e1SEric Dumazet 			rcu_assign_pointer(new_nht->hash_buckets[hash], n);
4911da177e4SLinus Torvalds 		}
4921da177e4SLinus Torvalds 	}
4931da177e4SLinus Torvalds 
494d6bf7817SEric Dumazet 	rcu_assign_pointer(tbl->nht, new_nht);
495d6bf7817SEric Dumazet 	call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
496d6bf7817SEric Dumazet 	return new_nht;
4971da177e4SLinus Torvalds }
4981da177e4SLinus Torvalds 
4991da177e4SLinus Torvalds struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
5001da177e4SLinus Torvalds 			       struct net_device *dev)
5011da177e4SLinus Torvalds {
5021da177e4SLinus Torvalds 	struct neighbour *n;
5031da177e4SLinus Torvalds 
5041da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, lookups);
5051da177e4SLinus Torvalds 
506d6bf7817SEric Dumazet 	rcu_read_lock_bh();
50760395a20SEric W. Biederman 	n = __neigh_lookup_noref(tbl, pkey, dev);
50860395a20SEric W. Biederman 	if (n) {
5099f237430SReshetova, Elena 		if (!refcount_inc_not_zero(&n->refcnt))
510767e97e1SEric Dumazet 			n = NULL;
5111da177e4SLinus Torvalds 		NEIGH_CACHE_STAT_INC(tbl, hits);
5121da177e4SLinus Torvalds 	}
513767e97e1SEric Dumazet 
514d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
5151da177e4SLinus Torvalds 	return n;
5161da177e4SLinus Torvalds }
5170a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_lookup);
5181da177e4SLinus Torvalds 
519426b5303SEric W. Biederman struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
520426b5303SEric W. Biederman 				     const void *pkey)
5211da177e4SLinus Torvalds {
5221da177e4SLinus Torvalds 	struct neighbour *n;
52301ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
524bc4bf5f3SPavel Emelyanov 	u32 hash_val;
525d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
5261da177e4SLinus Torvalds 
5271da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, lookups);
5281da177e4SLinus Torvalds 
529d6bf7817SEric Dumazet 	rcu_read_lock_bh();
530d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
531cd089336SDavid S. Miller 	hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
532767e97e1SEric Dumazet 
533767e97e1SEric Dumazet 	for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
534767e97e1SEric Dumazet 	     n != NULL;
535767e97e1SEric Dumazet 	     n = rcu_dereference_bh(n->next)) {
536426b5303SEric W. Biederman 		if (!memcmp(n->primary_key, pkey, key_len) &&
537878628fbSYOSHIFUJI Hideaki 		    net_eq(dev_net(n->dev), net)) {
5389f237430SReshetova, Elena 			if (!refcount_inc_not_zero(&n->refcnt))
539767e97e1SEric Dumazet 				n = NULL;
5401da177e4SLinus Torvalds 			NEIGH_CACHE_STAT_INC(tbl, hits);
5411da177e4SLinus Torvalds 			break;
5421da177e4SLinus Torvalds 		}
5431da177e4SLinus Torvalds 	}
544767e97e1SEric Dumazet 
545d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
5461da177e4SLinus Torvalds 	return n;
5471da177e4SLinus Torvalds }
5480a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_lookup_nodev);
5491da177e4SLinus Torvalds 
55058956317SDavid Ahern static struct neighbour *___neigh_create(struct neigh_table *tbl,
55158956317SDavid Ahern 					 const void *pkey,
55258956317SDavid Ahern 					 struct net_device *dev,
55358956317SDavid Ahern 					 bool permanent, bool want_ref)
5541da177e4SLinus Torvalds {
55558956317SDavid Ahern 	struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev, permanent);
5561da177e4SLinus Torvalds 	u32 hash_val;
55701ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
5581da177e4SLinus Torvalds 	int error;
559d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
5601da177e4SLinus Torvalds 
5611da177e4SLinus Torvalds 	if (!n) {
5621da177e4SLinus Torvalds 		rc = ERR_PTR(-ENOBUFS);
5631da177e4SLinus Torvalds 		goto out;
5641da177e4SLinus Torvalds 	}
5651da177e4SLinus Torvalds 
5661da177e4SLinus Torvalds 	memcpy(n->primary_key, pkey, key_len);
5671da177e4SLinus Torvalds 	n->dev = dev;
5681da177e4SLinus Torvalds 	dev_hold(dev);
5691da177e4SLinus Torvalds 
5701da177e4SLinus Torvalds 	/* Protocol specific setup. */
5711da177e4SLinus Torvalds 	if (tbl->constructor &&	(error = tbl->constructor(n)) < 0) {
5721da177e4SLinus Torvalds 		rc = ERR_PTR(error);
5731da177e4SLinus Torvalds 		goto out_neigh_release;
5741da177e4SLinus Torvalds 	}
5751da177e4SLinus Torvalds 
576da6a8fa0SDavid Miller 	if (dev->netdev_ops->ndo_neigh_construct) {
577503eebc2SJiri Pirko 		error = dev->netdev_ops->ndo_neigh_construct(dev, n);
578da6a8fa0SDavid Miller 		if (error < 0) {
579da6a8fa0SDavid Miller 			rc = ERR_PTR(error);
580da6a8fa0SDavid Miller 			goto out_neigh_release;
581da6a8fa0SDavid Miller 		}
582da6a8fa0SDavid Miller 	}
583da6a8fa0SDavid Miller 
584447f2191SDavid S. Miller 	/* Device specific setup. */
585447f2191SDavid S. Miller 	if (n->parms->neigh_setup &&
586447f2191SDavid S. Miller 	    (error = n->parms->neigh_setup(n)) < 0) {
587447f2191SDavid S. Miller 		rc = ERR_PTR(error);
588447f2191SDavid S. Miller 		goto out_neigh_release;
589447f2191SDavid S. Miller 	}
590447f2191SDavid S. Miller 
5911f9248e5SJiri Pirko 	n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1);
5921da177e4SLinus Torvalds 
5931da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
594d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
595d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
5961da177e4SLinus Torvalds 
597cd089336SDavid S. Miller 	if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
598cd089336SDavid S. Miller 		nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
5991da177e4SLinus Torvalds 
600096b9854SJim Westfall 	hash_val = tbl->hash(n->primary_key, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
6011da177e4SLinus Torvalds 
6021da177e4SLinus Torvalds 	if (n->parms->dead) {
6031da177e4SLinus Torvalds 		rc = ERR_PTR(-EINVAL);
6041da177e4SLinus Torvalds 		goto out_tbl_unlock;
6051da177e4SLinus Torvalds 	}
6061da177e4SLinus Torvalds 
607767e97e1SEric Dumazet 	for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
608767e97e1SEric Dumazet 					    lockdep_is_held(&tbl->lock));
609767e97e1SEric Dumazet 	     n1 != NULL;
610767e97e1SEric Dumazet 	     n1 = rcu_dereference_protected(n1->next,
611767e97e1SEric Dumazet 			lockdep_is_held(&tbl->lock))) {
612096b9854SJim Westfall 		if (dev == n1->dev && !memcmp(n1->primary_key, n->primary_key, key_len)) {
613a263b309SDavid S. Miller 			if (want_ref)
6141da177e4SLinus Torvalds 				neigh_hold(n1);
6151da177e4SLinus Torvalds 			rc = n1;
6161da177e4SLinus Torvalds 			goto out_tbl_unlock;
6171da177e4SLinus Torvalds 		}
6181da177e4SLinus Torvalds 	}
6191da177e4SLinus Torvalds 
6201da177e4SLinus Torvalds 	n->dead = 0;
6218cc196d6SDavid Ahern 	if (!permanent)
6228cc196d6SDavid Ahern 		list_add_tail(&n->gc_list, &n->tbl->gc_list);
6238cc196d6SDavid Ahern 
624a263b309SDavid S. Miller 	if (want_ref)
6251da177e4SLinus Torvalds 		neigh_hold(n);
626767e97e1SEric Dumazet 	rcu_assign_pointer(n->next,
627767e97e1SEric Dumazet 			   rcu_dereference_protected(nht->hash_buckets[hash_val],
628767e97e1SEric Dumazet 						     lockdep_is_held(&tbl->lock)));
629767e97e1SEric Dumazet 	rcu_assign_pointer(nht->hash_buckets[hash_val], n);
6301da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
631d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is created\n", n);
6321da177e4SLinus Torvalds 	rc = n;
6331da177e4SLinus Torvalds out:
6341da177e4SLinus Torvalds 	return rc;
6351da177e4SLinus Torvalds out_tbl_unlock:
6361da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
6371da177e4SLinus Torvalds out_neigh_release:
6381da177e4SLinus Torvalds 	neigh_release(n);
6391da177e4SLinus Torvalds 	goto out;
6401da177e4SLinus Torvalds }
64158956317SDavid Ahern 
64258956317SDavid Ahern struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
64358956317SDavid Ahern 				 struct net_device *dev, bool want_ref)
64458956317SDavid Ahern {
64558956317SDavid Ahern 	return ___neigh_create(tbl, pkey, dev, false, want_ref);
64658956317SDavid Ahern }
647a263b309SDavid S. Miller EXPORT_SYMBOL(__neigh_create);
6481da177e4SLinus Torvalds 
64901ccdf12SAlexey Dobriyan static u32 pneigh_hash(const void *pkey, unsigned int key_len)
650fa86d322SPavel Emelyanov {
651fa86d322SPavel Emelyanov 	u32 hash_val = *(u32 *)(pkey + key_len - 4);
652fa86d322SPavel Emelyanov 	hash_val ^= (hash_val >> 16);
653fa86d322SPavel Emelyanov 	hash_val ^= hash_val >> 8;
654fa86d322SPavel Emelyanov 	hash_val ^= hash_val >> 4;
655fa86d322SPavel Emelyanov 	hash_val &= PNEIGH_HASHMASK;
656be01d655SYOSHIFUJI Hideaki 	return hash_val;
657fa86d322SPavel Emelyanov }
658fa86d322SPavel Emelyanov 
659be01d655SYOSHIFUJI Hideaki static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
660be01d655SYOSHIFUJI Hideaki 					      struct net *net,
661be01d655SYOSHIFUJI Hideaki 					      const void *pkey,
66201ccdf12SAlexey Dobriyan 					      unsigned int key_len,
663be01d655SYOSHIFUJI Hideaki 					      struct net_device *dev)
664be01d655SYOSHIFUJI Hideaki {
665be01d655SYOSHIFUJI Hideaki 	while (n) {
666be01d655SYOSHIFUJI Hideaki 		if (!memcmp(n->key, pkey, key_len) &&
667be01d655SYOSHIFUJI Hideaki 		    net_eq(pneigh_net(n), net) &&
668be01d655SYOSHIFUJI Hideaki 		    (n->dev == dev || !n->dev))
669fa86d322SPavel Emelyanov 			return n;
670be01d655SYOSHIFUJI Hideaki 		n = n->next;
671be01d655SYOSHIFUJI Hideaki 	}
672be01d655SYOSHIFUJI Hideaki 	return NULL;
673be01d655SYOSHIFUJI Hideaki }
674be01d655SYOSHIFUJI Hideaki 
675be01d655SYOSHIFUJI Hideaki struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
676be01d655SYOSHIFUJI Hideaki 		struct net *net, const void *pkey, struct net_device *dev)
677be01d655SYOSHIFUJI Hideaki {
67801ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
679be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
680be01d655SYOSHIFUJI Hideaki 
681be01d655SYOSHIFUJI Hideaki 	return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
682be01d655SYOSHIFUJI Hideaki 				 net, pkey, key_len, dev);
683fa86d322SPavel Emelyanov }
6840a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL_GPL(__pneigh_lookup);
685fa86d322SPavel Emelyanov 
686426b5303SEric W. Biederman struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
687426b5303SEric W. Biederman 				    struct net *net, const void *pkey,
6881da177e4SLinus Torvalds 				    struct net_device *dev, int creat)
6891da177e4SLinus Torvalds {
6901da177e4SLinus Torvalds 	struct pneigh_entry *n;
69101ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
692be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
6931da177e4SLinus Torvalds 
6941da177e4SLinus Torvalds 	read_lock_bh(&tbl->lock);
695be01d655SYOSHIFUJI Hideaki 	n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
696be01d655SYOSHIFUJI Hideaki 			      net, pkey, key_len, dev);
697be01d655SYOSHIFUJI Hideaki 	read_unlock_bh(&tbl->lock);
6981da177e4SLinus Torvalds 
699be01d655SYOSHIFUJI Hideaki 	if (n || !creat)
7001da177e4SLinus Torvalds 		goto out;
7011da177e4SLinus Torvalds 
7024ae28944SPavel Emelyanov 	ASSERT_RTNL();
7034ae28944SPavel Emelyanov 
7041da177e4SLinus Torvalds 	n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
7051da177e4SLinus Torvalds 	if (!n)
7061da177e4SLinus Torvalds 		goto out;
7071da177e4SLinus Torvalds 
708efd7ef1cSEric W. Biederman 	write_pnet(&n->net, net);
7091da177e4SLinus Torvalds 	memcpy(n->key, pkey, key_len);
7101da177e4SLinus Torvalds 	n->dev = dev;
7111da177e4SLinus Torvalds 	if (dev)
7121da177e4SLinus Torvalds 		dev_hold(dev);
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds 	if (tbl->pconstructor && tbl->pconstructor(n)) {
7151da177e4SLinus Torvalds 		if (dev)
7161da177e4SLinus Torvalds 			dev_put(dev);
7171da177e4SLinus Torvalds 		kfree(n);
7181da177e4SLinus Torvalds 		n = NULL;
7191da177e4SLinus Torvalds 		goto out;
7201da177e4SLinus Torvalds 	}
7211da177e4SLinus Torvalds 
7221da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
7231da177e4SLinus Torvalds 	n->next = tbl->phash_buckets[hash_val];
7241da177e4SLinus Torvalds 	tbl->phash_buckets[hash_val] = n;
7251da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
7261da177e4SLinus Torvalds out:
7271da177e4SLinus Torvalds 	return n;
7281da177e4SLinus Torvalds }
7290a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(pneigh_lookup);
7301da177e4SLinus Torvalds 
7311da177e4SLinus Torvalds 
732426b5303SEric W. Biederman int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
7331da177e4SLinus Torvalds 		  struct net_device *dev)
7341da177e4SLinus Torvalds {
7351da177e4SLinus Torvalds 	struct pneigh_entry *n, **np;
73601ccdf12SAlexey Dobriyan 	unsigned int key_len = tbl->key_len;
737be01d655SYOSHIFUJI Hideaki 	u32 hash_val = pneigh_hash(pkey, key_len);
7381da177e4SLinus Torvalds 
7391da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
7401da177e4SLinus Torvalds 	for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
7411da177e4SLinus Torvalds 	     np = &n->next) {
742426b5303SEric W. Biederman 		if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
743878628fbSYOSHIFUJI Hideaki 		    net_eq(pneigh_net(n), net)) {
7441da177e4SLinus Torvalds 			*np = n->next;
7451da177e4SLinus Torvalds 			write_unlock_bh(&tbl->lock);
7461da177e4SLinus Torvalds 			if (tbl->pdestructor)
7471da177e4SLinus Torvalds 				tbl->pdestructor(n);
7481da177e4SLinus Torvalds 			if (n->dev)
7491da177e4SLinus Torvalds 				dev_put(n->dev);
7501da177e4SLinus Torvalds 			kfree(n);
7511da177e4SLinus Torvalds 			return 0;
7521da177e4SLinus Torvalds 		}
7531da177e4SLinus Torvalds 	}
7541da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
7551da177e4SLinus Torvalds 	return -ENOENT;
7561da177e4SLinus Torvalds }
7571da177e4SLinus Torvalds 
75853b76cdfSWolfgang Bumiller static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
75953b76cdfSWolfgang Bumiller 				    struct net_device *dev)
7601da177e4SLinus Torvalds {
76153b76cdfSWolfgang Bumiller 	struct pneigh_entry *n, **np, *freelist = NULL;
7621da177e4SLinus Torvalds 	u32 h;
7631da177e4SLinus Torvalds 
7641da177e4SLinus Torvalds 	for (h = 0; h <= PNEIGH_HASHMASK; h++) {
7651da177e4SLinus Torvalds 		np = &tbl->phash_buckets[h];
7661da177e4SLinus Torvalds 		while ((n = *np) != NULL) {
7671da177e4SLinus Torvalds 			if (!dev || n->dev == dev) {
7681da177e4SLinus Torvalds 				*np = n->next;
76953b76cdfSWolfgang Bumiller 				n->next = freelist;
77053b76cdfSWolfgang Bumiller 				freelist = n;
77153b76cdfSWolfgang Bumiller 				continue;
77253b76cdfSWolfgang Bumiller 			}
77353b76cdfSWolfgang Bumiller 			np = &n->next;
77453b76cdfSWolfgang Bumiller 		}
77553b76cdfSWolfgang Bumiller 	}
77653b76cdfSWolfgang Bumiller 	write_unlock_bh(&tbl->lock);
77753b76cdfSWolfgang Bumiller 	while ((n = freelist)) {
77853b76cdfSWolfgang Bumiller 		freelist = n->next;
77953b76cdfSWolfgang Bumiller 		n->next = NULL;
7801da177e4SLinus Torvalds 		if (tbl->pdestructor)
7811da177e4SLinus Torvalds 			tbl->pdestructor(n);
7821da177e4SLinus Torvalds 		if (n->dev)
7831da177e4SLinus Torvalds 			dev_put(n->dev);
7841da177e4SLinus Torvalds 		kfree(n);
7851da177e4SLinus Torvalds 	}
7861da177e4SLinus Torvalds 	return -ENOENT;
7871da177e4SLinus Torvalds }
7881da177e4SLinus Torvalds 
78906f0511dSDenis V. Lunev static void neigh_parms_destroy(struct neigh_parms *parms);
79006f0511dSDenis V. Lunev 
79106f0511dSDenis V. Lunev static inline void neigh_parms_put(struct neigh_parms *parms)
79206f0511dSDenis V. Lunev {
7936343944bSReshetova, Elena 	if (refcount_dec_and_test(&parms->refcnt))
79406f0511dSDenis V. Lunev 		neigh_parms_destroy(parms);
79506f0511dSDenis V. Lunev }
7961da177e4SLinus Torvalds 
7971da177e4SLinus Torvalds /*
7981da177e4SLinus Torvalds  *	neighbour must already be out of the table;
7991da177e4SLinus Torvalds  *
8001da177e4SLinus Torvalds  */
8011da177e4SLinus Torvalds void neigh_destroy(struct neighbour *neigh)
8021da177e4SLinus Torvalds {
803da6a8fa0SDavid Miller 	struct net_device *dev = neigh->dev;
804da6a8fa0SDavid Miller 
8051da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
8061da177e4SLinus Torvalds 
8071da177e4SLinus Torvalds 	if (!neigh->dead) {
808e005d193SJoe Perches 		pr_warn("Destroying alive neighbour %p\n", neigh);
8091da177e4SLinus Torvalds 		dump_stack();
8101da177e4SLinus Torvalds 		return;
8111da177e4SLinus Torvalds 	}
8121da177e4SLinus Torvalds 
8131da177e4SLinus Torvalds 	if (neigh_del_timer(neigh))
814e005d193SJoe Perches 		pr_warn("Impossible event\n");
8151da177e4SLinus Torvalds 
816c9ab4d85SEric Dumazet 	write_lock_bh(&neigh->lock);
817c9ab4d85SEric Dumazet 	__skb_queue_purge(&neigh->arp_queue);
818c9ab4d85SEric Dumazet 	write_unlock_bh(&neigh->lock);
8198b5c171bSEric Dumazet 	neigh->arp_queue_len_bytes = 0;
8201da177e4SLinus Torvalds 
821447f2191SDavid S. Miller 	if (dev->netdev_ops->ndo_neigh_destroy)
822503eebc2SJiri Pirko 		dev->netdev_ops->ndo_neigh_destroy(dev, neigh);
823447f2191SDavid S. Miller 
824da6a8fa0SDavid Miller 	dev_put(dev);
8251da177e4SLinus Torvalds 	neigh_parms_put(neigh->parms);
8261da177e4SLinus Torvalds 
827d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is destroyed\n", neigh);
8281da177e4SLinus Torvalds 
8291da177e4SLinus Torvalds 	atomic_dec(&neigh->tbl->entries);
8305b8b0060SDavid Miller 	kfree_rcu(neigh, rcu);
8311da177e4SLinus Torvalds }
8320a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_destroy);
8331da177e4SLinus Torvalds 
8341da177e4SLinus Torvalds /* Neighbour state is suspicious;
8351da177e4SLinus Torvalds    disable fast path.
8361da177e4SLinus Torvalds 
8371da177e4SLinus Torvalds    Called with write_locked neigh.
8381da177e4SLinus Torvalds  */
8391da177e4SLinus Torvalds static void neigh_suspect(struct neighbour *neigh)
8401da177e4SLinus Torvalds {
841d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is suspected\n", neigh);
8421da177e4SLinus Torvalds 
8431da177e4SLinus Torvalds 	neigh->output = neigh->ops->output;
8441da177e4SLinus Torvalds }
8451da177e4SLinus Torvalds 
8461da177e4SLinus Torvalds /* Neighbour state is OK;
8471da177e4SLinus Torvalds    enable fast path.
8481da177e4SLinus Torvalds 
8491da177e4SLinus Torvalds    Called with write_locked neigh.
8501da177e4SLinus Torvalds  */
8511da177e4SLinus Torvalds static void neigh_connect(struct neighbour *neigh)
8521da177e4SLinus Torvalds {
853d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is connected\n", neigh);
8541da177e4SLinus Torvalds 
8551da177e4SLinus Torvalds 	neigh->output = neigh->ops->connected_output;
8561da177e4SLinus Torvalds }
8571da177e4SLinus Torvalds 
858e4c4e448SEric Dumazet static void neigh_periodic_work(struct work_struct *work)
8591da177e4SLinus Torvalds {
860e4c4e448SEric Dumazet 	struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
861767e97e1SEric Dumazet 	struct neighbour *n;
862767e97e1SEric Dumazet 	struct neighbour __rcu **np;
863e4c4e448SEric Dumazet 	unsigned int i;
864d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
8651da177e4SLinus Torvalds 
8661da177e4SLinus Torvalds 	NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
8671da177e4SLinus Torvalds 
868e4c4e448SEric Dumazet 	write_lock_bh(&tbl->lock);
869d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
870d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
8711da177e4SLinus Torvalds 
8721da177e4SLinus Torvalds 	/*
8731da177e4SLinus Torvalds 	 *	periodically recompute ReachableTime from random function
8741da177e4SLinus Torvalds 	 */
8751da177e4SLinus Torvalds 
876e4c4e448SEric Dumazet 	if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
8771da177e4SLinus Torvalds 		struct neigh_parms *p;
878e4c4e448SEric Dumazet 		tbl->last_rand = jiffies;
87975fbfd33SNicolas Dichtel 		list_for_each_entry(p, &tbl->parms_list, list)
8801da177e4SLinus Torvalds 			p->reachable_time =
8811f9248e5SJiri Pirko 				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
8821da177e4SLinus Torvalds 	}
8831da177e4SLinus Torvalds 
884feff9ab2SDuan Jiong 	if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
885feff9ab2SDuan Jiong 		goto out;
886feff9ab2SDuan Jiong 
887cd089336SDavid S. Miller 	for (i = 0 ; i < (1 << nht->hash_shift); i++) {
888d6bf7817SEric Dumazet 		np = &nht->hash_buckets[i];
8891da177e4SLinus Torvalds 
890767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
891767e97e1SEric Dumazet 				lockdep_is_held(&tbl->lock))) != NULL) {
8921da177e4SLinus Torvalds 			unsigned int state;
8931da177e4SLinus Torvalds 
8941da177e4SLinus Torvalds 			write_lock(&n->lock);
8951da177e4SLinus Torvalds 
8961da177e4SLinus Torvalds 			state = n->nud_state;
8979ce33e46SRoopa Prabhu 			if ((state & (NUD_PERMANENT | NUD_IN_TIMER)) ||
8989ce33e46SRoopa Prabhu 			    (n->flags & NTF_EXT_LEARNED)) {
8991da177e4SLinus Torvalds 				write_unlock(&n->lock);
9001da177e4SLinus Torvalds 				goto next_elt;
9011da177e4SLinus Torvalds 			}
9021da177e4SLinus Torvalds 
9031da177e4SLinus Torvalds 			if (time_before(n->used, n->confirmed))
9041da177e4SLinus Torvalds 				n->used = n->confirmed;
9051da177e4SLinus Torvalds 
9069f237430SReshetova, Elena 			if (refcount_read(&n->refcnt) == 1 &&
9071da177e4SLinus Torvalds 			    (state == NUD_FAILED ||
9081f9248e5SJiri Pirko 			     time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
9091da177e4SLinus Torvalds 				*np = n->next;
91058956317SDavid Ahern 				neigh_mark_dead(n);
9111da177e4SLinus Torvalds 				write_unlock(&n->lock);
9124f494554SThomas Graf 				neigh_cleanup_and_release(n);
9131da177e4SLinus Torvalds 				continue;
9141da177e4SLinus Torvalds 			}
9151da177e4SLinus Torvalds 			write_unlock(&n->lock);
9161da177e4SLinus Torvalds 
9171da177e4SLinus Torvalds next_elt:
9181da177e4SLinus Torvalds 			np = &n->next;
9191da177e4SLinus Torvalds 		}
920e4c4e448SEric Dumazet 		/*
921e4c4e448SEric Dumazet 		 * It's fine to release lock here, even if hash table
922e4c4e448SEric Dumazet 		 * grows while we are preempted.
923e4c4e448SEric Dumazet 		 */
924e4c4e448SEric Dumazet 		write_unlock_bh(&tbl->lock);
925e4c4e448SEric Dumazet 		cond_resched();
926e4c4e448SEric Dumazet 		write_lock_bh(&tbl->lock);
92784338a6cSMichel Machado 		nht = rcu_dereference_protected(tbl->nht,
92884338a6cSMichel Machado 						lockdep_is_held(&tbl->lock));
929e4c4e448SEric Dumazet 	}
9302724680bSYOSHIFUJI Hideaki / 吉藤英明 out:
9311f9248e5SJiri Pirko 	/* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks.
9321f9248e5SJiri Pirko 	 * ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2
9331f9248e5SJiri Pirko 	 * BASE_REACHABLE_TIME.
9341da177e4SLinus Torvalds 	 */
935f618002bSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
9361f9248e5SJiri Pirko 			      NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1);
937e4c4e448SEric Dumazet 	write_unlock_bh(&tbl->lock);
9381da177e4SLinus Torvalds }
9391da177e4SLinus Torvalds 
9401da177e4SLinus Torvalds static __inline__ int neigh_max_probes(struct neighbour *n)
9411da177e4SLinus Torvalds {
9421da177e4SLinus Torvalds 	struct neigh_parms *p = n->parms;
9438da86466SYOSHIFUJI Hideaki/吉藤英明 	return NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) +
9448da86466SYOSHIFUJI Hideaki/吉藤英明 	       (n->nud_state & NUD_PROBE ? NEIGH_VAR(p, MCAST_REPROBES) :
9458da86466SYOSHIFUJI Hideaki/吉藤英明 	        NEIGH_VAR(p, MCAST_PROBES));
9461da177e4SLinus Torvalds }
9471da177e4SLinus Torvalds 
9485ef12d98STimo Teras static void neigh_invalidate(struct neighbour *neigh)
9490a141509SEric Dumazet 	__releases(neigh->lock)
9500a141509SEric Dumazet 	__acquires(neigh->lock)
9515ef12d98STimo Teras {
9525ef12d98STimo Teras 	struct sk_buff *skb;
9535ef12d98STimo Teras 
9545ef12d98STimo Teras 	NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
955d5d427cdSJoe Perches 	neigh_dbg(2, "neigh %p is failed\n", neigh);
9565ef12d98STimo Teras 	neigh->updated = jiffies;
9575ef12d98STimo Teras 
9585ef12d98STimo Teras 	/* It is very thin place. report_unreachable is very complicated
9595ef12d98STimo Teras 	   routine. Particularly, it can hit the same neighbour entry!
9605ef12d98STimo Teras 
9615ef12d98STimo Teras 	   So that, we try to be accurate and avoid dead loop. --ANK
9625ef12d98STimo Teras 	 */
9635ef12d98STimo Teras 	while (neigh->nud_state == NUD_FAILED &&
9645ef12d98STimo Teras 	       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
9655ef12d98STimo Teras 		write_unlock(&neigh->lock);
9665ef12d98STimo Teras 		neigh->ops->error_report(neigh, skb);
9675ef12d98STimo Teras 		write_lock(&neigh->lock);
9685ef12d98STimo Teras 	}
969c9ab4d85SEric Dumazet 	__skb_queue_purge(&neigh->arp_queue);
9708b5c171bSEric Dumazet 	neigh->arp_queue_len_bytes = 0;
9715ef12d98STimo Teras }
9725ef12d98STimo Teras 
973cd28ca0aSEric Dumazet static void neigh_probe(struct neighbour *neigh)
974cd28ca0aSEric Dumazet 	__releases(neigh->lock)
975cd28ca0aSEric Dumazet {
9764ed377e3SHannes Frederic Sowa 	struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);
977cd28ca0aSEric Dumazet 	/* keep skb alive even if arp_queue overflows */
978cd28ca0aSEric Dumazet 	if (skb)
97919125c1aSMartin Zhang 		skb = skb_clone(skb, GFP_ATOMIC);
980cd28ca0aSEric Dumazet 	write_unlock(&neigh->lock);
98148481c8fSEric Dumazet 	if (neigh->ops->solicit)
982cd28ca0aSEric Dumazet 		neigh->ops->solicit(neigh, skb);
983cd28ca0aSEric Dumazet 	atomic_inc(&neigh->probes);
984cd28ca0aSEric Dumazet 	kfree_skb(skb);
985cd28ca0aSEric Dumazet }
986cd28ca0aSEric Dumazet 
9871da177e4SLinus Torvalds /* Called when a timer expires for a neighbour entry. */
9881da177e4SLinus Torvalds 
989e99e88a9SKees Cook static void neigh_timer_handler(struct timer_list *t)
9901da177e4SLinus Torvalds {
9911da177e4SLinus Torvalds 	unsigned long now, next;
992e99e88a9SKees Cook 	struct neighbour *neigh = from_timer(neigh, t, timer);
99395c96174SEric Dumazet 	unsigned int state;
9941da177e4SLinus Torvalds 	int notify = 0;
9951da177e4SLinus Torvalds 
9961da177e4SLinus Torvalds 	write_lock(&neigh->lock);
9971da177e4SLinus Torvalds 
9981da177e4SLinus Torvalds 	state = neigh->nud_state;
9991da177e4SLinus Torvalds 	now = jiffies;
10001da177e4SLinus Torvalds 	next = now + HZ;
10011da177e4SLinus Torvalds 
1002045f7b3bSDavid S. Miller 	if (!(state & NUD_IN_TIMER))
10031da177e4SLinus Torvalds 		goto out;
10041da177e4SLinus Torvalds 
10051da177e4SLinus Torvalds 	if (state & NUD_REACHABLE) {
10061da177e4SLinus Torvalds 		if (time_before_eq(now,
10071da177e4SLinus Torvalds 				   neigh->confirmed + neigh->parms->reachable_time)) {
1008d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is still alive\n", neigh);
10091da177e4SLinus Torvalds 			next = neigh->confirmed + neigh->parms->reachable_time;
10101da177e4SLinus Torvalds 		} else if (time_before_eq(now,
10111f9248e5SJiri Pirko 					  neigh->used +
10121f9248e5SJiri Pirko 					  NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
1013d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is delayed\n", neigh);
10141da177e4SLinus Torvalds 			neigh->nud_state = NUD_DELAY;
1015955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10161da177e4SLinus Torvalds 			neigh_suspect(neigh);
10171f9248e5SJiri Pirko 			next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME);
10181da177e4SLinus Torvalds 		} else {
1019d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is suspected\n", neigh);
10201da177e4SLinus Torvalds 			neigh->nud_state = NUD_STALE;
1021955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10221da177e4SLinus Torvalds 			neigh_suspect(neigh);
10238d71740cSTom Tucker 			notify = 1;
10241da177e4SLinus Torvalds 		}
10251da177e4SLinus Torvalds 	} else if (state & NUD_DELAY) {
10261da177e4SLinus Torvalds 		if (time_before_eq(now,
10271f9248e5SJiri Pirko 				   neigh->confirmed +
10281f9248e5SJiri Pirko 				   NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
1029d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is now reachable\n", neigh);
10301da177e4SLinus Torvalds 			neigh->nud_state = NUD_REACHABLE;
1031955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10321da177e4SLinus Torvalds 			neigh_connect(neigh);
10338d71740cSTom Tucker 			notify = 1;
10341da177e4SLinus Torvalds 			next = neigh->confirmed + neigh->parms->reachable_time;
10351da177e4SLinus Torvalds 		} else {
1036d5d427cdSJoe Perches 			neigh_dbg(2, "neigh %p is probed\n", neigh);
10371da177e4SLinus Torvalds 			neigh->nud_state = NUD_PROBE;
1038955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
10391da177e4SLinus Torvalds 			atomic_set(&neigh->probes, 0);
1040765c9c63SErik Kline 			notify = 1;
10411f9248e5SJiri Pirko 			next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
10421da177e4SLinus Torvalds 		}
10431da177e4SLinus Torvalds 	} else {
10441da177e4SLinus Torvalds 		/* NUD_PROBE|NUD_INCOMPLETE */
10451f9248e5SJiri Pirko 		next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
10461da177e4SLinus Torvalds 	}
10471da177e4SLinus Torvalds 
10481da177e4SLinus Torvalds 	if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
10491da177e4SLinus Torvalds 	    atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
10501da177e4SLinus Torvalds 		neigh->nud_state = NUD_FAILED;
10511da177e4SLinus Torvalds 		notify = 1;
10525ef12d98STimo Teras 		neigh_invalidate(neigh);
10535e2c21dcSDuan Jiong 		goto out;
10541da177e4SLinus Torvalds 	}
10551da177e4SLinus Torvalds 
10561da177e4SLinus Torvalds 	if (neigh->nud_state & NUD_IN_TIMER) {
10571da177e4SLinus Torvalds 		if (time_before(next, jiffies + HZ/2))
10581da177e4SLinus Torvalds 			next = jiffies + HZ/2;
10596fb9974fSHerbert Xu 		if (!mod_timer(&neigh->timer, next))
10606fb9974fSHerbert Xu 			neigh_hold(neigh);
10611da177e4SLinus Torvalds 	}
10621da177e4SLinus Torvalds 	if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
1063cd28ca0aSEric Dumazet 		neigh_probe(neigh);
10649ff56607SDavid S. Miller 	} else {
10651da177e4SLinus Torvalds out:
10661da177e4SLinus Torvalds 		write_unlock(&neigh->lock);
10679ff56607SDavid S. Miller 	}
10681da177e4SLinus Torvalds 
1069d961db35SThomas Graf 	if (notify)
10707b8f7a40SRoopa Prabhu 		neigh_update_notify(neigh, 0);
1071d961db35SThomas Graf 
10721da177e4SLinus Torvalds 	neigh_release(neigh);
10731da177e4SLinus Torvalds }
10741da177e4SLinus Torvalds 
10751da177e4SLinus Torvalds int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
10761da177e4SLinus Torvalds {
10771da177e4SLinus Torvalds 	int rc;
1078cd28ca0aSEric Dumazet 	bool immediate_probe = false;
10791da177e4SLinus Torvalds 
10801da177e4SLinus Torvalds 	write_lock_bh(&neigh->lock);
10811da177e4SLinus Torvalds 
10821da177e4SLinus Torvalds 	rc = 0;
10831da177e4SLinus Torvalds 	if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
10841da177e4SLinus Torvalds 		goto out_unlock_bh;
10852c51a97fSJulian Anastasov 	if (neigh->dead)
10862c51a97fSJulian Anastasov 		goto out_dead;
10871da177e4SLinus Torvalds 
10881da177e4SLinus Torvalds 	if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
10891f9248e5SJiri Pirko 		if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
10901f9248e5SJiri Pirko 		    NEIGH_VAR(neigh->parms, APP_PROBES)) {
1091cd28ca0aSEric Dumazet 			unsigned long next, now = jiffies;
1092cd28ca0aSEric Dumazet 
10931f9248e5SJiri Pirko 			atomic_set(&neigh->probes,
10941f9248e5SJiri Pirko 				   NEIGH_VAR(neigh->parms, UCAST_PROBES));
10951da177e4SLinus Torvalds 			neigh->nud_state     = NUD_INCOMPLETE;
1096cd28ca0aSEric Dumazet 			neigh->updated = now;
10971f9248e5SJiri Pirko 			next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
10981f9248e5SJiri Pirko 					 HZ/2);
1099cd28ca0aSEric Dumazet 			neigh_add_timer(neigh, next);
1100cd28ca0aSEric Dumazet 			immediate_probe = true;
11011da177e4SLinus Torvalds 		} else {
11021da177e4SLinus Torvalds 			neigh->nud_state = NUD_FAILED;
1103955aaa2fSYOSHIFUJI Hideaki 			neigh->updated = jiffies;
11041da177e4SLinus Torvalds 			write_unlock_bh(&neigh->lock);
11051da177e4SLinus Torvalds 
11061da177e4SLinus Torvalds 			kfree_skb(skb);
11071da177e4SLinus Torvalds 			return 1;
11081da177e4SLinus Torvalds 		}
11091da177e4SLinus Torvalds 	} else if (neigh->nud_state & NUD_STALE) {
1110d5d427cdSJoe Perches 		neigh_dbg(2, "neigh %p is delayed\n", neigh);
11111da177e4SLinus Torvalds 		neigh->nud_state = NUD_DELAY;
1112955aaa2fSYOSHIFUJI Hideaki 		neigh->updated = jiffies;
11131f9248e5SJiri Pirko 		neigh_add_timer(neigh, jiffies +
11141f9248e5SJiri Pirko 				NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME));
11151da177e4SLinus Torvalds 	}
11161da177e4SLinus Torvalds 
11171da177e4SLinus Torvalds 	if (neigh->nud_state == NUD_INCOMPLETE) {
11181da177e4SLinus Torvalds 		if (skb) {
11198b5c171bSEric Dumazet 			while (neigh->arp_queue_len_bytes + skb->truesize >
11201f9248e5SJiri Pirko 			       NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) {
11211da177e4SLinus Torvalds 				struct sk_buff *buff;
11228b5c171bSEric Dumazet 
1123f72051b0SDavid S. Miller 				buff = __skb_dequeue(&neigh->arp_queue);
11248b5c171bSEric Dumazet 				if (!buff)
11258b5c171bSEric Dumazet 					break;
11268b5c171bSEric Dumazet 				neigh->arp_queue_len_bytes -= buff->truesize;
11271da177e4SLinus Torvalds 				kfree_skb(buff);
11289a6d276eSNeil Horman 				NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
11291da177e4SLinus Torvalds 			}
1130a4731138SEric Dumazet 			skb_dst_force(skb);
11311da177e4SLinus Torvalds 			__skb_queue_tail(&neigh->arp_queue, skb);
11328b5c171bSEric Dumazet 			neigh->arp_queue_len_bytes += skb->truesize;
11331da177e4SLinus Torvalds 		}
11341da177e4SLinus Torvalds 		rc = 1;
11351da177e4SLinus Torvalds 	}
11361da177e4SLinus Torvalds out_unlock_bh:
1137cd28ca0aSEric Dumazet 	if (immediate_probe)
1138cd28ca0aSEric Dumazet 		neigh_probe(neigh);
1139cd28ca0aSEric Dumazet 	else
1140cd28ca0aSEric Dumazet 		write_unlock(&neigh->lock);
1141cd28ca0aSEric Dumazet 	local_bh_enable();
11421da177e4SLinus Torvalds 	return rc;
11432c51a97fSJulian Anastasov 
11442c51a97fSJulian Anastasov out_dead:
11452c51a97fSJulian Anastasov 	if (neigh->nud_state & NUD_STALE)
11462c51a97fSJulian Anastasov 		goto out_unlock_bh;
11472c51a97fSJulian Anastasov 	write_unlock_bh(&neigh->lock);
11482c51a97fSJulian Anastasov 	kfree_skb(skb);
11492c51a97fSJulian Anastasov 	return 1;
11501da177e4SLinus Torvalds }
11510a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(__neigh_event_send);
11521da177e4SLinus Torvalds 
1153f6b72b62SDavid S. Miller static void neigh_update_hhs(struct neighbour *neigh)
11541da177e4SLinus Torvalds {
11551da177e4SLinus Torvalds 	struct hh_cache *hh;
11563b04dddeSStephen Hemminger 	void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
115791a72a70SDoug Kehn 		= NULL;
115891a72a70SDoug Kehn 
115991a72a70SDoug Kehn 	if (neigh->dev->header_ops)
116091a72a70SDoug Kehn 		update = neigh->dev->header_ops->cache_update;
11611da177e4SLinus Torvalds 
11621da177e4SLinus Torvalds 	if (update) {
1163f6b72b62SDavid S. Miller 		hh = &neigh->hh;
1164f6b72b62SDavid S. Miller 		if (hh->hh_len) {
11653644f0ceSStephen Hemminger 			write_seqlock_bh(&hh->hh_lock);
11661da177e4SLinus Torvalds 			update(hh, neigh->dev, neigh->ha);
11673644f0ceSStephen Hemminger 			write_sequnlock_bh(&hh->hh_lock);
11681da177e4SLinus Torvalds 		}
11691da177e4SLinus Torvalds 	}
11701da177e4SLinus Torvalds }
11711da177e4SLinus Torvalds 
11721da177e4SLinus Torvalds 
11731da177e4SLinus Torvalds 
11741da177e4SLinus Torvalds /* Generic update routine.
11751da177e4SLinus Torvalds    -- lladdr is new lladdr or NULL, if it is not supplied.
11761da177e4SLinus Torvalds    -- new    is new state.
11771da177e4SLinus Torvalds    -- flags
11781da177e4SLinus Torvalds 	NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
11791da177e4SLinus Torvalds 				if it is different.
11801da177e4SLinus Torvalds 	NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
11811da177e4SLinus Torvalds 				lladdr instead of overriding it
11821da177e4SLinus Torvalds 				if it is different.
11831da177e4SLinus Torvalds 	NEIGH_UPDATE_F_ADMIN	means that the change is administrative.
11841da177e4SLinus Torvalds 
11851da177e4SLinus Torvalds 	NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
11861da177e4SLinus Torvalds 				NTF_ROUTER flag.
11871da177e4SLinus Torvalds 	NEIGH_UPDATE_F_ISROUTER	indicates if the neighbour is known as
11881da177e4SLinus Torvalds 				a router.
11891da177e4SLinus Torvalds 
11901da177e4SLinus Torvalds    Caller MUST hold reference count on the entry.
11911da177e4SLinus Torvalds  */
11921da177e4SLinus Torvalds 
11937a35a50dSDavid Ahern static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
11947a35a50dSDavid Ahern 			  u8 new, u32 flags, u32 nlmsg_pid,
11957a35a50dSDavid Ahern 			  struct netlink_ext_ack *extack)
11961da177e4SLinus Torvalds {
11971da177e4SLinus Torvalds 	u8 old;
11981da177e4SLinus Torvalds 	int err;
11991da177e4SLinus Torvalds 	int notify = 0;
12001da177e4SLinus Torvalds 	struct net_device *dev;
12011da177e4SLinus Torvalds 	int update_isrouter = 0;
12021da177e4SLinus Torvalds 
12031da177e4SLinus Torvalds 	write_lock_bh(&neigh->lock);
12041da177e4SLinus Torvalds 
12051da177e4SLinus Torvalds 	dev    = neigh->dev;
12061da177e4SLinus Torvalds 	old    = neigh->nud_state;
12071da177e4SLinus Torvalds 	err    = -EPERM;
12081da177e4SLinus Torvalds 
12091da177e4SLinus Torvalds 	if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
12101da177e4SLinus Torvalds 	    (old & (NUD_NOARP | NUD_PERMANENT)))
12111da177e4SLinus Torvalds 		goto out;
12127a35a50dSDavid Ahern 	if (neigh->dead) {
12137a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Neighbor entry is now dead");
12142c51a97fSJulian Anastasov 		goto out;
12157a35a50dSDavid Ahern 	}
12161da177e4SLinus Torvalds 
12179ce33e46SRoopa Prabhu 	neigh_update_ext_learned(neigh, flags, &notify);
12189ce33e46SRoopa Prabhu 
12191da177e4SLinus Torvalds 	if (!(new & NUD_VALID)) {
12201da177e4SLinus Torvalds 		neigh_del_timer(neigh);
12211da177e4SLinus Torvalds 		if (old & NUD_CONNECTED)
12221da177e4SLinus Torvalds 			neigh_suspect(neigh);
12239c29a2f5SDavid Ahern 		neigh->nud_state = new;
12241da177e4SLinus Torvalds 		err = 0;
12251da177e4SLinus Torvalds 		notify = old & NUD_VALID;
1226d2fb4fb8SRoopa Prabhu 		if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
12275ef12d98STimo Teras 		    (new & NUD_FAILED)) {
12285ef12d98STimo Teras 			neigh_invalidate(neigh);
12295ef12d98STimo Teras 			notify = 1;
12305ef12d98STimo Teras 		}
12311da177e4SLinus Torvalds 		goto out;
12321da177e4SLinus Torvalds 	}
12331da177e4SLinus Torvalds 
12341da177e4SLinus Torvalds 	/* Compare new lladdr with cached one */
12351da177e4SLinus Torvalds 	if (!dev->addr_len) {
12361da177e4SLinus Torvalds 		/* First case: device needs no address. */
12371da177e4SLinus Torvalds 		lladdr = neigh->ha;
12381da177e4SLinus Torvalds 	} else if (lladdr) {
12391da177e4SLinus Torvalds 		/* The second case: if something is already cached
12401da177e4SLinus Torvalds 		   and a new address is proposed:
12411da177e4SLinus Torvalds 		   - compare new & old
12421da177e4SLinus Torvalds 		   - if they are different, check override flag
12431da177e4SLinus Torvalds 		 */
12441da177e4SLinus Torvalds 		if ((old & NUD_VALID) &&
12451da177e4SLinus Torvalds 		    !memcmp(lladdr, neigh->ha, dev->addr_len))
12461da177e4SLinus Torvalds 			lladdr = neigh->ha;
12471da177e4SLinus Torvalds 	} else {
12481da177e4SLinus Torvalds 		/* No address is supplied; if we know something,
12491da177e4SLinus Torvalds 		   use it, otherwise discard the request.
12501da177e4SLinus Torvalds 		 */
12511da177e4SLinus Torvalds 		err = -EINVAL;
12527a35a50dSDavid Ahern 		if (!(old & NUD_VALID)) {
12537a35a50dSDavid Ahern 			NL_SET_ERR_MSG(extack, "No link layer address given");
12541da177e4SLinus Torvalds 			goto out;
12557a35a50dSDavid Ahern 		}
12561da177e4SLinus Torvalds 		lladdr = neigh->ha;
12571da177e4SLinus Torvalds 	}
12581da177e4SLinus Torvalds 
1259f0e0d044SVasily Khoruzhick 	/* Update confirmed timestamp for neighbour entry after we
1260f0e0d044SVasily Khoruzhick 	 * received ARP packet even if it doesn't change IP to MAC binding.
1261f0e0d044SVasily Khoruzhick 	 */
1262f0e0d044SVasily Khoruzhick 	if (new & NUD_CONNECTED)
1263f0e0d044SVasily Khoruzhick 		neigh->confirmed = jiffies;
1264f0e0d044SVasily Khoruzhick 
12651da177e4SLinus Torvalds 	/* If entry was valid and address is not changed,
12661da177e4SLinus Torvalds 	   do not change entry state, if new one is STALE.
12671da177e4SLinus Torvalds 	 */
12681da177e4SLinus Torvalds 	err = 0;
12691da177e4SLinus Torvalds 	update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
12701da177e4SLinus Torvalds 	if (old & NUD_VALID) {
12711da177e4SLinus Torvalds 		if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
12721da177e4SLinus Torvalds 			update_isrouter = 0;
12731da177e4SLinus Torvalds 			if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
12741da177e4SLinus Torvalds 			    (old & NUD_CONNECTED)) {
12751da177e4SLinus Torvalds 				lladdr = neigh->ha;
12761da177e4SLinus Torvalds 				new = NUD_STALE;
12771da177e4SLinus Torvalds 			} else
12781da177e4SLinus Torvalds 				goto out;
12791da177e4SLinus Torvalds 		} else {
12800e7bbcc1SJulian Anastasov 			if (lladdr == neigh->ha && new == NUD_STALE &&
12810e7bbcc1SJulian Anastasov 			    !(flags & NEIGH_UPDATE_F_ADMIN))
12821da177e4SLinus Torvalds 				new = old;
12831da177e4SLinus Torvalds 		}
12841da177e4SLinus Torvalds 	}
12851da177e4SLinus Torvalds 
1286f0e0d044SVasily Khoruzhick 	/* Update timestamp only once we know we will make a change to the
128777d71233SIhar Hrachyshka 	 * neighbour entry. Otherwise we risk to move the locktime window with
128877d71233SIhar Hrachyshka 	 * noop updates and ignore relevant ARP updates.
128977d71233SIhar Hrachyshka 	 */
1290f0e0d044SVasily Khoruzhick 	if (new != old || lladdr != neigh->ha)
129177d71233SIhar Hrachyshka 		neigh->updated = jiffies;
129277d71233SIhar Hrachyshka 
12931da177e4SLinus Torvalds 	if (new != old) {
12941da177e4SLinus Torvalds 		neigh_del_timer(neigh);
1295765c9c63SErik Kline 		if (new & NUD_PROBE)
1296765c9c63SErik Kline 			atomic_set(&neigh->probes, 0);
1297a43d8994SPavel Emelyanov 		if (new & NUD_IN_TIMER)
1298667347f1SDavid S. Miller 			neigh_add_timer(neigh, (jiffies +
12991da177e4SLinus Torvalds 						((new & NUD_REACHABLE) ?
1300667347f1SDavid S. Miller 						 neigh->parms->reachable_time :
1301667347f1SDavid S. Miller 						 0)));
13029c29a2f5SDavid Ahern 		neigh->nud_state = new;
130353385d2dSBob Gilligan 		notify = 1;
13041da177e4SLinus Torvalds 	}
13051da177e4SLinus Torvalds 
13061da177e4SLinus Torvalds 	if (lladdr != neigh->ha) {
13070ed8ddf4SEric Dumazet 		write_seqlock(&neigh->ha_lock);
13081da177e4SLinus Torvalds 		memcpy(&neigh->ha, lladdr, dev->addr_len);
13090ed8ddf4SEric Dumazet 		write_sequnlock(&neigh->ha_lock);
13101da177e4SLinus Torvalds 		neigh_update_hhs(neigh);
13111da177e4SLinus Torvalds 		if (!(new & NUD_CONNECTED))
13121da177e4SLinus Torvalds 			neigh->confirmed = jiffies -
13131f9248e5SJiri Pirko 				      (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1);
13141da177e4SLinus Torvalds 		notify = 1;
13151da177e4SLinus Torvalds 	}
13161da177e4SLinus Torvalds 	if (new == old)
13171da177e4SLinus Torvalds 		goto out;
13181da177e4SLinus Torvalds 	if (new & NUD_CONNECTED)
13191da177e4SLinus Torvalds 		neigh_connect(neigh);
13201da177e4SLinus Torvalds 	else
13211da177e4SLinus Torvalds 		neigh_suspect(neigh);
13221da177e4SLinus Torvalds 	if (!(old & NUD_VALID)) {
13231da177e4SLinus Torvalds 		struct sk_buff *skb;
13241da177e4SLinus Torvalds 
13251da177e4SLinus Torvalds 		/* Again: avoid dead loop if something went wrong */
13261da177e4SLinus Torvalds 
13271da177e4SLinus Torvalds 		while (neigh->nud_state & NUD_VALID &&
13281da177e4SLinus Torvalds 		       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
132969cce1d1SDavid S. Miller 			struct dst_entry *dst = skb_dst(skb);
133069cce1d1SDavid S. Miller 			struct neighbour *n2, *n1 = neigh;
13311da177e4SLinus Torvalds 			write_unlock_bh(&neigh->lock);
1332e049f288Sroy.qing.li@gmail.com 
1333e049f288Sroy.qing.li@gmail.com 			rcu_read_lock();
133413a43d94SDavid S. Miller 
133513a43d94SDavid S. Miller 			/* Why not just use 'neigh' as-is?  The problem is that
133613a43d94SDavid S. Miller 			 * things such as shaper, eql, and sch_teql can end up
133713a43d94SDavid S. Miller 			 * using alternative, different, neigh objects to output
133813a43d94SDavid S. Miller 			 * the packet in the output path.  So what we need to do
133913a43d94SDavid S. Miller 			 * here is re-lookup the top-level neigh in the path so
134013a43d94SDavid S. Miller 			 * we can reinject the packet there.
134113a43d94SDavid S. Miller 			 */
134213a43d94SDavid S. Miller 			n2 = NULL;
134313a43d94SDavid S. Miller 			if (dst) {
134413a43d94SDavid S. Miller 				n2 = dst_neigh_lookup_skb(dst, skb);
134513a43d94SDavid S. Miller 				if (n2)
134669cce1d1SDavid S. Miller 					n1 = n2;
134713a43d94SDavid S. Miller 			}
13488f40b161SDavid S. Miller 			n1->output(n1, skb);
134913a43d94SDavid S. Miller 			if (n2)
135013a43d94SDavid S. Miller 				neigh_release(n2);
1351e049f288Sroy.qing.li@gmail.com 			rcu_read_unlock();
1352e049f288Sroy.qing.li@gmail.com 
13531da177e4SLinus Torvalds 			write_lock_bh(&neigh->lock);
13541da177e4SLinus Torvalds 		}
1355c9ab4d85SEric Dumazet 		__skb_queue_purge(&neigh->arp_queue);
13568b5c171bSEric Dumazet 		neigh->arp_queue_len_bytes = 0;
13571da177e4SLinus Torvalds 	}
13581da177e4SLinus Torvalds out:
1359fc6e8073SRoopa Prabhu 	if (update_isrouter)
1360fc6e8073SRoopa Prabhu 		neigh_update_is_router(neigh, flags, &notify);
13611da177e4SLinus Torvalds 	write_unlock_bh(&neigh->lock);
13628d71740cSTom Tucker 
13639c29a2f5SDavid Ahern 	if ((new ^ old) & NUD_PERMANENT)
13649c29a2f5SDavid Ahern 		neigh_update_gc_list(neigh);
13659c29a2f5SDavid Ahern 
13668d71740cSTom Tucker 	if (notify)
13677b8f7a40SRoopa Prabhu 		neigh_update_notify(neigh, nlmsg_pid);
1368d961db35SThomas Graf 
13691da177e4SLinus Torvalds 	return err;
13701da177e4SLinus Torvalds }
13717a35a50dSDavid Ahern 
13727a35a50dSDavid Ahern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
13737a35a50dSDavid Ahern 		 u32 flags, u32 nlmsg_pid)
13747a35a50dSDavid Ahern {
13757a35a50dSDavid Ahern 	return __neigh_update(neigh, lladdr, new, flags, nlmsg_pid, NULL);
13767a35a50dSDavid Ahern }
13770a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_update);
13781da177e4SLinus Torvalds 
13797e980569SJiri Benc /* Update the neigh to listen temporarily for probe responses, even if it is
13807e980569SJiri Benc  * in a NUD_FAILED state. The caller has to hold neigh->lock for writing.
13817e980569SJiri Benc  */
13827e980569SJiri Benc void __neigh_set_probe_once(struct neighbour *neigh)
13837e980569SJiri Benc {
13842c51a97fSJulian Anastasov 	if (neigh->dead)
13852c51a97fSJulian Anastasov 		return;
13867e980569SJiri Benc 	neigh->updated = jiffies;
13877e980569SJiri Benc 	if (!(neigh->nud_state & NUD_FAILED))
13887e980569SJiri Benc 		return;
13892176d5d4SDuan Jiong 	neigh->nud_state = NUD_INCOMPLETE;
13902176d5d4SDuan Jiong 	atomic_set(&neigh->probes, neigh_max_probes(neigh));
13917e980569SJiri Benc 	neigh_add_timer(neigh,
13927e980569SJiri Benc 			jiffies + NEIGH_VAR(neigh->parms, RETRANS_TIME));
13937e980569SJiri Benc }
13947e980569SJiri Benc EXPORT_SYMBOL(__neigh_set_probe_once);
13957e980569SJiri Benc 
13961da177e4SLinus Torvalds struct neighbour *neigh_event_ns(struct neigh_table *tbl,
13971da177e4SLinus Torvalds 				 u8 *lladdr, void *saddr,
13981da177e4SLinus Torvalds 				 struct net_device *dev)
13991da177e4SLinus Torvalds {
14001da177e4SLinus Torvalds 	struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
14011da177e4SLinus Torvalds 						 lladdr || !dev->addr_len);
14021da177e4SLinus Torvalds 	if (neigh)
14031da177e4SLinus Torvalds 		neigh_update(neigh, lladdr, NUD_STALE,
14047b8f7a40SRoopa Prabhu 			     NEIGH_UPDATE_F_OVERRIDE, 0);
14051da177e4SLinus Torvalds 	return neigh;
14061da177e4SLinus Torvalds }
14070a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_event_ns);
14081da177e4SLinus Torvalds 
140934d101ddSEric Dumazet /* called with read_lock_bh(&n->lock); */
1410bdf53c58SEric W. Biederman static void neigh_hh_init(struct neighbour *n)
14111da177e4SLinus Torvalds {
1412bdf53c58SEric W. Biederman 	struct net_device *dev = n->dev;
1413bdf53c58SEric W. Biederman 	__be16 prot = n->tbl->protocol;
1414f6b72b62SDavid S. Miller 	struct hh_cache	*hh = &n->hh;
14150ed8ddf4SEric Dumazet 
14160ed8ddf4SEric Dumazet 	write_lock_bh(&n->lock);
141734d101ddSEric Dumazet 
1418f6b72b62SDavid S. Miller 	/* Only one thread can come in here and initialize the
1419f6b72b62SDavid S. Miller 	 * hh_cache entry.
1420f6b72b62SDavid S. Miller 	 */
1421b23b5455SDavid S. Miller 	if (!hh->hh_len)
1422b23b5455SDavid S. Miller 		dev->header_ops->cache(n, hh, prot);
1423f6b72b62SDavid S. Miller 
14240ed8ddf4SEric Dumazet 	write_unlock_bh(&n->lock);
14251da177e4SLinus Torvalds }
14261da177e4SLinus Torvalds 
14271da177e4SLinus Torvalds /* Slow and careful. */
14281da177e4SLinus Torvalds 
14298f40b161SDavid S. Miller int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
14301da177e4SLinus Torvalds {
14311da177e4SLinus Torvalds 	int rc = 0;
14321da177e4SLinus Torvalds 
14331da177e4SLinus Torvalds 	if (!neigh_event_send(neigh, skb)) {
14341da177e4SLinus Torvalds 		int err;
14351da177e4SLinus Torvalds 		struct net_device *dev = neigh->dev;
14360ed8ddf4SEric Dumazet 		unsigned int seq;
143734d101ddSEric Dumazet 
1438f6b72b62SDavid S. Miller 		if (dev->header_ops->cache && !neigh->hh.hh_len)
1439bdf53c58SEric W. Biederman 			neigh_hh_init(neigh);
144034d101ddSEric Dumazet 
14410ed8ddf4SEric Dumazet 		do {
1442e1f16503Sramesh.nagappa@gmail.com 			__skb_pull(skb, skb_network_offset(skb));
14430ed8ddf4SEric Dumazet 			seq = read_seqbegin(&neigh->ha_lock);
14440c4e8581SStephen Hemminger 			err = dev_hard_header(skb, dev, ntohs(skb->protocol),
14451da177e4SLinus Torvalds 					      neigh->ha, NULL, skb->len);
14460ed8ddf4SEric Dumazet 		} while (read_seqretry(&neigh->ha_lock, seq));
144734d101ddSEric Dumazet 
14481da177e4SLinus Torvalds 		if (err >= 0)
1449542d4d68SDavid S. Miller 			rc = dev_queue_xmit(skb);
14501da177e4SLinus Torvalds 		else
14511da177e4SLinus Torvalds 			goto out_kfree_skb;
14521da177e4SLinus Torvalds 	}
14531da177e4SLinus Torvalds out:
14541da177e4SLinus Torvalds 	return rc;
14551da177e4SLinus Torvalds out_kfree_skb:
14561da177e4SLinus Torvalds 	rc = -EINVAL;
14571da177e4SLinus Torvalds 	kfree_skb(skb);
14581da177e4SLinus Torvalds 	goto out;
14591da177e4SLinus Torvalds }
14600a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_resolve_output);
14611da177e4SLinus Torvalds 
14621da177e4SLinus Torvalds /* As fast as possible without hh cache */
14631da177e4SLinus Torvalds 
14648f40b161SDavid S. Miller int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
14651da177e4SLinus Torvalds {
14661da177e4SLinus Torvalds 	struct net_device *dev = neigh->dev;
14670ed8ddf4SEric Dumazet 	unsigned int seq;
14688f40b161SDavid S. Miller 	int err;
14691da177e4SLinus Torvalds 
14700ed8ddf4SEric Dumazet 	do {
1471e1f16503Sramesh.nagappa@gmail.com 		__skb_pull(skb, skb_network_offset(skb));
14720ed8ddf4SEric Dumazet 		seq = read_seqbegin(&neigh->ha_lock);
14730c4e8581SStephen Hemminger 		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
14741da177e4SLinus Torvalds 				      neigh->ha, NULL, skb->len);
14750ed8ddf4SEric Dumazet 	} while (read_seqretry(&neigh->ha_lock, seq));
14760ed8ddf4SEric Dumazet 
14771da177e4SLinus Torvalds 	if (err >= 0)
1478542d4d68SDavid S. Miller 		err = dev_queue_xmit(skb);
14791da177e4SLinus Torvalds 	else {
14801da177e4SLinus Torvalds 		err = -EINVAL;
14811da177e4SLinus Torvalds 		kfree_skb(skb);
14821da177e4SLinus Torvalds 	}
14831da177e4SLinus Torvalds 	return err;
14841da177e4SLinus Torvalds }
14850a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_connected_output);
14861da177e4SLinus Torvalds 
14878f40b161SDavid S. Miller int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
14888f40b161SDavid S. Miller {
14898f40b161SDavid S. Miller 	return dev_queue_xmit(skb);
14908f40b161SDavid S. Miller }
14918f40b161SDavid S. Miller EXPORT_SYMBOL(neigh_direct_output);
14928f40b161SDavid S. Miller 
1493e99e88a9SKees Cook static void neigh_proxy_process(struct timer_list *t)
14941da177e4SLinus Torvalds {
1495e99e88a9SKees Cook 	struct neigh_table *tbl = from_timer(tbl, t, proxy_timer);
14961da177e4SLinus Torvalds 	long sched_next = 0;
14971da177e4SLinus Torvalds 	unsigned long now = jiffies;
1498f72051b0SDavid S. Miller 	struct sk_buff *skb, *n;
14991da177e4SLinus Torvalds 
15001da177e4SLinus Torvalds 	spin_lock(&tbl->proxy_queue.lock);
15011da177e4SLinus Torvalds 
1502f72051b0SDavid S. Miller 	skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1503f72051b0SDavid S. Miller 		long tdif = NEIGH_CB(skb)->sched_next - now;
15041da177e4SLinus Torvalds 
15051da177e4SLinus Torvalds 		if (tdif <= 0) {
1506f72051b0SDavid S. Miller 			struct net_device *dev = skb->dev;
150720e6074eSEric Dumazet 
1508f72051b0SDavid S. Miller 			__skb_unlink(skb, &tbl->proxy_queue);
150920e6074eSEric Dumazet 			if (tbl->proxy_redo && netif_running(dev)) {
151020e6074eSEric Dumazet 				rcu_read_lock();
1511f72051b0SDavid S. Miller 				tbl->proxy_redo(skb);
151220e6074eSEric Dumazet 				rcu_read_unlock();
151320e6074eSEric Dumazet 			} else {
1514f72051b0SDavid S. Miller 				kfree_skb(skb);
151520e6074eSEric Dumazet 			}
15161da177e4SLinus Torvalds 
15171da177e4SLinus Torvalds 			dev_put(dev);
15181da177e4SLinus Torvalds 		} else if (!sched_next || tdif < sched_next)
15191da177e4SLinus Torvalds 			sched_next = tdif;
15201da177e4SLinus Torvalds 	}
15211da177e4SLinus Torvalds 	del_timer(&tbl->proxy_timer);
15221da177e4SLinus Torvalds 	if (sched_next)
15231da177e4SLinus Torvalds 		mod_timer(&tbl->proxy_timer, jiffies + sched_next);
15241da177e4SLinus Torvalds 	spin_unlock(&tbl->proxy_queue.lock);
15251da177e4SLinus Torvalds }
15261da177e4SLinus Torvalds 
15271da177e4SLinus Torvalds void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
15281da177e4SLinus Torvalds 		    struct sk_buff *skb)
15291da177e4SLinus Torvalds {
15301da177e4SLinus Torvalds 	unsigned long now = jiffies;
153163862b5bSAruna-Hewapathirane 
153263862b5bSAruna-Hewapathirane 	unsigned long sched_next = now + (prandom_u32() %
15331f9248e5SJiri Pirko 					  NEIGH_VAR(p, PROXY_DELAY));
15341da177e4SLinus Torvalds 
15351f9248e5SJiri Pirko 	if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) {
15361da177e4SLinus Torvalds 		kfree_skb(skb);
15371da177e4SLinus Torvalds 		return;
15381da177e4SLinus Torvalds 	}
1539a61bbcf2SPatrick McHardy 
1540a61bbcf2SPatrick McHardy 	NEIGH_CB(skb)->sched_next = sched_next;
1541a61bbcf2SPatrick McHardy 	NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
15421da177e4SLinus Torvalds 
15431da177e4SLinus Torvalds 	spin_lock(&tbl->proxy_queue.lock);
15441da177e4SLinus Torvalds 	if (del_timer(&tbl->proxy_timer)) {
15451da177e4SLinus Torvalds 		if (time_before(tbl->proxy_timer.expires, sched_next))
15461da177e4SLinus Torvalds 			sched_next = tbl->proxy_timer.expires;
15471da177e4SLinus Torvalds 	}
1548adf30907SEric Dumazet 	skb_dst_drop(skb);
15491da177e4SLinus Torvalds 	dev_hold(skb->dev);
15501da177e4SLinus Torvalds 	__skb_queue_tail(&tbl->proxy_queue, skb);
15511da177e4SLinus Torvalds 	mod_timer(&tbl->proxy_timer, sched_next);
15521da177e4SLinus Torvalds 	spin_unlock(&tbl->proxy_queue.lock);
15531da177e4SLinus Torvalds }
15540a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(pneigh_enqueue);
15551da177e4SLinus Torvalds 
155697fd5bc7STobias Klauser static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
1557426b5303SEric W. Biederman 						      struct net *net, int ifindex)
1558426b5303SEric W. Biederman {
1559426b5303SEric W. Biederman 	struct neigh_parms *p;
1560426b5303SEric W. Biederman 
156175fbfd33SNicolas Dichtel 	list_for_each_entry(p, &tbl->parms_list, list) {
1562878628fbSYOSHIFUJI Hideaki 		if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
1563170d6f99SGao feng 		    (!p->dev && !ifindex && net_eq(net, &init_net)))
1564426b5303SEric W. Biederman 			return p;
1565426b5303SEric W. Biederman 	}
1566426b5303SEric W. Biederman 
1567426b5303SEric W. Biederman 	return NULL;
1568426b5303SEric W. Biederman }
15691da177e4SLinus Torvalds 
15701da177e4SLinus Torvalds struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
15711da177e4SLinus Torvalds 				      struct neigh_table *tbl)
15721da177e4SLinus Torvalds {
1573cf89d6b2SGao feng 	struct neigh_parms *p;
157400829823SStephen Hemminger 	struct net *net = dev_net(dev);
157500829823SStephen Hemminger 	const struct net_device_ops *ops = dev->netdev_ops;
15761da177e4SLinus Torvalds 
1577cf89d6b2SGao feng 	p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL);
15781da177e4SLinus Torvalds 	if (p) {
15791da177e4SLinus Torvalds 		p->tbl		  = tbl;
15806343944bSReshetova, Elena 		refcount_set(&p->refcnt, 1);
15811da177e4SLinus Torvalds 		p->reachable_time =
15821f9248e5SJiri Pirko 				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
1583c7fb64dbSThomas Graf 		dev_hold(dev);
1584c7fb64dbSThomas Graf 		p->dev = dev;
1585efd7ef1cSEric W. Biederman 		write_pnet(&p->net, net);
15861da177e4SLinus Torvalds 		p->sysctl_table = NULL;
158763134803SVeaceslav Falico 
158863134803SVeaceslav Falico 		if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
158963134803SVeaceslav Falico 			dev_put(dev);
159063134803SVeaceslav Falico 			kfree(p);
159163134803SVeaceslav Falico 			return NULL;
159263134803SVeaceslav Falico 		}
159363134803SVeaceslav Falico 
15941da177e4SLinus Torvalds 		write_lock_bh(&tbl->lock);
159575fbfd33SNicolas Dichtel 		list_add(&p->list, &tbl->parms.list);
15961da177e4SLinus Torvalds 		write_unlock_bh(&tbl->lock);
15971d4c8c29SJiri Pirko 
15981d4c8c29SJiri Pirko 		neigh_parms_data_state_cleanall(p);
15991da177e4SLinus Torvalds 	}
16001da177e4SLinus Torvalds 	return p;
16011da177e4SLinus Torvalds }
16020a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_parms_alloc);
16031da177e4SLinus Torvalds 
16041da177e4SLinus Torvalds static void neigh_rcu_free_parms(struct rcu_head *head)
16051da177e4SLinus Torvalds {
16061da177e4SLinus Torvalds 	struct neigh_parms *parms =
16071da177e4SLinus Torvalds 		container_of(head, struct neigh_parms, rcu_head);
16081da177e4SLinus Torvalds 
16091da177e4SLinus Torvalds 	neigh_parms_put(parms);
16101da177e4SLinus Torvalds }
16111da177e4SLinus Torvalds 
16121da177e4SLinus Torvalds void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
16131da177e4SLinus Torvalds {
16141da177e4SLinus Torvalds 	if (!parms || parms == &tbl->parms)
16151da177e4SLinus Torvalds 		return;
16161da177e4SLinus Torvalds 	write_lock_bh(&tbl->lock);
161775fbfd33SNicolas Dichtel 	list_del(&parms->list);
16181da177e4SLinus Torvalds 	parms->dead = 1;
16191da177e4SLinus Torvalds 	write_unlock_bh(&tbl->lock);
1620cecbb639SDavid S. Miller 	if (parms->dev)
1621cecbb639SDavid S. Miller 		dev_put(parms->dev);
16221da177e4SLinus Torvalds 	call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
16231da177e4SLinus Torvalds }
16240a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_parms_release);
16251da177e4SLinus Torvalds 
162606f0511dSDenis V. Lunev static void neigh_parms_destroy(struct neigh_parms *parms)
16271da177e4SLinus Torvalds {
16281da177e4SLinus Torvalds 	kfree(parms);
16291da177e4SLinus Torvalds }
16301da177e4SLinus Torvalds 
1631c2ecba71SPavel Emelianov static struct lock_class_key neigh_table_proxy_queue_class;
1632c2ecba71SPavel Emelianov 
1633d7480fd3SWANG Cong static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly;
1634d7480fd3SWANG Cong 
1635d7480fd3SWANG Cong void neigh_table_init(int index, struct neigh_table *tbl)
16361da177e4SLinus Torvalds {
16371da177e4SLinus Torvalds 	unsigned long now = jiffies;
16381da177e4SLinus Torvalds 	unsigned long phsize;
16391da177e4SLinus Torvalds 
164075fbfd33SNicolas Dichtel 	INIT_LIST_HEAD(&tbl->parms_list);
164158956317SDavid Ahern 	INIT_LIST_HEAD(&tbl->gc_list);
164275fbfd33SNicolas Dichtel 	list_add(&tbl->parms.list, &tbl->parms_list);
1643e42ea986SEric Dumazet 	write_pnet(&tbl->parms.net, &init_net);
16446343944bSReshetova, Elena 	refcount_set(&tbl->parms.refcnt, 1);
16451da177e4SLinus Torvalds 	tbl->parms.reachable_time =
16461f9248e5SJiri Pirko 			  neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME));
16471da177e4SLinus Torvalds 
16481da177e4SLinus Torvalds 	tbl->stats = alloc_percpu(struct neigh_statistics);
16491da177e4SLinus Torvalds 	if (!tbl->stats)
16501da177e4SLinus Torvalds 		panic("cannot create neighbour cache statistics");
16511da177e4SLinus Torvalds 
16521da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
165371a5053aSChristoph Hellwig 	if (!proc_create_seq_data(tbl->id, 0, init_net.proc_net_stat,
165471a5053aSChristoph Hellwig 			      &neigh_stat_seq_ops, tbl))
16551da177e4SLinus Torvalds 		panic("cannot create neighbour proc dir entry");
16561da177e4SLinus Torvalds #endif
16571da177e4SLinus Torvalds 
1658cd089336SDavid S. Miller 	RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
16591da177e4SLinus Torvalds 
16601da177e4SLinus Torvalds 	phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
166177d04bd9SAndrew Morton 	tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
16621da177e4SLinus Torvalds 
1663d6bf7817SEric Dumazet 	if (!tbl->nht || !tbl->phash_buckets)
16641da177e4SLinus Torvalds 		panic("cannot allocate neighbour cache hashes");
16651da177e4SLinus Torvalds 
166608433effSYOSHIFUJI Hideaki / 吉藤英明 	if (!tbl->entry_size)
166708433effSYOSHIFUJI Hideaki / 吉藤英明 		tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
166808433effSYOSHIFUJI Hideaki / 吉藤英明 					tbl->key_len, NEIGH_PRIV_ALIGN);
166908433effSYOSHIFUJI Hideaki / 吉藤英明 	else
167008433effSYOSHIFUJI Hideaki / 吉藤英明 		WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
167108433effSYOSHIFUJI Hideaki / 吉藤英明 
16721da177e4SLinus Torvalds 	rwlock_init(&tbl->lock);
1673203b42f7STejun Heo 	INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
1674f618002bSviresh kumar 	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
1675f618002bSviresh kumar 			tbl->parms.reachable_time);
1676e99e88a9SKees Cook 	timer_setup(&tbl->proxy_timer, neigh_proxy_process, 0);
1677c2ecba71SPavel Emelianov 	skb_queue_head_init_class(&tbl->proxy_queue,
1678c2ecba71SPavel Emelianov 			&neigh_table_proxy_queue_class);
16791da177e4SLinus Torvalds 
16801da177e4SLinus Torvalds 	tbl->last_flush = now;
16811da177e4SLinus Torvalds 	tbl->last_rand	= now + tbl->parms.reachable_time * 20;
1682bd89efc5SSimon Kelley 
1683d7480fd3SWANG Cong 	neigh_tables[index] = tbl;
16841da177e4SLinus Torvalds }
16850a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_table_init);
16861da177e4SLinus Torvalds 
1687d7480fd3SWANG Cong int neigh_table_clear(int index, struct neigh_table *tbl)
16881da177e4SLinus Torvalds {
1689d7480fd3SWANG Cong 	neigh_tables[index] = NULL;
16901da177e4SLinus Torvalds 	/* It is not clean... Fix it to unload IPv6 module safely */
1691a5c30b34STejun Heo 	cancel_delayed_work_sync(&tbl->gc_work);
16921da177e4SLinus Torvalds 	del_timer_sync(&tbl->proxy_timer);
16931da177e4SLinus Torvalds 	pneigh_queue_purge(&tbl->proxy_queue);
16941da177e4SLinus Torvalds 	neigh_ifdown(tbl, NULL);
16951da177e4SLinus Torvalds 	if (atomic_read(&tbl->entries))
1696e005d193SJoe Perches 		pr_crit("neighbour leakage\n");
16971da177e4SLinus Torvalds 
16986193d2beSEric Dumazet 	call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
16996193d2beSEric Dumazet 		 neigh_hash_free_rcu);
1700d6bf7817SEric Dumazet 	tbl->nht = NULL;
17011da177e4SLinus Torvalds 
17021da177e4SLinus Torvalds 	kfree(tbl->phash_buckets);
17031da177e4SLinus Torvalds 	tbl->phash_buckets = NULL;
17041da177e4SLinus Torvalds 
17053f192b5cSAlexey Dobriyan 	remove_proc_entry(tbl->id, init_net.proc_net_stat);
17063f192b5cSAlexey Dobriyan 
17073fcde74bSKirill Korotaev 	free_percpu(tbl->stats);
17083fcde74bSKirill Korotaev 	tbl->stats = NULL;
17093fcde74bSKirill Korotaev 
17101da177e4SLinus Torvalds 	return 0;
17111da177e4SLinus Torvalds }
17120a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_table_clear);
17131da177e4SLinus Torvalds 
1714d7480fd3SWANG Cong static struct neigh_table *neigh_find_table(int family)
1715d7480fd3SWANG Cong {
1716d7480fd3SWANG Cong 	struct neigh_table *tbl = NULL;
1717d7480fd3SWANG Cong 
1718d7480fd3SWANG Cong 	switch (family) {
1719d7480fd3SWANG Cong 	case AF_INET:
1720d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_ARP_TABLE];
1721d7480fd3SWANG Cong 		break;
1722d7480fd3SWANG Cong 	case AF_INET6:
1723d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_ND_TABLE];
1724d7480fd3SWANG Cong 		break;
1725d7480fd3SWANG Cong 	case AF_DECnet:
1726d7480fd3SWANG Cong 		tbl = neigh_tables[NEIGH_DN_TABLE];
1727d7480fd3SWANG Cong 		break;
1728d7480fd3SWANG Cong 	}
1729d7480fd3SWANG Cong 
1730d7480fd3SWANG Cong 	return tbl;
1731d7480fd3SWANG Cong }
1732d7480fd3SWANG Cong 
1733c21ef3e3SDavid Ahern static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
1734c21ef3e3SDavid Ahern 			struct netlink_ext_ack *extack)
17351da177e4SLinus Torvalds {
17363b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
1737a14a49d2SThomas Graf 	struct ndmsg *ndm;
1738a14a49d2SThomas Graf 	struct nlattr *dst_attr;
17391da177e4SLinus Torvalds 	struct neigh_table *tbl;
1740d7480fd3SWANG Cong 	struct neighbour *neigh;
17411da177e4SLinus Torvalds 	struct net_device *dev = NULL;
1742a14a49d2SThomas Graf 	int err = -EINVAL;
17431da177e4SLinus Torvalds 
1744110b2499SEric Dumazet 	ASSERT_RTNL();
1745a14a49d2SThomas Graf 	if (nlmsg_len(nlh) < sizeof(*ndm))
17461da177e4SLinus Torvalds 		goto out;
17471da177e4SLinus Torvalds 
1748a14a49d2SThomas Graf 	dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
17497a35a50dSDavid Ahern 	if (!dst_attr) {
17507a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Network address not specified");
1751a14a49d2SThomas Graf 		goto out;
17527a35a50dSDavid Ahern 	}
1753a14a49d2SThomas Graf 
1754a14a49d2SThomas Graf 	ndm = nlmsg_data(nlh);
1755a14a49d2SThomas Graf 	if (ndm->ndm_ifindex) {
1756110b2499SEric Dumazet 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
1757a14a49d2SThomas Graf 		if (dev == NULL) {
1758a14a49d2SThomas Graf 			err = -ENODEV;
1759a14a49d2SThomas Graf 			goto out;
1760a14a49d2SThomas Graf 		}
1761a14a49d2SThomas Graf 	}
1762a14a49d2SThomas Graf 
1763d7480fd3SWANG Cong 	tbl = neigh_find_table(ndm->ndm_family);
1764d7480fd3SWANG Cong 	if (tbl == NULL)
1765d7480fd3SWANG Cong 		return -EAFNOSUPPORT;
17661da177e4SLinus Torvalds 
17677a35a50dSDavid Ahern 	if (nla_len(dst_attr) < (int)tbl->key_len) {
17687a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid network address");
1769110b2499SEric Dumazet 		goto out;
17707a35a50dSDavid Ahern 	}
17711da177e4SLinus Torvalds 
17721da177e4SLinus Torvalds 	if (ndm->ndm_flags & NTF_PROXY) {
1773426b5303SEric W. Biederman 		err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
1774110b2499SEric Dumazet 		goto out;
17751da177e4SLinus Torvalds 	}
17761da177e4SLinus Torvalds 
1777a14a49d2SThomas Graf 	if (dev == NULL)
1778110b2499SEric Dumazet 		goto out;
17791da177e4SLinus Torvalds 
1780a14a49d2SThomas Graf 	neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1781a14a49d2SThomas Graf 	if (neigh == NULL) {
1782a14a49d2SThomas Graf 		err = -ENOENT;
1783110b2499SEric Dumazet 		goto out;
1784a14a49d2SThomas Graf 	}
1785a14a49d2SThomas Graf 
17867a35a50dSDavid Ahern 	err = __neigh_update(neigh, NULL, NUD_FAILED,
17877a35a50dSDavid Ahern 			     NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN,
17887a35a50dSDavid Ahern 			     NETLINK_CB(skb).portid, extack);
17895071034eSSowmini Varadhan 	write_lock_bh(&tbl->lock);
1790a14a49d2SThomas Graf 	neigh_release(neigh);
17915071034eSSowmini Varadhan 	neigh_remove_one(neigh, tbl);
17925071034eSSowmini Varadhan 	write_unlock_bh(&tbl->lock);
1793a14a49d2SThomas Graf 
17941da177e4SLinus Torvalds out:
17951da177e4SLinus Torvalds 	return err;
17961da177e4SLinus Torvalds }
17971da177e4SLinus Torvalds 
1798c21ef3e3SDavid Ahern static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
1799c21ef3e3SDavid Ahern 		     struct netlink_ext_ack *extack)
18001da177e4SLinus Torvalds {
1801f7aa74e4SRoopa Prabhu 	int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE |
1802f7aa74e4SRoopa Prabhu 		NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
18033b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
18045208debdSThomas Graf 	struct ndmsg *ndm;
18055208debdSThomas Graf 	struct nlattr *tb[NDA_MAX+1];
18061da177e4SLinus Torvalds 	struct neigh_table *tbl;
18071da177e4SLinus Torvalds 	struct net_device *dev = NULL;
1808d7480fd3SWANG Cong 	struct neighbour *neigh;
1809d7480fd3SWANG Cong 	void *dst, *lladdr;
18105208debdSThomas Graf 	int err;
18111da177e4SLinus Torvalds 
1812110b2499SEric Dumazet 	ASSERT_RTNL();
1813c21ef3e3SDavid Ahern 	err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL, extack);
18145208debdSThomas Graf 	if (err < 0)
18151da177e4SLinus Torvalds 		goto out;
18161da177e4SLinus Torvalds 
18175208debdSThomas Graf 	err = -EINVAL;
18187a35a50dSDavid Ahern 	if (!tb[NDA_DST]) {
18197a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Network address not specified");
18205208debdSThomas Graf 		goto out;
18217a35a50dSDavid Ahern 	}
18225208debdSThomas Graf 
18235208debdSThomas Graf 	ndm = nlmsg_data(nlh);
18245208debdSThomas Graf 	if (ndm->ndm_ifindex) {
1825110b2499SEric Dumazet 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
18265208debdSThomas Graf 		if (dev == NULL) {
18275208debdSThomas Graf 			err = -ENODEV;
18285208debdSThomas Graf 			goto out;
18295208debdSThomas Graf 		}
18305208debdSThomas Graf 
18317a35a50dSDavid Ahern 		if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) {
18327a35a50dSDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid link address");
1833110b2499SEric Dumazet 			goto out;
18345208debdSThomas Graf 		}
18357a35a50dSDavid Ahern 	}
18365208debdSThomas Graf 
1837d7480fd3SWANG Cong 	tbl = neigh_find_table(ndm->ndm_family);
1838d7480fd3SWANG Cong 	if (tbl == NULL)
1839d7480fd3SWANG Cong 		return -EAFNOSUPPORT;
18401da177e4SLinus Torvalds 
18417a35a50dSDavid Ahern 	if (nla_len(tb[NDA_DST]) < (int)tbl->key_len) {
18427a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid network address");
1843110b2499SEric Dumazet 		goto out;
18447a35a50dSDavid Ahern 	}
18457a35a50dSDavid Ahern 
18465208debdSThomas Graf 	dst = nla_data(tb[NDA_DST]);
18475208debdSThomas Graf 	lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
18481da177e4SLinus Torvalds 
18491da177e4SLinus Torvalds 	if (ndm->ndm_flags & NTF_PROXY) {
185062dd9318SVille Nuorvala 		struct pneigh_entry *pn;
185162dd9318SVille Nuorvala 
18525208debdSThomas Graf 		err = -ENOBUFS;
1853426b5303SEric W. Biederman 		pn = pneigh_lookup(tbl, net, dst, dev, 1);
185462dd9318SVille Nuorvala 		if (pn) {
185562dd9318SVille Nuorvala 			pn->flags = ndm->ndm_flags;
185662dd9318SVille Nuorvala 			err = 0;
185762dd9318SVille Nuorvala 		}
1858110b2499SEric Dumazet 		goto out;
18591da177e4SLinus Torvalds 	}
18601da177e4SLinus Torvalds 
18617a35a50dSDavid Ahern 	if (!dev) {
18627a35a50dSDavid Ahern 		NL_SET_ERR_MSG(extack, "Device not specified");
1863110b2499SEric Dumazet 		goto out;
18647a35a50dSDavid Ahern 	}
18651da177e4SLinus Torvalds 
18665208debdSThomas Graf 	neigh = neigh_lookup(tbl, dst, dev);
18675208debdSThomas Graf 	if (neigh == NULL) {
18685208debdSThomas Graf 		if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
18691da177e4SLinus Torvalds 			err = -ENOENT;
1870110b2499SEric Dumazet 			goto out;
18715208debdSThomas Graf 		}
18725208debdSThomas Graf 
187358956317SDavid Ahern 		neigh = ___neigh_create(tbl, dst, dev,
187458956317SDavid Ahern 					ndm->ndm_state & NUD_PERMANENT,
187558956317SDavid Ahern 					true);
18765208debdSThomas Graf 		if (IS_ERR(neigh)) {
18775208debdSThomas Graf 			err = PTR_ERR(neigh);
1878110b2499SEric Dumazet 			goto out;
18791da177e4SLinus Torvalds 		}
18805208debdSThomas Graf 	} else {
18815208debdSThomas Graf 		if (nlh->nlmsg_flags & NLM_F_EXCL) {
18825208debdSThomas Graf 			err = -EEXIST;
18835208debdSThomas Graf 			neigh_release(neigh);
1884110b2499SEric Dumazet 			goto out;
18851da177e4SLinus Torvalds 		}
18861da177e4SLinus Torvalds 
18875208debdSThomas Graf 		if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
1888f7aa74e4SRoopa Prabhu 			flags &= ~(NEIGH_UPDATE_F_OVERRIDE |
1889f7aa74e4SRoopa Prabhu 				   NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
18905208debdSThomas Graf 	}
18911da177e4SLinus Torvalds 
18929ce33e46SRoopa Prabhu 	if (ndm->ndm_flags & NTF_EXT_LEARNED)
18939ce33e46SRoopa Prabhu 		flags |= NEIGH_UPDATE_F_EXT_LEARNED;
18949ce33e46SRoopa Prabhu 
1895f7aa74e4SRoopa Prabhu 	if (ndm->ndm_flags & NTF_ROUTER)
1896f7aa74e4SRoopa Prabhu 		flags |= NEIGH_UPDATE_F_ISROUTER;
1897f7aa74e4SRoopa Prabhu 
18980c5c2d30SEric Biederman 	if (ndm->ndm_flags & NTF_USE) {
18990c5c2d30SEric Biederman 		neigh_event_send(neigh, NULL);
19000c5c2d30SEric Biederman 		err = 0;
19010c5c2d30SEric Biederman 	} else
19027a35a50dSDavid Ahern 		err = __neigh_update(neigh, lladdr, ndm->ndm_state, flags,
19037a35a50dSDavid Ahern 				     NETLINK_CB(skb).portid, extack);
19045208debdSThomas Graf 	neigh_release(neigh);
19051da177e4SLinus Torvalds 
19061da177e4SLinus Torvalds out:
19071da177e4SLinus Torvalds 	return err;
19081da177e4SLinus Torvalds }
19091da177e4SLinus Torvalds 
1910c7fb64dbSThomas Graf static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
1911c7fb64dbSThomas Graf {
1912ca860fb3SThomas Graf 	struct nlattr *nest;
1913e386c6ebSThomas Graf 
1914ca860fb3SThomas Graf 	nest = nla_nest_start(skb, NDTA_PARMS);
1915ca860fb3SThomas Graf 	if (nest == NULL)
1916ca860fb3SThomas Graf 		return -ENOBUFS;
1917c7fb64dbSThomas Graf 
19189a6308d7SDavid S. Miller 	if ((parms->dev &&
19199a6308d7SDavid S. Miller 	     nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
19206343944bSReshetova, Elena 	    nla_put_u32(skb, NDTPA_REFCNT, refcount_read(&parms->refcnt)) ||
19211f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_QUEUE_LENBYTES,
19221f9248e5SJiri Pirko 			NEIGH_VAR(parms, QUEUE_LEN_BYTES)) ||
19238b5c171bSEric Dumazet 	    /* approximative value for deprecated QUEUE_LEN (in packets) */
19249a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTPA_QUEUE_LEN,
19251f9248e5SJiri Pirko 			NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) ||
19261f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) ||
19271f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) ||
19281f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_UCAST_PROBES,
19291f9248e5SJiri Pirko 			NEIGH_VAR(parms, UCAST_PROBES)) ||
19301f9248e5SJiri Pirko 	    nla_put_u32(skb, NDTPA_MCAST_PROBES,
19311f9248e5SJiri Pirko 			NEIGH_VAR(parms, MCAST_PROBES)) ||
19328da86466SYOSHIFUJI Hideaki/吉藤英明 	    nla_put_u32(skb, NDTPA_MCAST_REPROBES,
19338da86466SYOSHIFUJI Hideaki/吉藤英明 			NEIGH_VAR(parms, MCAST_REPROBES)) ||
19342175d87cSNicolas Dichtel 	    nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time,
19352175d87cSNicolas Dichtel 			  NDTPA_PAD) ||
19369a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
19372175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, BASE_REACHABLE_TIME), NDTPA_PAD) ||
19381f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_GC_STALETIME,
19392175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, GC_STALETIME), NDTPA_PAD) ||
19409a6308d7SDavid S. Miller 	    nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
19412175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, DELAY_PROBE_TIME), NDTPA_PAD) ||
19421f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_RETRANS_TIME,
19432175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, RETRANS_TIME), NDTPA_PAD) ||
19441f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_ANYCAST_DELAY,
19452175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, ANYCAST_DELAY), NDTPA_PAD) ||
19461f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_PROXY_DELAY,
19472175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, PROXY_DELAY), NDTPA_PAD) ||
19481f9248e5SJiri Pirko 	    nla_put_msecs(skb, NDTPA_LOCKTIME,
19492175d87cSNicolas Dichtel 			  NEIGH_VAR(parms, LOCKTIME), NDTPA_PAD))
19509a6308d7SDavid S. Miller 		goto nla_put_failure;
1951ca860fb3SThomas Graf 	return nla_nest_end(skb, nest);
1952c7fb64dbSThomas Graf 
1953ca860fb3SThomas Graf nla_put_failure:
1954bc3ed28cSThomas Graf 	nla_nest_cancel(skb, nest);
1955bc3ed28cSThomas Graf 	return -EMSGSIZE;
1956c7fb64dbSThomas Graf }
1957c7fb64dbSThomas Graf 
1958ca860fb3SThomas Graf static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
1959ca860fb3SThomas Graf 			      u32 pid, u32 seq, int type, int flags)
1960c7fb64dbSThomas Graf {
1961c7fb64dbSThomas Graf 	struct nlmsghdr *nlh;
1962c7fb64dbSThomas Graf 	struct ndtmsg *ndtmsg;
1963c7fb64dbSThomas Graf 
1964ca860fb3SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1965ca860fb3SThomas Graf 	if (nlh == NULL)
196626932566SPatrick McHardy 		return -EMSGSIZE;
1967c7fb64dbSThomas Graf 
1968ca860fb3SThomas Graf 	ndtmsg = nlmsg_data(nlh);
1969c7fb64dbSThomas Graf 
1970c7fb64dbSThomas Graf 	read_lock_bh(&tbl->lock);
1971c7fb64dbSThomas Graf 	ndtmsg->ndtm_family = tbl->family;
19729ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad1   = 0;
19739ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad2   = 0;
1974c7fb64dbSThomas Graf 
19759a6308d7SDavid S. Miller 	if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
19762175d87cSNicolas Dichtel 	    nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval, NDTA_PAD) ||
19779a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
19789a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
19799a6308d7SDavid S. Miller 	    nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
19809a6308d7SDavid S. Miller 		goto nla_put_failure;
1981c7fb64dbSThomas Graf 	{
1982c7fb64dbSThomas Graf 		unsigned long now = jiffies;
1983c7fb64dbSThomas Graf 		unsigned int flush_delta = now - tbl->last_flush;
1984c7fb64dbSThomas Graf 		unsigned int rand_delta = now - tbl->last_rand;
1985d6bf7817SEric Dumazet 		struct neigh_hash_table *nht;
1986c7fb64dbSThomas Graf 		struct ndt_config ndc = {
1987c7fb64dbSThomas Graf 			.ndtc_key_len		= tbl->key_len,
1988c7fb64dbSThomas Graf 			.ndtc_entry_size	= tbl->entry_size,
1989c7fb64dbSThomas Graf 			.ndtc_entries		= atomic_read(&tbl->entries),
1990c7fb64dbSThomas Graf 			.ndtc_last_flush	= jiffies_to_msecs(flush_delta),
1991c7fb64dbSThomas Graf 			.ndtc_last_rand		= jiffies_to_msecs(rand_delta),
1992c7fb64dbSThomas Graf 			.ndtc_proxy_qlen	= tbl->proxy_queue.qlen,
1993c7fb64dbSThomas Graf 		};
1994c7fb64dbSThomas Graf 
1995d6bf7817SEric Dumazet 		rcu_read_lock_bh();
1996d6bf7817SEric Dumazet 		nht = rcu_dereference_bh(tbl->nht);
19972c2aba6cSDavid S. Miller 		ndc.ndtc_hash_rnd = nht->hash_rnd[0];
1998cd089336SDavid S. Miller 		ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
1999d6bf7817SEric Dumazet 		rcu_read_unlock_bh();
2000d6bf7817SEric Dumazet 
20019a6308d7SDavid S. Miller 		if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
20029a6308d7SDavid S. Miller 			goto nla_put_failure;
2003c7fb64dbSThomas Graf 	}
2004c7fb64dbSThomas Graf 
2005c7fb64dbSThomas Graf 	{
2006c7fb64dbSThomas Graf 		int cpu;
2007c7fb64dbSThomas Graf 		struct ndt_stats ndst;
2008c7fb64dbSThomas Graf 
2009c7fb64dbSThomas Graf 		memset(&ndst, 0, sizeof(ndst));
2010c7fb64dbSThomas Graf 
20116f912042SKAMEZAWA Hiroyuki 		for_each_possible_cpu(cpu) {
2012c7fb64dbSThomas Graf 			struct neigh_statistics	*st;
2013c7fb64dbSThomas Graf 
2014c7fb64dbSThomas Graf 			st = per_cpu_ptr(tbl->stats, cpu);
2015c7fb64dbSThomas Graf 			ndst.ndts_allocs		+= st->allocs;
2016c7fb64dbSThomas Graf 			ndst.ndts_destroys		+= st->destroys;
2017c7fb64dbSThomas Graf 			ndst.ndts_hash_grows		+= st->hash_grows;
2018c7fb64dbSThomas Graf 			ndst.ndts_res_failed		+= st->res_failed;
2019c7fb64dbSThomas Graf 			ndst.ndts_lookups		+= st->lookups;
2020c7fb64dbSThomas Graf 			ndst.ndts_hits			+= st->hits;
2021c7fb64dbSThomas Graf 			ndst.ndts_rcv_probes_mcast	+= st->rcv_probes_mcast;
2022c7fb64dbSThomas Graf 			ndst.ndts_rcv_probes_ucast	+= st->rcv_probes_ucast;
2023c7fb64dbSThomas Graf 			ndst.ndts_periodic_gc_runs	+= st->periodic_gc_runs;
2024c7fb64dbSThomas Graf 			ndst.ndts_forced_gc_runs	+= st->forced_gc_runs;
2025fb811395SRick Jones 			ndst.ndts_table_fulls		+= st->table_fulls;
2026c7fb64dbSThomas Graf 		}
2027c7fb64dbSThomas Graf 
2028b676338fSNicolas Dichtel 		if (nla_put_64bit(skb, NDTA_STATS, sizeof(ndst), &ndst,
2029b676338fSNicolas Dichtel 				  NDTA_PAD))
20309a6308d7SDavid S. Miller 			goto nla_put_failure;
2031c7fb64dbSThomas Graf 	}
2032c7fb64dbSThomas Graf 
2033c7fb64dbSThomas Graf 	BUG_ON(tbl->parms.dev);
2034c7fb64dbSThomas Graf 	if (neightbl_fill_parms(skb, &tbl->parms) < 0)
2035ca860fb3SThomas Graf 		goto nla_put_failure;
2036c7fb64dbSThomas Graf 
2037c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
2038053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2039053c095aSJohannes Berg 	return 0;
2040c7fb64dbSThomas Graf 
2041ca860fb3SThomas Graf nla_put_failure:
2042c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
204326932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
204426932566SPatrick McHardy 	return -EMSGSIZE;
2045c7fb64dbSThomas Graf }
2046c7fb64dbSThomas Graf 
2047ca860fb3SThomas Graf static int neightbl_fill_param_info(struct sk_buff *skb,
2048ca860fb3SThomas Graf 				    struct neigh_table *tbl,
2049c7fb64dbSThomas Graf 				    struct neigh_parms *parms,
2050ca860fb3SThomas Graf 				    u32 pid, u32 seq, int type,
2051ca860fb3SThomas Graf 				    unsigned int flags)
2052c7fb64dbSThomas Graf {
2053c7fb64dbSThomas Graf 	struct ndtmsg *ndtmsg;
2054c7fb64dbSThomas Graf 	struct nlmsghdr *nlh;
2055c7fb64dbSThomas Graf 
2056ca860fb3SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2057ca860fb3SThomas Graf 	if (nlh == NULL)
205826932566SPatrick McHardy 		return -EMSGSIZE;
2059c7fb64dbSThomas Graf 
2060ca860fb3SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2061c7fb64dbSThomas Graf 
2062c7fb64dbSThomas Graf 	read_lock_bh(&tbl->lock);
2063c7fb64dbSThomas Graf 	ndtmsg->ndtm_family = tbl->family;
20649ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad1   = 0;
20659ef1d4c7SPatrick McHardy 	ndtmsg->ndtm_pad2   = 0;
2066c7fb64dbSThomas Graf 
2067ca860fb3SThomas Graf 	if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
2068ca860fb3SThomas Graf 	    neightbl_fill_parms(skb, parms) < 0)
2069ca860fb3SThomas Graf 		goto errout;
2070c7fb64dbSThomas Graf 
2071c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
2072053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2073053c095aSJohannes Berg 	return 0;
2074ca860fb3SThomas Graf errout:
2075c7fb64dbSThomas Graf 	read_unlock_bh(&tbl->lock);
207626932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
207726932566SPatrick McHardy 	return -EMSGSIZE;
2078c7fb64dbSThomas Graf }
2079c7fb64dbSThomas Graf 
2080ef7c79edSPatrick McHardy static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
20816b3f8674SThomas Graf 	[NDTA_NAME]		= { .type = NLA_STRING },
20826b3f8674SThomas Graf 	[NDTA_THRESH1]		= { .type = NLA_U32 },
20836b3f8674SThomas Graf 	[NDTA_THRESH2]		= { .type = NLA_U32 },
20846b3f8674SThomas Graf 	[NDTA_THRESH3]		= { .type = NLA_U32 },
20856b3f8674SThomas Graf 	[NDTA_GC_INTERVAL]	= { .type = NLA_U64 },
20866b3f8674SThomas Graf 	[NDTA_PARMS]		= { .type = NLA_NESTED },
20876b3f8674SThomas Graf };
20886b3f8674SThomas Graf 
2089ef7c79edSPatrick McHardy static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
20906b3f8674SThomas Graf 	[NDTPA_IFINDEX]			= { .type = NLA_U32 },
20916b3f8674SThomas Graf 	[NDTPA_QUEUE_LEN]		= { .type = NLA_U32 },
20926b3f8674SThomas Graf 	[NDTPA_PROXY_QLEN]		= { .type = NLA_U32 },
20936b3f8674SThomas Graf 	[NDTPA_APP_PROBES]		= { .type = NLA_U32 },
20946b3f8674SThomas Graf 	[NDTPA_UCAST_PROBES]		= { .type = NLA_U32 },
20956b3f8674SThomas Graf 	[NDTPA_MCAST_PROBES]		= { .type = NLA_U32 },
20968da86466SYOSHIFUJI Hideaki/吉藤英明 	[NDTPA_MCAST_REPROBES]		= { .type = NLA_U32 },
20976b3f8674SThomas Graf 	[NDTPA_BASE_REACHABLE_TIME]	= { .type = NLA_U64 },
20986b3f8674SThomas Graf 	[NDTPA_GC_STALETIME]		= { .type = NLA_U64 },
20996b3f8674SThomas Graf 	[NDTPA_DELAY_PROBE_TIME]	= { .type = NLA_U64 },
21006b3f8674SThomas Graf 	[NDTPA_RETRANS_TIME]		= { .type = NLA_U64 },
21016b3f8674SThomas Graf 	[NDTPA_ANYCAST_DELAY]		= { .type = NLA_U64 },
21026b3f8674SThomas Graf 	[NDTPA_PROXY_DELAY]		= { .type = NLA_U64 },
21036b3f8674SThomas Graf 	[NDTPA_LOCKTIME]		= { .type = NLA_U64 },
21046b3f8674SThomas Graf };
21056b3f8674SThomas Graf 
2106c21ef3e3SDavid Ahern static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
2107c21ef3e3SDavid Ahern 			struct netlink_ext_ack *extack)
2108c7fb64dbSThomas Graf {
21093b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
2110c7fb64dbSThomas Graf 	struct neigh_table *tbl;
21116b3f8674SThomas Graf 	struct ndtmsg *ndtmsg;
21126b3f8674SThomas Graf 	struct nlattr *tb[NDTA_MAX+1];
2113d7480fd3SWANG Cong 	bool found = false;
2114d7480fd3SWANG Cong 	int err, tidx;
2115c7fb64dbSThomas Graf 
21166b3f8674SThomas Graf 	err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
2117c21ef3e3SDavid Ahern 			  nl_neightbl_policy, extack);
21186b3f8674SThomas Graf 	if (err < 0)
21196b3f8674SThomas Graf 		goto errout;
2120c7fb64dbSThomas Graf 
21216b3f8674SThomas Graf 	if (tb[NDTA_NAME] == NULL) {
21226b3f8674SThomas Graf 		err = -EINVAL;
21236b3f8674SThomas Graf 		goto errout;
21246b3f8674SThomas Graf 	}
21256b3f8674SThomas Graf 
21266b3f8674SThomas Graf 	ndtmsg = nlmsg_data(nlh);
2127d7480fd3SWANG Cong 
2128d7480fd3SWANG Cong 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2129d7480fd3SWANG Cong 		tbl = neigh_tables[tidx];
2130d7480fd3SWANG Cong 		if (!tbl)
2131d7480fd3SWANG Cong 			continue;
2132c7fb64dbSThomas Graf 		if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
2133c7fb64dbSThomas Graf 			continue;
2134d7480fd3SWANG Cong 		if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) {
2135d7480fd3SWANG Cong 			found = true;
2136c7fb64dbSThomas Graf 			break;
2137c7fb64dbSThomas Graf 		}
2138c7fb64dbSThomas Graf 	}
2139c7fb64dbSThomas Graf 
2140d7480fd3SWANG Cong 	if (!found)
2141d7480fd3SWANG Cong 		return -ENOENT;
2142d7480fd3SWANG Cong 
2143c7fb64dbSThomas Graf 	/*
2144c7fb64dbSThomas Graf 	 * We acquire tbl->lock to be nice to the periodic timers and
2145c7fb64dbSThomas Graf 	 * make sure they always see a consistent set of values.
2146c7fb64dbSThomas Graf 	 */
2147c7fb64dbSThomas Graf 	write_lock_bh(&tbl->lock);
2148c7fb64dbSThomas Graf 
21496b3f8674SThomas Graf 	if (tb[NDTA_PARMS]) {
21506b3f8674SThomas Graf 		struct nlattr *tbp[NDTPA_MAX+1];
2151c7fb64dbSThomas Graf 		struct neigh_parms *p;
21526b3f8674SThomas Graf 		int i, ifindex = 0;
2153c7fb64dbSThomas Graf 
21546b3f8674SThomas Graf 		err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS],
2155c21ef3e3SDavid Ahern 				       nl_ntbl_parm_policy, extack);
21566b3f8674SThomas Graf 		if (err < 0)
21576b3f8674SThomas Graf 			goto errout_tbl_lock;
2158c7fb64dbSThomas Graf 
21596b3f8674SThomas Graf 		if (tbp[NDTPA_IFINDEX])
21606b3f8674SThomas Graf 			ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
2161c7fb64dbSThomas Graf 
216297fd5bc7STobias Klauser 		p = lookup_neigh_parms(tbl, net, ifindex);
2163c7fb64dbSThomas Graf 		if (p == NULL) {
2164c7fb64dbSThomas Graf 			err = -ENOENT;
21656b3f8674SThomas Graf 			goto errout_tbl_lock;
2166c7fb64dbSThomas Graf 		}
2167c7fb64dbSThomas Graf 
21686b3f8674SThomas Graf 		for (i = 1; i <= NDTPA_MAX; i++) {
21696b3f8674SThomas Graf 			if (tbp[i] == NULL)
21706b3f8674SThomas Graf 				continue;
2171c7fb64dbSThomas Graf 
21726b3f8674SThomas Graf 			switch (i) {
21736b3f8674SThomas Graf 			case NDTPA_QUEUE_LEN:
21741f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
21751f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]) *
21761f9248e5SJiri Pirko 					      SKB_TRUESIZE(ETH_FRAME_LEN));
21778b5c171bSEric Dumazet 				break;
21788b5c171bSEric Dumazet 			case NDTPA_QUEUE_LENBYTES:
21791f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
21801f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
21816b3f8674SThomas Graf 				break;
21826b3f8674SThomas Graf 			case NDTPA_PROXY_QLEN:
21831f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, PROXY_QLEN,
21841f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
21856b3f8674SThomas Graf 				break;
21866b3f8674SThomas Graf 			case NDTPA_APP_PROBES:
21871f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, APP_PROBES,
21881f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
21896b3f8674SThomas Graf 				break;
21906b3f8674SThomas Graf 			case NDTPA_UCAST_PROBES:
21911f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, UCAST_PROBES,
21921f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
21936b3f8674SThomas Graf 				break;
21946b3f8674SThomas Graf 			case NDTPA_MCAST_PROBES:
21951f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, MCAST_PROBES,
21961f9248e5SJiri Pirko 					      nla_get_u32(tbp[i]));
21976b3f8674SThomas Graf 				break;
21988da86466SYOSHIFUJI Hideaki/吉藤英明 			case NDTPA_MCAST_REPROBES:
21998da86466SYOSHIFUJI Hideaki/吉藤英明 				NEIGH_VAR_SET(p, MCAST_REPROBES,
22008da86466SYOSHIFUJI Hideaki/吉藤英明 					      nla_get_u32(tbp[i]));
22018da86466SYOSHIFUJI Hideaki/吉藤英明 				break;
22026b3f8674SThomas Graf 			case NDTPA_BASE_REACHABLE_TIME:
22031f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,
22041f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
22054bf6980dSJean-Francois Remy 				/* update reachable_time as well, otherwise, the change will
22064bf6980dSJean-Francois Remy 				 * only be effective after the next time neigh_periodic_work
22074bf6980dSJean-Francois Remy 				 * decides to recompute it (can be multiple minutes)
22084bf6980dSJean-Francois Remy 				 */
22094bf6980dSJean-Francois Remy 				p->reachable_time =
22104bf6980dSJean-Francois Remy 					neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
22116b3f8674SThomas Graf 				break;
22126b3f8674SThomas Graf 			case NDTPA_GC_STALETIME:
22131f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, GC_STALETIME,
22141f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
22156b3f8674SThomas Graf 				break;
22166b3f8674SThomas Graf 			case NDTPA_DELAY_PROBE_TIME:
22171f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, DELAY_PROBE_TIME,
22181f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
22192a4501aeSIdo Schimmel 				call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
22206b3f8674SThomas Graf 				break;
22216b3f8674SThomas Graf 			case NDTPA_RETRANS_TIME:
22221f9248e5SJiri Pirko 				NEIGH_VAR_SET(p, RETRANS_TIME,
22231f9248e5SJiri Pirko 					      nla_get_msecs(tbp[i]));
22246b3f8674SThomas Graf 				break;
22256b3f8674SThomas Graf 			case NDTPA_ANYCAST_DELAY:
22263977458cSJiri Pirko 				NEIGH_VAR_SET(p, ANYCAST_DELAY,
22273977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
22286b3f8674SThomas Graf 				break;
22296b3f8674SThomas Graf 			case NDTPA_PROXY_DELAY:
22303977458cSJiri Pirko 				NEIGH_VAR_SET(p, PROXY_DELAY,
22313977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
22326b3f8674SThomas Graf 				break;
22336b3f8674SThomas Graf 			case NDTPA_LOCKTIME:
22343977458cSJiri Pirko 				NEIGH_VAR_SET(p, LOCKTIME,
22353977458cSJiri Pirko 					      nla_get_msecs(tbp[i]));
22366b3f8674SThomas Graf 				break;
2237c7fb64dbSThomas Graf 			}
22386b3f8674SThomas Graf 		}
22396b3f8674SThomas Graf 	}
22406b3f8674SThomas Graf 
2241dc25c676SGao feng 	err = -ENOENT;
2242dc25c676SGao feng 	if ((tb[NDTA_THRESH1] || tb[NDTA_THRESH2] ||
2243dc25c676SGao feng 	     tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]) &&
2244dc25c676SGao feng 	    !net_eq(net, &init_net))
2245dc25c676SGao feng 		goto errout_tbl_lock;
2246dc25c676SGao feng 
22476b3f8674SThomas Graf 	if (tb[NDTA_THRESH1])
22486b3f8674SThomas Graf 		tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
22496b3f8674SThomas Graf 
22506b3f8674SThomas Graf 	if (tb[NDTA_THRESH2])
22516b3f8674SThomas Graf 		tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
22526b3f8674SThomas Graf 
22536b3f8674SThomas Graf 	if (tb[NDTA_THRESH3])
22546b3f8674SThomas Graf 		tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
22556b3f8674SThomas Graf 
22566b3f8674SThomas Graf 	if (tb[NDTA_GC_INTERVAL])
22576b3f8674SThomas Graf 		tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2258c7fb64dbSThomas Graf 
2259c7fb64dbSThomas Graf 	err = 0;
2260c7fb64dbSThomas Graf 
22616b3f8674SThomas Graf errout_tbl_lock:
2262c7fb64dbSThomas Graf 	write_unlock_bh(&tbl->lock);
22636b3f8674SThomas Graf errout:
2264c7fb64dbSThomas Graf 	return err;
2265c7fb64dbSThomas Graf }
2266c7fb64dbSThomas Graf 
22679632d47fSDavid Ahern static int neightbl_valid_dump_info(const struct nlmsghdr *nlh,
22689632d47fSDavid Ahern 				    struct netlink_ext_ack *extack)
22699632d47fSDavid Ahern {
22709632d47fSDavid Ahern 	struct ndtmsg *ndtm;
22719632d47fSDavid Ahern 
22729632d47fSDavid Ahern 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndtm))) {
22739632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid header for neighbor table dump request");
22749632d47fSDavid Ahern 		return -EINVAL;
22759632d47fSDavid Ahern 	}
22769632d47fSDavid Ahern 
22779632d47fSDavid Ahern 	ndtm = nlmsg_data(nlh);
22789632d47fSDavid Ahern 	if (ndtm->ndtm_pad1  || ndtm->ndtm_pad2) {
22799632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor table dump request");
22809632d47fSDavid Ahern 		return -EINVAL;
22819632d47fSDavid Ahern 	}
22829632d47fSDavid Ahern 
22839632d47fSDavid Ahern 	if (nlmsg_attrlen(nlh, sizeof(*ndtm))) {
22849632d47fSDavid Ahern 		NL_SET_ERR_MSG(extack, "Invalid data after header in neighbor table dump request");
22859632d47fSDavid Ahern 		return -EINVAL;
22869632d47fSDavid Ahern 	}
22879632d47fSDavid Ahern 
22889632d47fSDavid Ahern 	return 0;
22899632d47fSDavid Ahern }
22909632d47fSDavid Ahern 
2291c8822a4eSThomas Graf static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
2292c7fb64dbSThomas Graf {
22939632d47fSDavid Ahern 	const struct nlmsghdr *nlh = cb->nlh;
22943b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
2295ca860fb3SThomas Graf 	int family, tidx, nidx = 0;
2296ca860fb3SThomas Graf 	int tbl_skip = cb->args[0];
2297ca860fb3SThomas Graf 	int neigh_skip = cb->args[1];
2298c7fb64dbSThomas Graf 	struct neigh_table *tbl;
2299c7fb64dbSThomas Graf 
23009632d47fSDavid Ahern 	if (cb->strict_check) {
23019632d47fSDavid Ahern 		int err = neightbl_valid_dump_info(nlh, cb->extack);
23029632d47fSDavid Ahern 
23039632d47fSDavid Ahern 		if (err < 0)
23049632d47fSDavid Ahern 			return err;
23059632d47fSDavid Ahern 	}
23069632d47fSDavid Ahern 
23079632d47fSDavid Ahern 	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
2308c7fb64dbSThomas Graf 
2309d7480fd3SWANG Cong 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2310c7fb64dbSThomas Graf 		struct neigh_parms *p;
2311c7fb64dbSThomas Graf 
2312d7480fd3SWANG Cong 		tbl = neigh_tables[tidx];
2313d7480fd3SWANG Cong 		if (!tbl)
2314d7480fd3SWANG Cong 			continue;
2315d7480fd3SWANG Cong 
2316ca860fb3SThomas Graf 		if (tidx < tbl_skip || (family && tbl->family != family))
2317c7fb64dbSThomas Graf 			continue;
2318c7fb64dbSThomas Graf 
231915e47304SEric W. Biederman 		if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
23209632d47fSDavid Ahern 				       nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
23217b46a644SDavid S. Miller 				       NLM_F_MULTI) < 0)
2322c7fb64dbSThomas Graf 			break;
2323c7fb64dbSThomas Graf 
232475fbfd33SNicolas Dichtel 		nidx = 0;
232575fbfd33SNicolas Dichtel 		p = list_next_entry(&tbl->parms, list);
232675fbfd33SNicolas Dichtel 		list_for_each_entry_from(p, &tbl->parms_list, list) {
2327878628fbSYOSHIFUJI Hideaki 			if (!net_eq(neigh_parms_net(p), net))
2328426b5303SEric W. Biederman 				continue;
2329426b5303SEric W. Biederman 
2330efc683fcSGautam Kachroo 			if (nidx < neigh_skip)
2331efc683fcSGautam Kachroo 				goto next;
2332c7fb64dbSThomas Graf 
2333ca860fb3SThomas Graf 			if (neightbl_fill_param_info(skb, tbl, p,
233415e47304SEric W. Biederman 						     NETLINK_CB(cb->skb).portid,
23359632d47fSDavid Ahern 						     nlh->nlmsg_seq,
2336ca860fb3SThomas Graf 						     RTM_NEWNEIGHTBL,
23377b46a644SDavid S. Miller 						     NLM_F_MULTI) < 0)
2338c7fb64dbSThomas Graf 				goto out;
2339efc683fcSGautam Kachroo 		next:
2340efc683fcSGautam Kachroo 			nidx++;
2341c7fb64dbSThomas Graf 		}
2342c7fb64dbSThomas Graf 
2343ca860fb3SThomas Graf 		neigh_skip = 0;
2344c7fb64dbSThomas Graf 	}
2345c7fb64dbSThomas Graf out:
2346ca860fb3SThomas Graf 	cb->args[0] = tidx;
2347ca860fb3SThomas Graf 	cb->args[1] = nidx;
2348c7fb64dbSThomas Graf 
2349c7fb64dbSThomas Graf 	return skb->len;
2350c7fb64dbSThomas Graf }
23511da177e4SLinus Torvalds 
23528b8aec50SThomas Graf static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
23538b8aec50SThomas Graf 			   u32 pid, u32 seq, int type, unsigned int flags)
23541da177e4SLinus Torvalds {
23551da177e4SLinus Torvalds 	unsigned long now = jiffies;
23561da177e4SLinus Torvalds 	struct nda_cacheinfo ci;
23578b8aec50SThomas Graf 	struct nlmsghdr *nlh;
23588b8aec50SThomas Graf 	struct ndmsg *ndm;
23591da177e4SLinus Torvalds 
23608b8aec50SThomas Graf 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
23618b8aec50SThomas Graf 	if (nlh == NULL)
236226932566SPatrick McHardy 		return -EMSGSIZE;
23638b8aec50SThomas Graf 
23648b8aec50SThomas Graf 	ndm = nlmsg_data(nlh);
23658b8aec50SThomas Graf 	ndm->ndm_family	 = neigh->ops->family;
23669ef1d4c7SPatrick McHardy 	ndm->ndm_pad1    = 0;
23679ef1d4c7SPatrick McHardy 	ndm->ndm_pad2    = 0;
23688b8aec50SThomas Graf 	ndm->ndm_flags	 = neigh->flags;
23698b8aec50SThomas Graf 	ndm->ndm_type	 = neigh->type;
23708b8aec50SThomas Graf 	ndm->ndm_ifindex = neigh->dev->ifindex;
23711da177e4SLinus Torvalds 
23729a6308d7SDavid S. Miller 	if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
23739a6308d7SDavid S. Miller 		goto nla_put_failure;
23748b8aec50SThomas Graf 
23758b8aec50SThomas Graf 	read_lock_bh(&neigh->lock);
23768b8aec50SThomas Graf 	ndm->ndm_state	 = neigh->nud_state;
23770ed8ddf4SEric Dumazet 	if (neigh->nud_state & NUD_VALID) {
23780ed8ddf4SEric Dumazet 		char haddr[MAX_ADDR_LEN];
23790ed8ddf4SEric Dumazet 
23800ed8ddf4SEric Dumazet 		neigh_ha_snapshot(haddr, neigh, neigh->dev);
23810ed8ddf4SEric Dumazet 		if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
23828b8aec50SThomas Graf 			read_unlock_bh(&neigh->lock);
23838b8aec50SThomas Graf 			goto nla_put_failure;
23848b8aec50SThomas Graf 		}
23850ed8ddf4SEric Dumazet 	}
23868b8aec50SThomas Graf 
2387b9f5f52cSStephen Hemminger 	ci.ndm_used	 = jiffies_to_clock_t(now - neigh->used);
2388b9f5f52cSStephen Hemminger 	ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2389b9f5f52cSStephen Hemminger 	ci.ndm_updated	 = jiffies_to_clock_t(now - neigh->updated);
23909f237430SReshetova, Elena 	ci.ndm_refcnt	 = refcount_read(&neigh->refcnt) - 1;
23918b8aec50SThomas Graf 	read_unlock_bh(&neigh->lock);
23928b8aec50SThomas Graf 
23939a6308d7SDavid S. Miller 	if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
23949a6308d7SDavid S. Miller 	    nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
23959a6308d7SDavid S. Miller 		goto nla_put_failure;
23968b8aec50SThomas Graf 
2397053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2398053c095aSJohannes Berg 	return 0;
23998b8aec50SThomas Graf 
24008b8aec50SThomas Graf nla_put_failure:
240126932566SPatrick McHardy 	nlmsg_cancel(skb, nlh);
240226932566SPatrick McHardy 	return -EMSGSIZE;
24031da177e4SLinus Torvalds }
24041da177e4SLinus Torvalds 
240584920c14STony Zelenoff static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
240684920c14STony Zelenoff 			    u32 pid, u32 seq, int type, unsigned int flags,
240784920c14STony Zelenoff 			    struct neigh_table *tbl)
240884920c14STony Zelenoff {
240984920c14STony Zelenoff 	struct nlmsghdr *nlh;
241084920c14STony Zelenoff 	struct ndmsg *ndm;
241184920c14STony Zelenoff 
241284920c14STony Zelenoff 	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
241384920c14STony Zelenoff 	if (nlh == NULL)
241484920c14STony Zelenoff 		return -EMSGSIZE;
241584920c14STony Zelenoff 
241684920c14STony Zelenoff 	ndm = nlmsg_data(nlh);
241784920c14STony Zelenoff 	ndm->ndm_family	 = tbl->family;
241884920c14STony Zelenoff 	ndm->ndm_pad1    = 0;
241984920c14STony Zelenoff 	ndm->ndm_pad2    = 0;
242084920c14STony Zelenoff 	ndm->ndm_flags	 = pn->flags | NTF_PROXY;
2421545469f7SJun Zhao 	ndm->ndm_type	 = RTN_UNICAST;
24226adc5fd6SKonstantin Khlebnikov 	ndm->ndm_ifindex = pn->dev ? pn->dev->ifindex : 0;
242384920c14STony Zelenoff 	ndm->ndm_state	 = NUD_NONE;
242484920c14STony Zelenoff 
24259a6308d7SDavid S. Miller 	if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
24269a6308d7SDavid S. Miller 		goto nla_put_failure;
242784920c14STony Zelenoff 
2428053c095aSJohannes Berg 	nlmsg_end(skb, nlh);
2429053c095aSJohannes Berg 	return 0;
243084920c14STony Zelenoff 
243184920c14STony Zelenoff nla_put_failure:
243284920c14STony Zelenoff 	nlmsg_cancel(skb, nlh);
243384920c14STony Zelenoff 	return -EMSGSIZE;
243484920c14STony Zelenoff }
243584920c14STony Zelenoff 
24367b8f7a40SRoopa Prabhu static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid)
2437d961db35SThomas Graf {
2438d961db35SThomas Graf 	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
24397b8f7a40SRoopa Prabhu 	__neigh_notify(neigh, RTM_NEWNEIGH, 0, nlmsg_pid);
2440d961db35SThomas Graf }
24411da177e4SLinus Torvalds 
244221fdd092SDavid Ahern static bool neigh_master_filtered(struct net_device *dev, int master_idx)
244321fdd092SDavid Ahern {
244421fdd092SDavid Ahern 	struct net_device *master;
244521fdd092SDavid Ahern 
244621fdd092SDavid Ahern 	if (!master_idx)
244721fdd092SDavid Ahern 		return false;
244821fdd092SDavid Ahern 
2449aab456dfSEric Dumazet 	master = dev ? netdev_master_upper_dev_get(dev) : NULL;
245021fdd092SDavid Ahern 	if (!master || master->ifindex != master_idx)
245121fdd092SDavid Ahern 		return true;
245221fdd092SDavid Ahern 
245321fdd092SDavid Ahern 	return false;
245421fdd092SDavid Ahern }
245521fdd092SDavid Ahern 
245616660f0bSDavid Ahern static bool neigh_ifindex_filtered(struct net_device *dev, int filter_idx)
245716660f0bSDavid Ahern {
2458aab456dfSEric Dumazet 	if (filter_idx && (!dev || dev->ifindex != filter_idx))
245916660f0bSDavid Ahern 		return true;
246016660f0bSDavid Ahern 
246116660f0bSDavid Ahern 	return false;
246216660f0bSDavid Ahern }
246316660f0bSDavid Ahern 
24646f52f80eSDavid Ahern struct neigh_dump_filter {
24656f52f80eSDavid Ahern 	int master_idx;
24666f52f80eSDavid Ahern 	int dev_idx;
24676f52f80eSDavid Ahern };
24686f52f80eSDavid Ahern 
24691da177e4SLinus Torvalds static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
24706f52f80eSDavid Ahern 			    struct netlink_callback *cb,
24716f52f80eSDavid Ahern 			    struct neigh_dump_filter *filter)
24721da177e4SLinus Torvalds {
24733b1e0a65SYOSHIFUJI Hideaki 	struct net *net = sock_net(skb->sk);
24741da177e4SLinus Torvalds 	struct neighbour *n;
24751da177e4SLinus Torvalds 	int rc, h, s_h = cb->args[1];
24761da177e4SLinus Torvalds 	int idx, s_idx = idx = cb->args[2];
2477d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
247821fdd092SDavid Ahern 	unsigned int flags = NLM_F_MULTI;
247921fdd092SDavid Ahern 
24806f52f80eSDavid Ahern 	if (filter->dev_idx || filter->master_idx)
248121fdd092SDavid Ahern 		flags |= NLM_F_DUMP_FILTERED;
24821da177e4SLinus Torvalds 
2483d6bf7817SEric Dumazet 	rcu_read_lock_bh();
2484d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
2485d6bf7817SEric Dumazet 
24864bd6683bSEric Dumazet 	for (h = s_h; h < (1 << nht->hash_shift); h++) {
24871da177e4SLinus Torvalds 		if (h > s_h)
24881da177e4SLinus Torvalds 			s_idx = 0;
2489767e97e1SEric Dumazet 		for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2490767e97e1SEric Dumazet 		     n != NULL;
2491767e97e1SEric Dumazet 		     n = rcu_dereference_bh(n->next)) {
249218502acdSZhang Shengju 			if (idx < s_idx || !net_eq(dev_net(n->dev), net))
249318502acdSZhang Shengju 				goto next;
24946f52f80eSDavid Ahern 			if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
24956f52f80eSDavid Ahern 			    neigh_master_filtered(n->dev, filter->master_idx))
2496efc683fcSGautam Kachroo 				goto next;
249715e47304SEric W. Biederman 			if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
24981da177e4SLinus Torvalds 					    cb->nlh->nlmsg_seq,
2499b6544c0bSJamal Hadi Salim 					    RTM_NEWNEIGH,
250021fdd092SDavid Ahern 					    flags) < 0) {
25011da177e4SLinus Torvalds 				rc = -1;
25021da177e4SLinus Torvalds 				goto out;
25031da177e4SLinus Torvalds 			}
2504efc683fcSGautam Kachroo next:
2505efc683fcSGautam Kachroo 			idx++;
25061da177e4SLinus Torvalds 		}
25071da177e4SLinus Torvalds 	}
25081da177e4SLinus Torvalds 	rc = skb->len;
25091da177e4SLinus Torvalds out:
2510d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
25111da177e4SLinus Torvalds 	cb->args[1] = h;
25121da177e4SLinus Torvalds 	cb->args[2] = idx;
25131da177e4SLinus Torvalds 	return rc;
25141da177e4SLinus Torvalds }
25151da177e4SLinus Torvalds 
251684920c14STony Zelenoff static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
25176f52f80eSDavid Ahern 			     struct netlink_callback *cb,
25186f52f80eSDavid Ahern 			     struct neigh_dump_filter *filter)
251984920c14STony Zelenoff {
252084920c14STony Zelenoff 	struct pneigh_entry *n;
252184920c14STony Zelenoff 	struct net *net = sock_net(skb->sk);
252284920c14STony Zelenoff 	int rc, h, s_h = cb->args[3];
252384920c14STony Zelenoff 	int idx, s_idx = idx = cb->args[4];
25246f52f80eSDavid Ahern 	unsigned int flags = NLM_F_MULTI;
25256f52f80eSDavid Ahern 
25266f52f80eSDavid Ahern 	if (filter->dev_idx || filter->master_idx)
25276f52f80eSDavid Ahern 		flags |= NLM_F_DUMP_FILTERED;
252884920c14STony Zelenoff 
252984920c14STony Zelenoff 	read_lock_bh(&tbl->lock);
253084920c14STony Zelenoff 
25314bd6683bSEric Dumazet 	for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
253284920c14STony Zelenoff 		if (h > s_h)
253384920c14STony Zelenoff 			s_idx = 0;
253484920c14STony Zelenoff 		for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
253518502acdSZhang Shengju 			if (idx < s_idx || pneigh_net(n) != net)
253684920c14STony Zelenoff 				goto next;
25376f52f80eSDavid Ahern 			if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
25386f52f80eSDavid Ahern 			    neigh_master_filtered(n->dev, filter->master_idx))
25396f52f80eSDavid Ahern 				goto next;
254015e47304SEric W. Biederman 			if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
254184920c14STony Zelenoff 					    cb->nlh->nlmsg_seq,
25426f52f80eSDavid Ahern 					    RTM_NEWNEIGH, flags, tbl) < 0) {
254384920c14STony Zelenoff 				read_unlock_bh(&tbl->lock);
254484920c14STony Zelenoff 				rc = -1;
254584920c14STony Zelenoff 				goto out;
254684920c14STony Zelenoff 			}
254784920c14STony Zelenoff 		next:
254884920c14STony Zelenoff 			idx++;
254984920c14STony Zelenoff 		}
255084920c14STony Zelenoff 	}
255184920c14STony Zelenoff 
255284920c14STony Zelenoff 	read_unlock_bh(&tbl->lock);
255384920c14STony Zelenoff 	rc = skb->len;
255484920c14STony Zelenoff out:
255584920c14STony Zelenoff 	cb->args[3] = h;
255684920c14STony Zelenoff 	cb->args[4] = idx;
255784920c14STony Zelenoff 	return rc;
255884920c14STony Zelenoff 
255984920c14STony Zelenoff }
256084920c14STony Zelenoff 
256151183d23SDavid Ahern static int neigh_valid_dump_req(const struct nlmsghdr *nlh,
256251183d23SDavid Ahern 				bool strict_check,
256351183d23SDavid Ahern 				struct neigh_dump_filter *filter,
256451183d23SDavid Ahern 				struct netlink_ext_ack *extack)
256551183d23SDavid Ahern {
256651183d23SDavid Ahern 	struct nlattr *tb[NDA_MAX + 1];
256751183d23SDavid Ahern 	int err, i;
256851183d23SDavid Ahern 
256951183d23SDavid Ahern 	if (strict_check) {
257051183d23SDavid Ahern 		struct ndmsg *ndm;
257151183d23SDavid Ahern 
257251183d23SDavid Ahern 		if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
257351183d23SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid header for neighbor dump request");
257451183d23SDavid Ahern 			return -EINVAL;
257551183d23SDavid Ahern 		}
257651183d23SDavid Ahern 
257751183d23SDavid Ahern 		ndm = nlmsg_data(nlh);
257851183d23SDavid Ahern 		if (ndm->ndm_pad1  || ndm->ndm_pad2  || ndm->ndm_ifindex ||
257951183d23SDavid Ahern 		    ndm->ndm_state || ndm->ndm_flags || ndm->ndm_type) {
258051183d23SDavid Ahern 			NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor dump request");
258151183d23SDavid Ahern 			return -EINVAL;
258251183d23SDavid Ahern 		}
258351183d23SDavid Ahern 
258451183d23SDavid Ahern 		err = nlmsg_parse_strict(nlh, sizeof(struct ndmsg), tb, NDA_MAX,
258551183d23SDavid Ahern 					 NULL, extack);
258651183d23SDavid Ahern 	} else {
258751183d23SDavid Ahern 		err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX,
258851183d23SDavid Ahern 				  NULL, extack);
258951183d23SDavid Ahern 	}
259051183d23SDavid Ahern 	if (err < 0)
259151183d23SDavid Ahern 		return err;
259251183d23SDavid Ahern 
259351183d23SDavid Ahern 	for (i = 0; i <= NDA_MAX; ++i) {
259451183d23SDavid Ahern 		if (!tb[i])
259551183d23SDavid Ahern 			continue;
259651183d23SDavid Ahern 
259751183d23SDavid Ahern 		/* all new attributes should require strict_check */
259851183d23SDavid Ahern 		switch (i) {
259951183d23SDavid Ahern 		case NDA_IFINDEX:
260051183d23SDavid Ahern 			if (nla_len(tb[i]) != sizeof(u32)) {
260151183d23SDavid Ahern 				NL_SET_ERR_MSG(extack, "Invalid IFINDEX attribute in neighbor dump request");
260251183d23SDavid Ahern 				return -EINVAL;
260351183d23SDavid Ahern 			}
260451183d23SDavid Ahern 			filter->dev_idx = nla_get_u32(tb[i]);
260551183d23SDavid Ahern 			break;
260651183d23SDavid Ahern 		case NDA_MASTER:
260751183d23SDavid Ahern 			if (nla_len(tb[i]) != sizeof(u32)) {
260851183d23SDavid Ahern 				NL_SET_ERR_MSG(extack, "Invalid MASTER attribute in neighbor dump request");
260951183d23SDavid Ahern 				return -EINVAL;
261051183d23SDavid Ahern 			}
261151183d23SDavid Ahern 			filter->master_idx = nla_get_u32(tb[i]);
261251183d23SDavid Ahern 			break;
261351183d23SDavid Ahern 		default:
261451183d23SDavid Ahern 			if (strict_check) {
261551183d23SDavid Ahern 				NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor dump request");
261651183d23SDavid Ahern 				return -EINVAL;
261751183d23SDavid Ahern 			}
261851183d23SDavid Ahern 		}
261951183d23SDavid Ahern 	}
262051183d23SDavid Ahern 
262151183d23SDavid Ahern 	return 0;
262251183d23SDavid Ahern }
262351183d23SDavid Ahern 
2624c8822a4eSThomas Graf static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
26251da177e4SLinus Torvalds {
26266f52f80eSDavid Ahern 	const struct nlmsghdr *nlh = cb->nlh;
26276f52f80eSDavid Ahern 	struct neigh_dump_filter filter = {};
26281da177e4SLinus Torvalds 	struct neigh_table *tbl;
26291da177e4SLinus Torvalds 	int t, family, s_t;
263084920c14STony Zelenoff 	int proxy = 0;
26314bd6683bSEric Dumazet 	int err;
26321da177e4SLinus Torvalds 
26336f52f80eSDavid Ahern 	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
263484920c14STony Zelenoff 
263584920c14STony Zelenoff 	/* check for full ndmsg structure presence, family member is
263684920c14STony Zelenoff 	 * the same for both structures
263784920c14STony Zelenoff 	 */
26386f52f80eSDavid Ahern 	if (nlmsg_len(nlh) >= sizeof(struct ndmsg) &&
26396f52f80eSDavid Ahern 	    ((struct ndmsg *)nlmsg_data(nlh))->ndm_flags == NTF_PROXY)
264084920c14STony Zelenoff 		proxy = 1;
264184920c14STony Zelenoff 
264251183d23SDavid Ahern 	err = neigh_valid_dump_req(nlh, cb->strict_check, &filter, cb->extack);
264351183d23SDavid Ahern 	if (err < 0 && cb->strict_check)
264451183d23SDavid Ahern 		return err;
264551183d23SDavid Ahern 
26461da177e4SLinus Torvalds 	s_t = cb->args[0];
26471da177e4SLinus Torvalds 
2648d7480fd3SWANG Cong 	for (t = 0; t < NEIGH_NR_TABLES; t++) {
2649d7480fd3SWANG Cong 		tbl = neigh_tables[t];
2650d7480fd3SWANG Cong 
2651d7480fd3SWANG Cong 		if (!tbl)
2652d7480fd3SWANG Cong 			continue;
26531da177e4SLinus Torvalds 		if (t < s_t || (family && tbl->family != family))
26541da177e4SLinus Torvalds 			continue;
26551da177e4SLinus Torvalds 		if (t > s_t)
26561da177e4SLinus Torvalds 			memset(&cb->args[1], 0, sizeof(cb->args) -
26571da177e4SLinus Torvalds 						sizeof(cb->args[0]));
265884920c14STony Zelenoff 		if (proxy)
26596f52f80eSDavid Ahern 			err = pneigh_dump_table(tbl, skb, cb, &filter);
266084920c14STony Zelenoff 		else
26616f52f80eSDavid Ahern 			err = neigh_dump_table(tbl, skb, cb, &filter);
26624bd6683bSEric Dumazet 		if (err < 0)
26634bd6683bSEric Dumazet 			break;
26641da177e4SLinus Torvalds 	}
26651da177e4SLinus Torvalds 
26661da177e4SLinus Torvalds 	cb->args[0] = t;
26671da177e4SLinus Torvalds 	return skb->len;
26681da177e4SLinus Torvalds }
26691da177e4SLinus Torvalds 
26701da177e4SLinus Torvalds void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
26711da177e4SLinus Torvalds {
26721da177e4SLinus Torvalds 	int chain;
2673d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
26741da177e4SLinus Torvalds 
2675d6bf7817SEric Dumazet 	rcu_read_lock_bh();
2676d6bf7817SEric Dumazet 	nht = rcu_dereference_bh(tbl->nht);
2677d6bf7817SEric Dumazet 
2678767e97e1SEric Dumazet 	read_lock(&tbl->lock); /* avoid resizes */
2679cd089336SDavid S. Miller 	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
26801da177e4SLinus Torvalds 		struct neighbour *n;
26811da177e4SLinus Torvalds 
2682767e97e1SEric Dumazet 		for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
2683767e97e1SEric Dumazet 		     n != NULL;
2684767e97e1SEric Dumazet 		     n = rcu_dereference_bh(n->next))
26851da177e4SLinus Torvalds 			cb(n, cookie);
26861da177e4SLinus Torvalds 	}
2687d6bf7817SEric Dumazet 	read_unlock(&tbl->lock);
2688d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
26891da177e4SLinus Torvalds }
26901da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_for_each);
26911da177e4SLinus Torvalds 
26921da177e4SLinus Torvalds /* The tbl->lock must be held as a writer and BH disabled. */
26931da177e4SLinus Torvalds void __neigh_for_each_release(struct neigh_table *tbl,
26941da177e4SLinus Torvalds 			      int (*cb)(struct neighbour *))
26951da177e4SLinus Torvalds {
26961da177e4SLinus Torvalds 	int chain;
2697d6bf7817SEric Dumazet 	struct neigh_hash_table *nht;
26981da177e4SLinus Torvalds 
2699d6bf7817SEric Dumazet 	nht = rcu_dereference_protected(tbl->nht,
2700d6bf7817SEric Dumazet 					lockdep_is_held(&tbl->lock));
2701cd089336SDavid S. Miller 	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
2702767e97e1SEric Dumazet 		struct neighbour *n;
2703767e97e1SEric Dumazet 		struct neighbour __rcu **np;
27041da177e4SLinus Torvalds 
2705d6bf7817SEric Dumazet 		np = &nht->hash_buckets[chain];
2706767e97e1SEric Dumazet 		while ((n = rcu_dereference_protected(*np,
2707767e97e1SEric Dumazet 					lockdep_is_held(&tbl->lock))) != NULL) {
27081da177e4SLinus Torvalds 			int release;
27091da177e4SLinus Torvalds 
27101da177e4SLinus Torvalds 			write_lock(&n->lock);
27111da177e4SLinus Torvalds 			release = cb(n);
27121da177e4SLinus Torvalds 			if (release) {
2713767e97e1SEric Dumazet 				rcu_assign_pointer(*np,
2714767e97e1SEric Dumazet 					rcu_dereference_protected(n->next,
2715767e97e1SEric Dumazet 						lockdep_is_held(&tbl->lock)));
271658956317SDavid Ahern 				neigh_mark_dead(n);
27171da177e4SLinus Torvalds 			} else
27181da177e4SLinus Torvalds 				np = &n->next;
27191da177e4SLinus Torvalds 			write_unlock(&n->lock);
27204f494554SThomas Graf 			if (release)
27214f494554SThomas Graf 				neigh_cleanup_and_release(n);
27221da177e4SLinus Torvalds 		}
27231da177e4SLinus Torvalds 	}
2724ecbb4169SAlexey Kuznetsov }
27251da177e4SLinus Torvalds EXPORT_SYMBOL(__neigh_for_each_release);
27261da177e4SLinus Torvalds 
2727b79bda3dSEric W. Biederman int neigh_xmit(int index, struct net_device *dev,
27284fd3d7d9SEric W. Biederman 	       const void *addr, struct sk_buff *skb)
27294fd3d7d9SEric W. Biederman {
2730b79bda3dSEric W. Biederman 	int err = -EAFNOSUPPORT;
2731b79bda3dSEric W. Biederman 	if (likely(index < NEIGH_NR_TABLES)) {
27324fd3d7d9SEric W. Biederman 		struct neigh_table *tbl;
27334fd3d7d9SEric W. Biederman 		struct neighbour *neigh;
27344fd3d7d9SEric W. Biederman 
2735b79bda3dSEric W. Biederman 		tbl = neigh_tables[index];
27364fd3d7d9SEric W. Biederman 		if (!tbl)
27374fd3d7d9SEric W. Biederman 			goto out;
2738b560f03dSDavid Barroso 		rcu_read_lock_bh();
27394fd3d7d9SEric W. Biederman 		neigh = __neigh_lookup_noref(tbl, addr, dev);
27404fd3d7d9SEric W. Biederman 		if (!neigh)
27414fd3d7d9SEric W. Biederman 			neigh = __neigh_create(tbl, addr, dev, false);
27424fd3d7d9SEric W. Biederman 		err = PTR_ERR(neigh);
2743b560f03dSDavid Barroso 		if (IS_ERR(neigh)) {
2744b560f03dSDavid Barroso 			rcu_read_unlock_bh();
27454fd3d7d9SEric W. Biederman 			goto out_kfree_skb;
2746b560f03dSDavid Barroso 		}
27474fd3d7d9SEric W. Biederman 		err = neigh->output(neigh, skb);
2748b560f03dSDavid Barroso 		rcu_read_unlock_bh();
27494fd3d7d9SEric W. Biederman 	}
2750b79bda3dSEric W. Biederman 	else if (index == NEIGH_LINK_TABLE) {
2751b79bda3dSEric W. Biederman 		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
2752b79bda3dSEric W. Biederman 				      addr, NULL, skb->len);
2753b79bda3dSEric W. Biederman 		if (err < 0)
2754b79bda3dSEric W. Biederman 			goto out_kfree_skb;
2755b79bda3dSEric W. Biederman 		err = dev_queue_xmit(skb);
2756b79bda3dSEric W. Biederman 	}
27574fd3d7d9SEric W. Biederman out:
27584fd3d7d9SEric W. Biederman 	return err;
27594fd3d7d9SEric W. Biederman out_kfree_skb:
27604fd3d7d9SEric W. Biederman 	kfree_skb(skb);
27614fd3d7d9SEric W. Biederman 	goto out;
27624fd3d7d9SEric W. Biederman }
27634fd3d7d9SEric W. Biederman EXPORT_SYMBOL(neigh_xmit);
27644fd3d7d9SEric W. Biederman 
27651da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
27661da177e4SLinus Torvalds 
27671da177e4SLinus Torvalds static struct neighbour *neigh_get_first(struct seq_file *seq)
27681da177e4SLinus Torvalds {
27691da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
27701218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
2771d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = state->nht;
27721da177e4SLinus Torvalds 	struct neighbour *n = NULL;
27731da177e4SLinus Torvalds 	int bucket = state->bucket;
27741da177e4SLinus Torvalds 
27751da177e4SLinus Torvalds 	state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
2776cd089336SDavid S. Miller 	for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
2777767e97e1SEric Dumazet 		n = rcu_dereference_bh(nht->hash_buckets[bucket]);
27781da177e4SLinus Torvalds 
27791da177e4SLinus Torvalds 		while (n) {
2780878628fbSYOSHIFUJI Hideaki 			if (!net_eq(dev_net(n->dev), net))
2781426b5303SEric W. Biederman 				goto next;
27821da177e4SLinus Torvalds 			if (state->neigh_sub_iter) {
27831da177e4SLinus Torvalds 				loff_t fakep = 0;
27841da177e4SLinus Torvalds 				void *v;
27851da177e4SLinus Torvalds 
27861da177e4SLinus Torvalds 				v = state->neigh_sub_iter(state, n, &fakep);
27871da177e4SLinus Torvalds 				if (!v)
27881da177e4SLinus Torvalds 					goto next;
27891da177e4SLinus Torvalds 			}
27901da177e4SLinus Torvalds 			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
27911da177e4SLinus Torvalds 				break;
27921da177e4SLinus Torvalds 			if (n->nud_state & ~NUD_NOARP)
27931da177e4SLinus Torvalds 				break;
27941da177e4SLinus Torvalds next:
2795767e97e1SEric Dumazet 			n = rcu_dereference_bh(n->next);
27961da177e4SLinus Torvalds 		}
27971da177e4SLinus Torvalds 
27981da177e4SLinus Torvalds 		if (n)
27991da177e4SLinus Torvalds 			break;
28001da177e4SLinus Torvalds 	}
28011da177e4SLinus Torvalds 	state->bucket = bucket;
28021da177e4SLinus Torvalds 
28031da177e4SLinus Torvalds 	return n;
28041da177e4SLinus Torvalds }
28051da177e4SLinus Torvalds 
28061da177e4SLinus Torvalds static struct neighbour *neigh_get_next(struct seq_file *seq,
28071da177e4SLinus Torvalds 					struct neighbour *n,
28081da177e4SLinus Torvalds 					loff_t *pos)
28091da177e4SLinus Torvalds {
28101da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
28111218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
2812d6bf7817SEric Dumazet 	struct neigh_hash_table *nht = state->nht;
28131da177e4SLinus Torvalds 
28141da177e4SLinus Torvalds 	if (state->neigh_sub_iter) {
28151da177e4SLinus Torvalds 		void *v = state->neigh_sub_iter(state, n, pos);
28161da177e4SLinus Torvalds 		if (v)
28171da177e4SLinus Torvalds 			return n;
28181da177e4SLinus Torvalds 	}
2819767e97e1SEric Dumazet 	n = rcu_dereference_bh(n->next);
28201da177e4SLinus Torvalds 
28211da177e4SLinus Torvalds 	while (1) {
28221da177e4SLinus Torvalds 		while (n) {
2823878628fbSYOSHIFUJI Hideaki 			if (!net_eq(dev_net(n->dev), net))
2824426b5303SEric W. Biederman 				goto next;
28251da177e4SLinus Torvalds 			if (state->neigh_sub_iter) {
28261da177e4SLinus Torvalds 				void *v = state->neigh_sub_iter(state, n, pos);
28271da177e4SLinus Torvalds 				if (v)
28281da177e4SLinus Torvalds 					return n;
28291da177e4SLinus Torvalds 				goto next;
28301da177e4SLinus Torvalds 			}
28311da177e4SLinus Torvalds 			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
28321da177e4SLinus Torvalds 				break;
28331da177e4SLinus Torvalds 
28341da177e4SLinus Torvalds 			if (n->nud_state & ~NUD_NOARP)
28351da177e4SLinus Torvalds 				break;
28361da177e4SLinus Torvalds next:
2837767e97e1SEric Dumazet 			n = rcu_dereference_bh(n->next);
28381da177e4SLinus Torvalds 		}
28391da177e4SLinus Torvalds 
28401da177e4SLinus Torvalds 		if (n)
28411da177e4SLinus Torvalds 			break;
28421da177e4SLinus Torvalds 
2843cd089336SDavid S. Miller 		if (++state->bucket >= (1 << nht->hash_shift))
28441da177e4SLinus Torvalds 			break;
28451da177e4SLinus Torvalds 
2846767e97e1SEric Dumazet 		n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
28471da177e4SLinus Torvalds 	}
28481da177e4SLinus Torvalds 
28491da177e4SLinus Torvalds 	if (n && pos)
28501da177e4SLinus Torvalds 		--(*pos);
28511da177e4SLinus Torvalds 	return n;
28521da177e4SLinus Torvalds }
28531da177e4SLinus Torvalds 
28541da177e4SLinus Torvalds static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
28551da177e4SLinus Torvalds {
28561da177e4SLinus Torvalds 	struct neighbour *n = neigh_get_first(seq);
28571da177e4SLinus Torvalds 
28581da177e4SLinus Torvalds 	if (n) {
2859745e2031SChris Larson 		--(*pos);
28601da177e4SLinus Torvalds 		while (*pos) {
28611da177e4SLinus Torvalds 			n = neigh_get_next(seq, n, pos);
28621da177e4SLinus Torvalds 			if (!n)
28631da177e4SLinus Torvalds 				break;
28641da177e4SLinus Torvalds 		}
28651da177e4SLinus Torvalds 	}
28661da177e4SLinus Torvalds 	return *pos ? NULL : n;
28671da177e4SLinus Torvalds }
28681da177e4SLinus Torvalds 
28691da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
28701da177e4SLinus Torvalds {
28711da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
28721218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
28731da177e4SLinus Torvalds 	struct neigh_table *tbl = state->tbl;
28741da177e4SLinus Torvalds 	struct pneigh_entry *pn = NULL;
28751da177e4SLinus Torvalds 	int bucket = state->bucket;
28761da177e4SLinus Torvalds 
28771da177e4SLinus Torvalds 	state->flags |= NEIGH_SEQ_IS_PNEIGH;
28781da177e4SLinus Torvalds 	for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
28791da177e4SLinus Torvalds 		pn = tbl->phash_buckets[bucket];
2880878628fbSYOSHIFUJI Hideaki 		while (pn && !net_eq(pneigh_net(pn), net))
2881426b5303SEric W. Biederman 			pn = pn->next;
28821da177e4SLinus Torvalds 		if (pn)
28831da177e4SLinus Torvalds 			break;
28841da177e4SLinus Torvalds 	}
28851da177e4SLinus Torvalds 	state->bucket = bucket;
28861da177e4SLinus Torvalds 
28871da177e4SLinus Torvalds 	return pn;
28881da177e4SLinus Torvalds }
28891da177e4SLinus Torvalds 
28901da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
28911da177e4SLinus Torvalds 					    struct pneigh_entry *pn,
28921da177e4SLinus Torvalds 					    loff_t *pos)
28931da177e4SLinus Torvalds {
28941da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
28951218854aSYOSHIFUJI Hideaki 	struct net *net = seq_file_net(seq);
28961da177e4SLinus Torvalds 	struct neigh_table *tbl = state->tbl;
28971da177e4SLinus Torvalds 
2898df07a94cSJorge Boncompte [DTI2] 	do {
28991da177e4SLinus Torvalds 		pn = pn->next;
2900df07a94cSJorge Boncompte [DTI2] 	} while (pn && !net_eq(pneigh_net(pn), net));
2901df07a94cSJorge Boncompte [DTI2] 
29021da177e4SLinus Torvalds 	while (!pn) {
29031da177e4SLinus Torvalds 		if (++state->bucket > PNEIGH_HASHMASK)
29041da177e4SLinus Torvalds 			break;
29051da177e4SLinus Torvalds 		pn = tbl->phash_buckets[state->bucket];
2906878628fbSYOSHIFUJI Hideaki 		while (pn && !net_eq(pneigh_net(pn), net))
2907426b5303SEric W. Biederman 			pn = pn->next;
29081da177e4SLinus Torvalds 		if (pn)
29091da177e4SLinus Torvalds 			break;
29101da177e4SLinus Torvalds 	}
29111da177e4SLinus Torvalds 
29121da177e4SLinus Torvalds 	if (pn && pos)
29131da177e4SLinus Torvalds 		--(*pos);
29141da177e4SLinus Torvalds 
29151da177e4SLinus Torvalds 	return pn;
29161da177e4SLinus Torvalds }
29171da177e4SLinus Torvalds 
29181da177e4SLinus Torvalds static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
29191da177e4SLinus Torvalds {
29201da177e4SLinus Torvalds 	struct pneigh_entry *pn = pneigh_get_first(seq);
29211da177e4SLinus Torvalds 
29221da177e4SLinus Torvalds 	if (pn) {
2923745e2031SChris Larson 		--(*pos);
29241da177e4SLinus Torvalds 		while (*pos) {
29251da177e4SLinus Torvalds 			pn = pneigh_get_next(seq, pn, pos);
29261da177e4SLinus Torvalds 			if (!pn)
29271da177e4SLinus Torvalds 				break;
29281da177e4SLinus Torvalds 		}
29291da177e4SLinus Torvalds 	}
29301da177e4SLinus Torvalds 	return *pos ? NULL : pn;
29311da177e4SLinus Torvalds }
29321da177e4SLinus Torvalds 
29331da177e4SLinus Torvalds static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
29341da177e4SLinus Torvalds {
29351da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
29361da177e4SLinus Torvalds 	void *rc;
2937745e2031SChris Larson 	loff_t idxpos = *pos;
29381da177e4SLinus Torvalds 
2939745e2031SChris Larson 	rc = neigh_get_idx(seq, &idxpos);
29401da177e4SLinus Torvalds 	if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
2941745e2031SChris Larson 		rc = pneigh_get_idx(seq, &idxpos);
29421da177e4SLinus Torvalds 
29431da177e4SLinus Torvalds 	return rc;
29441da177e4SLinus Torvalds }
29451da177e4SLinus Torvalds 
29461da177e4SLinus Torvalds void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags)
2947d6bf7817SEric Dumazet 	__acquires(rcu_bh)
29481da177e4SLinus Torvalds {
29491da177e4SLinus Torvalds 	struct neigh_seq_state *state = seq->private;
29501da177e4SLinus Torvalds 
29511da177e4SLinus Torvalds 	state->tbl = tbl;
29521da177e4SLinus Torvalds 	state->bucket = 0;
29531da177e4SLinus Torvalds 	state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
29541da177e4SLinus Torvalds 
2955d6bf7817SEric Dumazet 	rcu_read_lock_bh();
2956d6bf7817SEric Dumazet 	state->nht = rcu_dereference_bh(tbl->nht);
2957767e97e1SEric Dumazet 
2958745e2031SChris Larson 	return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
29591da177e4SLinus Torvalds }
29601da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_start);
29611da177e4SLinus Torvalds 
29621da177e4SLinus Torvalds void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
29631da177e4SLinus Torvalds {
29641da177e4SLinus Torvalds 	struct neigh_seq_state *state;
29651da177e4SLinus Torvalds 	void *rc;
29661da177e4SLinus Torvalds 
29671da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN) {
2968bff69732SChris Larson 		rc = neigh_get_first(seq);
29691da177e4SLinus Torvalds 		goto out;
29701da177e4SLinus Torvalds 	}
29711da177e4SLinus Torvalds 
29721da177e4SLinus Torvalds 	state = seq->private;
29731da177e4SLinus Torvalds 	if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
29741da177e4SLinus Torvalds 		rc = neigh_get_next(seq, v, NULL);
29751da177e4SLinus Torvalds 		if (rc)
29761da177e4SLinus Torvalds 			goto out;
29771da177e4SLinus Torvalds 		if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
29781da177e4SLinus Torvalds 			rc = pneigh_get_first(seq);
29791da177e4SLinus Torvalds 	} else {
29801da177e4SLinus Torvalds 		BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
29811da177e4SLinus Torvalds 		rc = pneigh_get_next(seq, v, NULL);
29821da177e4SLinus Torvalds 	}
29831da177e4SLinus Torvalds out:
29841da177e4SLinus Torvalds 	++(*pos);
29851da177e4SLinus Torvalds 	return rc;
29861da177e4SLinus Torvalds }
29871da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_next);
29881da177e4SLinus Torvalds 
29891da177e4SLinus Torvalds void neigh_seq_stop(struct seq_file *seq, void *v)
2990d6bf7817SEric Dumazet 	__releases(rcu_bh)
29911da177e4SLinus Torvalds {
2992d6bf7817SEric Dumazet 	rcu_read_unlock_bh();
29931da177e4SLinus Torvalds }
29941da177e4SLinus Torvalds EXPORT_SYMBOL(neigh_seq_stop);
29951da177e4SLinus Torvalds 
29961da177e4SLinus Torvalds /* statistics via seq_file */
29971da177e4SLinus Torvalds 
29981da177e4SLinus Torvalds static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
29991da177e4SLinus Torvalds {
300071a5053aSChristoph Hellwig 	struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
30011da177e4SLinus Torvalds 	int cpu;
30021da177e4SLinus Torvalds 
30031da177e4SLinus Torvalds 	if (*pos == 0)
30041da177e4SLinus Torvalds 		return SEQ_START_TOKEN;
30051da177e4SLinus Torvalds 
30060f23174aSRusty Russell 	for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
30071da177e4SLinus Torvalds 		if (!cpu_possible(cpu))
30081da177e4SLinus Torvalds 			continue;
30091da177e4SLinus Torvalds 		*pos = cpu+1;
30101da177e4SLinus Torvalds 		return per_cpu_ptr(tbl->stats, cpu);
30111da177e4SLinus Torvalds 	}
30121da177e4SLinus Torvalds 	return NULL;
30131da177e4SLinus Torvalds }
30141da177e4SLinus Torvalds 
30151da177e4SLinus Torvalds static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
30161da177e4SLinus Torvalds {
301771a5053aSChristoph Hellwig 	struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
30181da177e4SLinus Torvalds 	int cpu;
30191da177e4SLinus Torvalds 
30200f23174aSRusty Russell 	for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
30211da177e4SLinus Torvalds 		if (!cpu_possible(cpu))
30221da177e4SLinus Torvalds 			continue;
30231da177e4SLinus Torvalds 		*pos = cpu+1;
30241da177e4SLinus Torvalds 		return per_cpu_ptr(tbl->stats, cpu);
30251da177e4SLinus Torvalds 	}
30261da177e4SLinus Torvalds 	return NULL;
30271da177e4SLinus Torvalds }
30281da177e4SLinus Torvalds 
30291da177e4SLinus Torvalds static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
30301da177e4SLinus Torvalds {
30311da177e4SLinus Torvalds 
30321da177e4SLinus Torvalds }
30331da177e4SLinus Torvalds 
30341da177e4SLinus Torvalds static int neigh_stat_seq_show(struct seq_file *seq, void *v)
30351da177e4SLinus Torvalds {
303671a5053aSChristoph Hellwig 	struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
30371da177e4SLinus Torvalds 	struct neigh_statistics *st = v;
30381da177e4SLinus Torvalds 
30391da177e4SLinus Torvalds 	if (v == SEQ_START_TOKEN) {
3040fb811395SRick 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");
30411da177e4SLinus Torvalds 		return 0;
30421da177e4SLinus Torvalds 	}
30431da177e4SLinus Torvalds 
30441da177e4SLinus Torvalds 	seq_printf(seq, "%08x  %08lx %08lx %08lx  %08lx %08lx  %08lx  "
3045fb811395SRick Jones 			"%08lx %08lx  %08lx %08lx %08lx %08lx\n",
30461da177e4SLinus Torvalds 		   atomic_read(&tbl->entries),
30471da177e4SLinus Torvalds 
30481da177e4SLinus Torvalds 		   st->allocs,
30491da177e4SLinus Torvalds 		   st->destroys,
30501da177e4SLinus Torvalds 		   st->hash_grows,
30511da177e4SLinus Torvalds 
30521da177e4SLinus Torvalds 		   st->lookups,
30531da177e4SLinus Torvalds 		   st->hits,
30541da177e4SLinus Torvalds 
30551da177e4SLinus Torvalds 		   st->res_failed,
30561da177e4SLinus Torvalds 
30571da177e4SLinus Torvalds 		   st->rcv_probes_mcast,
30581da177e4SLinus Torvalds 		   st->rcv_probes_ucast,
30591da177e4SLinus Torvalds 
30601da177e4SLinus Torvalds 		   st->periodic_gc_runs,
30619a6d276eSNeil Horman 		   st->forced_gc_runs,
3062fb811395SRick Jones 		   st->unres_discards,
3063fb811395SRick Jones 		   st->table_fulls
30641da177e4SLinus Torvalds 		   );
30651da177e4SLinus Torvalds 
30661da177e4SLinus Torvalds 	return 0;
30671da177e4SLinus Torvalds }
30681da177e4SLinus Torvalds 
3069f690808eSStephen Hemminger static const struct seq_operations neigh_stat_seq_ops = {
30701da177e4SLinus Torvalds 	.start	= neigh_stat_seq_start,
30711da177e4SLinus Torvalds 	.next	= neigh_stat_seq_next,
30721da177e4SLinus Torvalds 	.stop	= neigh_stat_seq_stop,
30731da177e4SLinus Torvalds 	.show	= neigh_stat_seq_show,
30741da177e4SLinus Torvalds };
30751da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */
30761da177e4SLinus Torvalds 
3077339bf98fSThomas Graf static inline size_t neigh_nlmsg_size(void)
3078339bf98fSThomas Graf {
3079339bf98fSThomas Graf 	return NLMSG_ALIGN(sizeof(struct ndmsg))
3080339bf98fSThomas Graf 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
3081339bf98fSThomas Graf 	       + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
3082339bf98fSThomas Graf 	       + nla_total_size(sizeof(struct nda_cacheinfo))
3083339bf98fSThomas Graf 	       + nla_total_size(4); /* NDA_PROBES */
3084339bf98fSThomas Graf }
3085339bf98fSThomas Graf 
30867b8f7a40SRoopa Prabhu static void __neigh_notify(struct neighbour *n, int type, int flags,
30877b8f7a40SRoopa Prabhu 			   u32 pid)
30881da177e4SLinus Torvalds {
3089c346dca1SYOSHIFUJI Hideaki 	struct net *net = dev_net(n->dev);
30908b8aec50SThomas Graf 	struct sk_buff *skb;
3091b8673311SThomas Graf 	int err = -ENOBUFS;
30921da177e4SLinus Torvalds 
3093339bf98fSThomas Graf 	skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
30948b8aec50SThomas Graf 	if (skb == NULL)
3095b8673311SThomas Graf 		goto errout;
30961da177e4SLinus Torvalds 
30977b8f7a40SRoopa Prabhu 	err = neigh_fill_info(skb, n, pid, 0, type, flags);
309826932566SPatrick McHardy 	if (err < 0) {
309926932566SPatrick McHardy 		/* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
310026932566SPatrick McHardy 		WARN_ON(err == -EMSGSIZE);
310126932566SPatrick McHardy 		kfree_skb(skb);
310226932566SPatrick McHardy 		goto errout;
310326932566SPatrick McHardy 	}
31041ce85fe4SPablo Neira Ayuso 	rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
31051ce85fe4SPablo Neira Ayuso 	return;
3106b8673311SThomas Graf errout:
3107b8673311SThomas Graf 	if (err < 0)
3108426b5303SEric W. Biederman 		rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
3109b8673311SThomas Graf }
3110b8673311SThomas Graf 
3111b8673311SThomas Graf void neigh_app_ns(struct neighbour *n)
3112b8673311SThomas Graf {
31137b8f7a40SRoopa Prabhu 	__neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST, 0);
31148b8aec50SThomas Graf }
31150a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_app_ns);
31161da177e4SLinus Torvalds 
31171da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL
3118b93196dcSCong Wang static int zero;
3119555445cdSFrancesco Fusco static int int_max = INT_MAX;
3120b93196dcSCong Wang static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
31211da177e4SLinus Torvalds 
3122fe2c6338SJoe Perches static int proc_unres_qlen(struct ctl_table *ctl, int write,
3123fe2c6338SJoe Perches 			   void __user *buffer, size_t *lenp, loff_t *ppos)
31248b5c171bSEric Dumazet {
31258b5c171bSEric Dumazet 	int size, ret;
3126fe2c6338SJoe Perches 	struct ctl_table tmp = *ctl;
31278b5c171bSEric Dumazet 
3128ce46cc64SShan Wei 	tmp.extra1 = &zero;
3129ce46cc64SShan Wei 	tmp.extra2 = &unres_qlen_max;
31308b5c171bSEric Dumazet 	tmp.data = &size;
3131ce46cc64SShan Wei 
3132ce46cc64SShan Wei 	size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN);
3133ce46cc64SShan Wei 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
3134ce46cc64SShan Wei 
31358b5c171bSEric Dumazet 	if (write && !ret)
31368b5c171bSEric Dumazet 		*(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
31378b5c171bSEric Dumazet 	return ret;
31388b5c171bSEric Dumazet }
31398b5c171bSEric Dumazet 
31401d4c8c29SJiri Pirko static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
31411d4c8c29SJiri Pirko 						   int family)
31421d4c8c29SJiri Pirko {
3143bba24896SJiri Pirko 	switch (family) {
3144bba24896SJiri Pirko 	case AF_INET:
31451d4c8c29SJiri Pirko 		return __in_dev_arp_parms_get_rcu(dev);
3146bba24896SJiri Pirko 	case AF_INET6:
3147bba24896SJiri Pirko 		return __in6_dev_nd_parms_get_rcu(dev);
3148bba24896SJiri Pirko 	}
31491d4c8c29SJiri Pirko 	return NULL;
31501d4c8c29SJiri Pirko }
31511d4c8c29SJiri Pirko 
31521d4c8c29SJiri Pirko static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
31531d4c8c29SJiri Pirko 				  int index)
31541d4c8c29SJiri Pirko {
31551d4c8c29SJiri Pirko 	struct net_device *dev;
31561d4c8c29SJiri Pirko 	int family = neigh_parms_family(p);
31571d4c8c29SJiri Pirko 
31581d4c8c29SJiri Pirko 	rcu_read_lock();
31591d4c8c29SJiri Pirko 	for_each_netdev_rcu(net, dev) {
31601d4c8c29SJiri Pirko 		struct neigh_parms *dst_p =
31611d4c8c29SJiri Pirko 				neigh_get_dev_parms_rcu(dev, family);
31621d4c8c29SJiri Pirko 
31631d4c8c29SJiri Pirko 		if (dst_p && !test_bit(index, dst_p->data_state))
31641d4c8c29SJiri Pirko 			dst_p->data[index] = p->data[index];
31651d4c8c29SJiri Pirko 	}
31661d4c8c29SJiri Pirko 	rcu_read_unlock();
31671d4c8c29SJiri Pirko }
31681d4c8c29SJiri Pirko 
31691d4c8c29SJiri Pirko static void neigh_proc_update(struct ctl_table *ctl, int write)
31701d4c8c29SJiri Pirko {
31711d4c8c29SJiri Pirko 	struct net_device *dev = ctl->extra1;
31721d4c8c29SJiri Pirko 	struct neigh_parms *p = ctl->extra2;
317377d47afbSJiri Pirko 	struct net *net = neigh_parms_net(p);
31741d4c8c29SJiri Pirko 	int index = (int *) ctl->data - p->data;
31751d4c8c29SJiri Pirko 
31761d4c8c29SJiri Pirko 	if (!write)
31771d4c8c29SJiri Pirko 		return;
31781d4c8c29SJiri Pirko 
31791d4c8c29SJiri Pirko 	set_bit(index, p->data_state);
31807627ae60SMarcus Huewe 	if (index == NEIGH_VAR_DELAY_PROBE_TIME)
31812a4501aeSIdo Schimmel 		call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
31821d4c8c29SJiri Pirko 	if (!dev) /* NULL dev means this is default value */
31831d4c8c29SJiri Pirko 		neigh_copy_dflt_parms(net, p, index);
31841d4c8c29SJiri Pirko }
31851d4c8c29SJiri Pirko 
31861f9248e5SJiri Pirko static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
31871f9248e5SJiri Pirko 					   void __user *buffer,
31881f9248e5SJiri Pirko 					   size_t *lenp, loff_t *ppos)
31891f9248e5SJiri Pirko {
31901f9248e5SJiri Pirko 	struct ctl_table tmp = *ctl;
31911d4c8c29SJiri Pirko 	int ret;
31921f9248e5SJiri Pirko 
31931f9248e5SJiri Pirko 	tmp.extra1 = &zero;
31941f9248e5SJiri Pirko 	tmp.extra2 = &int_max;
31951f9248e5SJiri Pirko 
31961d4c8c29SJiri Pirko 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
31971d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
31981d4c8c29SJiri Pirko 	return ret;
31991f9248e5SJiri Pirko }
32001f9248e5SJiri Pirko 
3201cb5b09c1SJiri Pirko int neigh_proc_dointvec(struct ctl_table *ctl, int write,
3202cb5b09c1SJiri Pirko 			void __user *buffer, size_t *lenp, loff_t *ppos)
3203cb5b09c1SJiri Pirko {
32041d4c8c29SJiri Pirko 	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
32051d4c8c29SJiri Pirko 
32061d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
32071d4c8c29SJiri Pirko 	return ret;
3208cb5b09c1SJiri Pirko }
3209cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec);
3210cb5b09c1SJiri Pirko 
3211cb5b09c1SJiri Pirko int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write,
3212cb5b09c1SJiri Pirko 				void __user *buffer,
3213cb5b09c1SJiri Pirko 				size_t *lenp, loff_t *ppos)
3214cb5b09c1SJiri Pirko {
32151d4c8c29SJiri Pirko 	int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
32161d4c8c29SJiri Pirko 
32171d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
32181d4c8c29SJiri Pirko 	return ret;
3219cb5b09c1SJiri Pirko }
3220cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
3221cb5b09c1SJiri Pirko 
3222cb5b09c1SJiri Pirko static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write,
3223cb5b09c1SJiri Pirko 					      void __user *buffer,
3224cb5b09c1SJiri Pirko 					      size_t *lenp, loff_t *ppos)
3225cb5b09c1SJiri Pirko {
32261d4c8c29SJiri Pirko 	int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
32271d4c8c29SJiri Pirko 
32281d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
32291d4c8c29SJiri Pirko 	return ret;
3230cb5b09c1SJiri Pirko }
3231cb5b09c1SJiri Pirko 
3232cb5b09c1SJiri Pirko int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
3233cb5b09c1SJiri Pirko 				   void __user *buffer,
3234cb5b09c1SJiri Pirko 				   size_t *lenp, loff_t *ppos)
3235cb5b09c1SJiri Pirko {
32361d4c8c29SJiri Pirko 	int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
32371d4c8c29SJiri Pirko 
32381d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
32391d4c8c29SJiri Pirko 	return ret;
3240cb5b09c1SJiri Pirko }
3241cb5b09c1SJiri Pirko EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
3242cb5b09c1SJiri Pirko 
3243cb5b09c1SJiri Pirko static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
3244cb5b09c1SJiri Pirko 					  void __user *buffer,
3245cb5b09c1SJiri Pirko 					  size_t *lenp, loff_t *ppos)
3246cb5b09c1SJiri Pirko {
32471d4c8c29SJiri Pirko 	int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
32481d4c8c29SJiri Pirko 
32491d4c8c29SJiri Pirko 	neigh_proc_update(ctl, write);
32501d4c8c29SJiri Pirko 	return ret;
3251cb5b09c1SJiri Pirko }
3252cb5b09c1SJiri Pirko 
32534bf6980dSJean-Francois Remy static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write,
32544bf6980dSJean-Francois Remy 					  void __user *buffer,
32554bf6980dSJean-Francois Remy 					  size_t *lenp, loff_t *ppos)
32564bf6980dSJean-Francois Remy {
32574bf6980dSJean-Francois Remy 	struct neigh_parms *p = ctl->extra2;
32584bf6980dSJean-Francois Remy 	int ret;
32594bf6980dSJean-Francois Remy 
32604bf6980dSJean-Francois Remy 	if (strcmp(ctl->procname, "base_reachable_time") == 0)
32614bf6980dSJean-Francois Remy 		ret = neigh_proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
32624bf6980dSJean-Francois Remy 	else if (strcmp(ctl->procname, "base_reachable_time_ms") == 0)
32634bf6980dSJean-Francois Remy 		ret = neigh_proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
32644bf6980dSJean-Francois Remy 	else
32654bf6980dSJean-Francois Remy 		ret = -1;
32664bf6980dSJean-Francois Remy 
32674bf6980dSJean-Francois Remy 	if (write && ret == 0) {
32684bf6980dSJean-Francois Remy 		/* update reachable_time as well, otherwise, the change will
32694bf6980dSJean-Francois Remy 		 * only be effective after the next time neigh_periodic_work
32704bf6980dSJean-Francois Remy 		 * decides to recompute it
32714bf6980dSJean-Francois Remy 		 */
32724bf6980dSJean-Francois Remy 		p->reachable_time =
32734bf6980dSJean-Francois Remy 			neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
32744bf6980dSJean-Francois Remy 	}
32754bf6980dSJean-Francois Remy 	return ret;
32764bf6980dSJean-Francois Remy }
32774bf6980dSJean-Francois Remy 
32781f9248e5SJiri Pirko #define NEIGH_PARMS_DATA_OFFSET(index)	\
32791f9248e5SJiri Pirko 	(&((struct neigh_parms *) 0)->data[index])
32801f9248e5SJiri Pirko 
32811f9248e5SJiri Pirko #define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \
32821f9248e5SJiri Pirko 	[NEIGH_VAR_ ## attr] = { \
32831f9248e5SJiri Pirko 		.procname	= name, \
32841f9248e5SJiri Pirko 		.data		= NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \
32851f9248e5SJiri Pirko 		.maxlen		= sizeof(int), \
32861f9248e5SJiri Pirko 		.mode		= mval, \
32871f9248e5SJiri Pirko 		.proc_handler	= proc, \
32881f9248e5SJiri Pirko 	}
32891f9248e5SJiri Pirko 
32901f9248e5SJiri Pirko #define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \
32911f9248e5SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax)
32921f9248e5SJiri Pirko 
32931f9248e5SJiri Pirko #define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \
3294cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies)
32951f9248e5SJiri Pirko 
32961f9248e5SJiri Pirko #define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
3297cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)
32981f9248e5SJiri Pirko 
32991f9248e5SJiri Pirko #define NEIGH_SYSCTL_MS_JIFFIES_ENTRY(attr, name) \
3300cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
33011f9248e5SJiri Pirko 
33021f9248e5SJiri Pirko #define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \
3303cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
33041f9248e5SJiri Pirko 
33051f9248e5SJiri Pirko #define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \
3306cb5b09c1SJiri Pirko 	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_unres_qlen)
330754716e3bSEric W. Biederman 
33081da177e4SLinus Torvalds static struct neigh_sysctl_table {
33091da177e4SLinus Torvalds 	struct ctl_table_header *sysctl_header;
33108b5c171bSEric Dumazet 	struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
3311ab32ea5dSBrian Haley } neigh_sysctl_template __read_mostly = {
33121da177e4SLinus Torvalds 	.neigh_vars = {
33131f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"),
33141f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"),
33151f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"),
33168da86466SYOSHIFUJI Hideaki/吉藤英明 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_REPROBES, "mcast_resolicit"),
33171f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),
33181f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),
33191f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"),
33201f9248e5SJiri Pirko 		NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"),
33211f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"),
33221f9248e5SJiri Pirko 		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"),
33231f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"),
33241f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"),
33251f9248e5SJiri Pirko 		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"),
33261f9248e5SJiri Pirko 		NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"),
33271f9248e5SJiri Pirko 		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"),
33281f9248e5SJiri Pirko 		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"),
33298b5c171bSEric Dumazet 		[NEIGH_VAR_GC_INTERVAL] = {
33301da177e4SLinus Torvalds 			.procname	= "gc_interval",
33311da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
33321da177e4SLinus Torvalds 			.mode		= 0644,
33336d9f239aSAlexey Dobriyan 			.proc_handler	= proc_dointvec_jiffies,
33341da177e4SLinus Torvalds 		},
33358b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH1] = {
33361da177e4SLinus Torvalds 			.procname	= "gc_thresh1",
33371da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
33381da177e4SLinus Torvalds 			.mode		= 0644,
3339555445cdSFrancesco Fusco 			.extra1 	= &zero,
3340555445cdSFrancesco Fusco 			.extra2		= &int_max,
3341555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
33421da177e4SLinus Torvalds 		},
33438b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH2] = {
33441da177e4SLinus Torvalds 			.procname	= "gc_thresh2",
33451da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
33461da177e4SLinus Torvalds 			.mode		= 0644,
3347555445cdSFrancesco Fusco 			.extra1 	= &zero,
3348555445cdSFrancesco Fusco 			.extra2		= &int_max,
3349555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
33501da177e4SLinus Torvalds 		},
33518b5c171bSEric Dumazet 		[NEIGH_VAR_GC_THRESH3] = {
33521da177e4SLinus Torvalds 			.procname	= "gc_thresh3",
33531da177e4SLinus Torvalds 			.maxlen		= sizeof(int),
33541da177e4SLinus Torvalds 			.mode		= 0644,
3355555445cdSFrancesco Fusco 			.extra1 	= &zero,
3356555445cdSFrancesco Fusco 			.extra2		= &int_max,
3357555445cdSFrancesco Fusco 			.proc_handler	= proc_dointvec_minmax,
33581da177e4SLinus Torvalds 		},
3359c3bac5a7SPavel Emelyanov 		{},
33601da177e4SLinus Torvalds 	},
33611da177e4SLinus Torvalds };
33621da177e4SLinus Torvalds 
33631da177e4SLinus Torvalds int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
336473af614aSJiri Pirko 			  proc_handler *handler)
33651da177e4SLinus Torvalds {
33661f9248e5SJiri Pirko 	int i;
33673c607bbbSPavel Emelyanov 	struct neigh_sysctl_table *t;
33681f9248e5SJiri Pirko 	const char *dev_name_source;
33698f40a1f9SEric W. Biederman 	char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
337073af614aSJiri Pirko 	char *p_name;
33711da177e4SLinus Torvalds 
33723c607bbbSPavel Emelyanov 	t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
33731da177e4SLinus Torvalds 	if (!t)
33743c607bbbSPavel Emelyanov 		goto err;
33753c607bbbSPavel Emelyanov 
3376b194c1f1SJiri Pirko 	for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
33771f9248e5SJiri Pirko 		t->neigh_vars[i].data += (long) p;
3378cb5b09c1SJiri Pirko 		t->neigh_vars[i].extra1 = dev;
33791d4c8c29SJiri Pirko 		t->neigh_vars[i].extra2 = p;
3380cb5b09c1SJiri Pirko 	}
33811da177e4SLinus Torvalds 
33821da177e4SLinus Torvalds 	if (dev) {
33831da177e4SLinus Torvalds 		dev_name_source = dev->name;
3384d12af679SEric W. Biederman 		/* Terminate the table early */
33858b5c171bSEric Dumazet 		memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
33868b5c171bSEric Dumazet 		       sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
33871da177e4SLinus Torvalds 	} else {
33889ecf07a1SMathias Krause 		struct neigh_table *tbl = p->tbl;
33898f40a1f9SEric W. Biederman 		dev_name_source = "default";
33909ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = &tbl->gc_interval;
33919ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = &tbl->gc_thresh1;
33929ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = &tbl->gc_thresh2;
33939ecf07a1SMathias Krause 		t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = &tbl->gc_thresh3;
33941da177e4SLinus Torvalds 	}
33951da177e4SLinus Torvalds 
3396f8572d8fSEric W. Biederman 	if (handler) {
33971da177e4SLinus Torvalds 		/* RetransTime */
33988b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
33991da177e4SLinus Torvalds 		/* ReachableTime */
34008b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
34011da177e4SLinus Torvalds 		/* RetransTime (in milliseconds)*/
34028b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
34031da177e4SLinus Torvalds 		/* ReachableTime (in milliseconds) */
34048b5c171bSEric Dumazet 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
34054bf6980dSJean-Francois Remy 	} else {
34064bf6980dSJean-Francois Remy 		/* Those handlers will update p->reachable_time after
34074bf6980dSJean-Francois Remy 		 * base_reachable_time(_ms) is set to ensure the new timer starts being
34084bf6980dSJean-Francois Remy 		 * applied after the next neighbour update instead of waiting for
34094bf6980dSJean-Francois Remy 		 * neigh_periodic_work to update its value (can be multiple minutes)
34104bf6980dSJean-Francois Remy 		 * So any handler that replaces them should do this as well
34114bf6980dSJean-Francois Remy 		 */
34124bf6980dSJean-Francois Remy 		/* ReachableTime */
34134bf6980dSJean-Francois Remy 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler =
34144bf6980dSJean-Francois Remy 			neigh_proc_base_reachable_time;
34154bf6980dSJean-Francois Remy 		/* ReachableTime (in milliseconds) */
34164bf6980dSJean-Francois Remy 		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler =
34174bf6980dSJean-Francois Remy 			neigh_proc_base_reachable_time;
34181da177e4SLinus Torvalds 	}
34191da177e4SLinus Torvalds 
3420464dc801SEric W. Biederman 	/* Don't export sysctls to unprivileged users */
3421464dc801SEric W. Biederman 	if (neigh_parms_net(p)->user_ns != &init_user_ns)
3422464dc801SEric W. Biederman 		t->neigh_vars[0].procname = NULL;
3423464dc801SEric W. Biederman 
342473af614aSJiri Pirko 	switch (neigh_parms_family(p)) {
342573af614aSJiri Pirko 	case AF_INET:
342673af614aSJiri Pirko 	      p_name = "ipv4";
342773af614aSJiri Pirko 	      break;
342873af614aSJiri Pirko 	case AF_INET6:
342973af614aSJiri Pirko 	      p_name = "ipv6";
343073af614aSJiri Pirko 	      break;
343173af614aSJiri Pirko 	default:
343273af614aSJiri Pirko 	      BUG();
343373af614aSJiri Pirko 	}
343473af614aSJiri Pirko 
34358f40a1f9SEric W. Biederman 	snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
34368f40a1f9SEric W. Biederman 		p_name, dev_name_source);
34374ab438fcSDenis V. Lunev 	t->sysctl_header =
34388f40a1f9SEric W. Biederman 		register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
34393c607bbbSPavel Emelyanov 	if (!t->sysctl_header)
34408f40a1f9SEric W. Biederman 		goto free;
34413c607bbbSPavel Emelyanov 
34421da177e4SLinus Torvalds 	p->sysctl_table = t;
34431da177e4SLinus Torvalds 	return 0;
34441da177e4SLinus Torvalds 
34451da177e4SLinus Torvalds free:
34461da177e4SLinus Torvalds 	kfree(t);
34473c607bbbSPavel Emelyanov err:
34483c607bbbSPavel Emelyanov 	return -ENOBUFS;
34491da177e4SLinus Torvalds }
34500a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_sysctl_register);
34511da177e4SLinus Torvalds 
34521da177e4SLinus Torvalds void neigh_sysctl_unregister(struct neigh_parms *p)
34531da177e4SLinus Torvalds {
34541da177e4SLinus Torvalds 	if (p->sysctl_table) {
34551da177e4SLinus Torvalds 		struct neigh_sysctl_table *t = p->sysctl_table;
34561da177e4SLinus Torvalds 		p->sysctl_table = NULL;
34575dd3df10SEric W. Biederman 		unregister_net_sysctl_table(t->sysctl_header);
34581da177e4SLinus Torvalds 		kfree(t);
34591da177e4SLinus Torvalds 	}
34601da177e4SLinus Torvalds }
34610a204500SYOSHIFUJI Hideaki EXPORT_SYMBOL(neigh_sysctl_unregister);
34621da177e4SLinus Torvalds 
34631da177e4SLinus Torvalds #endif	/* CONFIG_SYSCTL */
34641da177e4SLinus Torvalds 
3465c8822a4eSThomas Graf static int __init neigh_init(void)
3466c8822a4eSThomas Graf {
3467b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0);
3468b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0);
3469b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, 0);
3470c8822a4eSThomas Graf 
3471c7ac8679SGreg Rose 	rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
3472b97bac64SFlorian Westphal 		      0);
3473b97bac64SFlorian Westphal 	rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, 0);
3474c8822a4eSThomas Graf 
3475c8822a4eSThomas Graf 	return 0;
3476c8822a4eSThomas Graf }
3477c8822a4eSThomas Graf 
3478c8822a4eSThomas Graf subsys_initcall(neigh_init);
3479