blob: 98f20efbfadf26a6bcaa894445f482043dfc3716 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * Generic address resolution entity
4 *
5 * Authors:
6 * Pedro Roque <roque@di.fc.ul.pt>
7 * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
8 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * Fixes:
10 * Vitaly E. Lavrov releasing NULL neighbor in neigh_add.
11 * Harald Welte Add neighbour cache statistics like rtstat
12 */
13
Joe Perchese005d192012-05-16 19:58:40 +000014#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090016#include <linux/slab.h>
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +030017#include <linux/kmemleak.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/types.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/socket.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/netdevice.h>
23#include <linux/proc_fs.h>
24#ifdef CONFIG_SYSCTL
25#include <linux/sysctl.h>
26#endif
27#include <linux/times.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020028#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <net/neighbour.h>
David Ahern4b2a2bf2019-05-01 18:18:42 -070030#include <net/arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <net/dst.h>
32#include <net/sock.h>
Tom Tucker8d717402006-07-30 20:43:36 -070033#include <net/netevent.h>
Thomas Grafa14a49d2006-08-07 17:53:08 -070034#include <net/netlink.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/rtnetlink.h>
36#include <linux/random.h>
Paulo Marques543537b2005-06-23 00:09:02 -070037#include <linux/string.h>
vignesh babuc3609d52007-08-24 22:27:55 -070038#include <linux/log2.h>
Jiri Pirko1d4c8c22013-12-07 19:26:56 +010039#include <linux/inetdevice.h>
Jiri Pirkobba24892013-12-07 19:26:57 +010040#include <net/addrconf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
Roopa Prabhu56dd18a2019-02-14 09:15:11 -080042#include <trace/events/neigh.h>
43
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#define NEIGH_DEBUG 1
Joe Perchesd5d427c2013-04-15 15:17:19 +000045#define neigh_dbg(level, fmt, ...) \
46do { \
47 if (level <= NEIGH_DEBUG) \
48 pr_debug(fmt, ##__VA_ARGS__); \
49} while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51#define PNEIGH_HASHMASK 0xF
52
Kees Cooke99e88a2017-10-16 14:43:17 -070053static void neigh_timer_handler(struct timer_list *t);
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -070054static void __neigh_notify(struct neighbour *n, int type, int flags,
55 u32 pid);
56static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid);
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +020057static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
58 struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Amos Waterland45fc3b12005-09-24 16:53:16 -070060#ifdef CONFIG_PROC_FS
Christoph Hellwig71a50532018-04-15 10:16:41 +020061static const struct seq_operations neigh_stat_seq_ops;
Amos Waterland45fc3b12005-09-24 16:53:16 -070062#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64/*
65 Neighbour hash table buckets are protected with rwlock tbl->lock.
66
67 - All the scans/updates to hash buckets MUST be made under this lock.
68 - NOTHING clever should be made under this lock: no callbacks
69 to protocol backends, no attempts to send something to network.
70 It will result in deadlocks, if backend/driver wants to use neighbour
71 cache.
72 - If the entry requires some non-trivial actions, increase
73 its reference count and release table lock.
74
75 Neighbour entries are protected:
76 - with reference count.
77 - with rwlock neigh->lock
78
79 Reference count prevents destruction.
80
81 neigh->lock mainly serializes ll address data and its validity state.
82 However, the same lock is used to protect another entry fields:
83 - timer
84 - resolution queue
85
86 Again, nothing clever shall be made under neigh->lock,
87 the most complicated procedure, which we allow is dev->hard_header.
88 It is supposed, that dev->hard_header is simplistic and does
89 not make callbacks to neighbour tables.
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 */
91
David S. Miller8f40b162011-07-17 13:34:11 -070092static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -070093{
94 kfree_skb(skb);
95 return -ENETDOWN;
96}
97
Thomas Graf4f494552007-08-08 23:12:36 -070098static void neigh_cleanup_and_release(struct neighbour *neigh)
99{
Roopa Prabhu56dd18a2019-02-14 09:15:11 -0800100 trace_neigh_cleanup_and_release(neigh, 0);
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -0700101 __neigh_notify(neigh, RTM_DELNEIGH, 0, 0);
Ido Schimmel53f800e2016-12-23 09:32:48 +0100102 call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
Thomas Graf4f494552007-08-08 23:12:36 -0700103 neigh_release(neigh);
104}
105
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106/*
107 * It is random distribution in the interval (1/2)*base...(3/2)*base.
108 * It corresponds to default IPv6 settings and is not overridable,
109 * because it is really reasonable choice.
110 */
111
112unsigned long neigh_rand_reach_time(unsigned long base)
113{
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500114 return base ? (prandom_u32() % base) + (base >> 1) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900116EXPORT_SYMBOL(neigh_rand_reach_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
David Ahern58956312018-12-07 12:24:57 -0800118static void neigh_mark_dead(struct neighbour *n)
119{
120 n->dead = 1;
121 if (!list_empty(&n->gc_list)) {
122 list_del_init(&n->gc_list);
123 atomic_dec(&n->tbl->gc_entries);
124 }
125}
126
David Ahern9c29a2f2018-12-11 18:57:21 -0700127static void neigh_update_gc_list(struct neighbour *n)
David Ahern58956312018-12-07 12:24:57 -0800128{
David Aherne997f8a2018-12-11 18:57:25 -0700129 bool on_gc_list, exempt_from_gc;
David Ahern58956312018-12-07 12:24:57 -0800130
David Ahern9c29a2f2018-12-11 18:57:21 -0700131 write_lock_bh(&n->tbl->lock);
132 write_lock(&n->lock);
David Ahern58956312018-12-07 12:24:57 -0800133
Chinmay Agarwaleefb45e2021-04-22 01:12:22 +0530134 if (n->dead)
135 goto out;
136
David Aherne997f8a2018-12-11 18:57:25 -0700137 /* remove from the gc list if new state is permanent or if neighbor
138 * is externally learned; otherwise entry should be on the gc list
David Ahern58956312018-12-07 12:24:57 -0800139 */
David Aherne997f8a2018-12-11 18:57:25 -0700140 exempt_from_gc = n->nud_state & NUD_PERMANENT ||
141 n->flags & NTF_EXT_LEARNED;
David Ahern9c29a2f2018-12-11 18:57:21 -0700142 on_gc_list = !list_empty(&n->gc_list);
David Ahern8cc196d2018-12-10 13:54:07 -0800143
David Aherne997f8a2018-12-11 18:57:25 -0700144 if (exempt_from_gc && on_gc_list) {
David Ahern9c29a2f2018-12-11 18:57:21 -0700145 list_del_init(&n->gc_list);
David Ahern58956312018-12-07 12:24:57 -0800146 atomic_dec(&n->tbl->gc_entries);
David Aherne997f8a2018-12-11 18:57:25 -0700147 } else if (!exempt_from_gc && !on_gc_list) {
David Ahern58956312018-12-07 12:24:57 -0800148 /* add entries to the tail; cleaning removes from the front */
149 list_add_tail(&n->gc_list, &n->tbl->gc_list);
150 atomic_inc(&n->tbl->gc_entries);
151 }
David Ahern9c29a2f2018-12-11 18:57:21 -0700152
Chinmay Agarwaleefb45e2021-04-22 01:12:22 +0530153out:
David Ahern9c29a2f2018-12-11 18:57:21 -0700154 write_unlock(&n->lock);
155 write_unlock_bh(&n->tbl->lock);
David Ahern58956312018-12-07 12:24:57 -0800156}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
David Aherne997f8a2018-12-11 18:57:25 -0700158static bool neigh_update_ext_learned(struct neighbour *neigh, u32 flags,
David Ahern526f1b52018-12-11 18:57:24 -0700159 int *notify)
160{
David Aherne997f8a2018-12-11 18:57:25 -0700161 bool rc = false;
David Ahern526f1b52018-12-11 18:57:24 -0700162 u8 ndm_flags;
163
164 if (!(flags & NEIGH_UPDATE_F_ADMIN))
David Aherne997f8a2018-12-11 18:57:25 -0700165 return rc;
David Ahern526f1b52018-12-11 18:57:24 -0700166
167 ndm_flags = (flags & NEIGH_UPDATE_F_EXT_LEARNED) ? NTF_EXT_LEARNED : 0;
168 if ((neigh->flags ^ ndm_flags) & NTF_EXT_LEARNED) {
169 if (ndm_flags & NTF_EXT_LEARNED)
170 neigh->flags |= NTF_EXT_LEARNED;
171 else
172 neigh->flags &= ~NTF_EXT_LEARNED;
David Aherne997f8a2018-12-11 18:57:25 -0700173 rc = true;
David Ahern526f1b52018-12-11 18:57:24 -0700174 *notify = 1;
175 }
David Aherne997f8a2018-12-11 18:57:25 -0700176
177 return rc;
David Ahern526f1b52018-12-11 18:57:24 -0700178}
179
David Ahern7e6f1822018-12-11 18:57:23 -0700180static bool neigh_del(struct neighbour *n, struct neighbour __rcu **np,
181 struct neigh_table *tbl)
Sowmini Varadhan50710342017-06-02 09:01:49 -0700182{
183 bool retval = false;
184
185 write_lock(&n->lock);
David Ahern7e6f1822018-12-11 18:57:23 -0700186 if (refcount_read(&n->refcnt) == 1) {
Sowmini Varadhan50710342017-06-02 09:01:49 -0700187 struct neighbour *neigh;
188
189 neigh = rcu_dereference_protected(n->next,
190 lockdep_is_held(&tbl->lock));
191 rcu_assign_pointer(*np, neigh);
David Ahern58956312018-12-07 12:24:57 -0800192 neigh_mark_dead(n);
Sowmini Varadhan50710342017-06-02 09:01:49 -0700193 retval = true;
194 }
195 write_unlock(&n->lock);
196 if (retval)
197 neigh_cleanup_and_release(n);
198 return retval;
199}
200
201bool neigh_remove_one(struct neighbour *ndel, struct neigh_table *tbl)
202{
203 struct neigh_hash_table *nht;
204 void *pkey = ndel->primary_key;
205 u32 hash_val;
206 struct neighbour *n;
207 struct neighbour __rcu **np;
208
209 nht = rcu_dereference_protected(tbl->nht,
210 lockdep_is_held(&tbl->lock));
211 hash_val = tbl->hash(pkey, ndel->dev, nht->hash_rnd);
212 hash_val = hash_val >> (32 - nht->hash_shift);
213
214 np = &nht->hash_buckets[hash_val];
215 while ((n = rcu_dereference_protected(*np,
216 lockdep_is_held(&tbl->lock)))) {
217 if (n == ndel)
David Ahern7e6f1822018-12-11 18:57:23 -0700218 return neigh_del(n, np, tbl);
Sowmini Varadhan50710342017-06-02 09:01:49 -0700219 np = &n->next;
220 }
221 return false;
222}
223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224static int neigh_forced_gc(struct neigh_table *tbl)
225{
David Ahern58956312018-12-07 12:24:57 -0800226 int max_clean = atomic_read(&tbl->gc_entries) - tbl->gc_thresh2;
227 unsigned long tref = jiffies - 5 * HZ;
David Ahern58956312018-12-07 12:24:57 -0800228 struct neighbour *n, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 int shrunk = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
231 NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
232
233 write_lock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
David Ahern58956312018-12-07 12:24:57 -0800235 list_for_each_entry_safe(n, tmp, &tbl->gc_list, gc_list) {
236 if (refcount_read(&n->refcnt) == 1) {
237 bool remove = false;
238
239 write_lock(&n->lock);
David Ahern758a7f02018-12-11 18:57:22 -0700240 if ((n->nud_state == NUD_FAILED) ||
Jeff Dike8cf88212020-11-12 20:58:15 -0500241 (tbl->is_multicast &&
242 tbl->is_multicast(n->primary_key)) ||
David Aherne997f8a2018-12-11 18:57:25 -0700243 time_after(tref, n->updated))
David Ahern58956312018-12-07 12:24:57 -0800244 remove = true;
245 write_unlock(&n->lock);
246
247 if (remove && neigh_remove_one(n, tbl))
248 shrunk++;
249 if (shrunk >= max_clean)
250 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 }
252 }
253
254 tbl->last_flush = jiffies;
255
256 write_unlock_bh(&tbl->lock);
257
258 return shrunk;
259}
260
Pavel Emelyanova43d8992007-12-20 15:49:05 -0800261static void neigh_add_timer(struct neighbour *n, unsigned long when)
262{
263 neigh_hold(n);
264 if (unlikely(mod_timer(&n->timer, when))) {
265 printk("NEIGH: BUG, double timer add, state is %x\n",
266 n->nud_state);
267 dump_stack();
268 }
269}
270
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271static int neigh_del_timer(struct neighbour *n)
272{
273 if ((n->nud_state & NUD_IN_TIMER) &&
274 del_timer(&n->timer)) {
275 neigh_release(n);
276 return 1;
277 }
278 return 0;
279}
280
281static void pneigh_queue_purge(struct sk_buff_head *list)
282{
283 struct sk_buff *skb;
284
285 while ((skb = skb_dequeue(list)) != NULL) {
286 dev_put(skb->dev);
287 kfree_skb(skb);
288 }
289}
290
David Ahern859bd2e2018-10-11 20:33:49 -0700291static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev,
292 bool skip_perm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293{
294 int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000295 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000297 nht = rcu_dereference_protected(tbl->nht,
298 lockdep_is_held(&tbl->lock));
299
David S. Millercd089332011-07-11 01:28:12 -0700300 for (i = 0; i < (1 << nht->hash_shift); i++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700301 struct neighbour *n;
302 struct neighbour __rcu **np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Eric Dumazet767e97e2010-10-06 17:49:21 -0700304 while ((n = rcu_dereference_protected(*np,
305 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 if (dev && n->dev != dev) {
307 np = &n->next;
308 continue;
309 }
David Ahern859bd2e2018-10-11 20:33:49 -0700310 if (skip_perm && n->nud_state & NUD_PERMANENT) {
311 np = &n->next;
312 continue;
313 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700314 rcu_assign_pointer(*np,
315 rcu_dereference_protected(n->next,
316 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 write_lock(&n->lock);
318 neigh_del_timer(n);
David Ahern58956312018-12-07 12:24:57 -0800319 neigh_mark_dead(n);
Reshetova, Elena9f237432017-06-30 13:07:55 +0300320 if (refcount_read(&n->refcnt) != 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 /* The most unpleasant situation.
322 We must destroy neighbour entry,
323 but someone still uses it.
324
325 The destroy will be delayed until
326 the last user releases us, but
327 we must kill timers etc. and move
328 it to safe state.
329 */
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700330 __skb_queue_purge(&n->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000331 n->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 n->output = neigh_blackhole;
333 if (n->nud_state & NUD_VALID)
334 n->nud_state = NUD_NOARP;
335 else
336 n->nud_state = NUD_NONE;
Joe Perchesd5d427c2013-04-15 15:17:19 +0000337 neigh_dbg(2, "neigh %p is stray\n", n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 }
339 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700340 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 }
342 }
Herbert Xu49636bb2005-10-23 17:18:00 +1000343}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
Herbert Xu49636bb2005-10-23 17:18:00 +1000345void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
346{
347 write_lock_bh(&tbl->lock);
David Ahern859bd2e2018-10-11 20:33:49 -0700348 neigh_flush_dev(tbl, dev, false);
Herbert Xu49636bb2005-10-23 17:18:00 +1000349 write_unlock_bh(&tbl->lock);
350}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900351EXPORT_SYMBOL(neigh_changeaddr);
Herbert Xu49636bb2005-10-23 17:18:00 +1000352
David Ahern859bd2e2018-10-11 20:33:49 -0700353static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
354 bool skip_perm)
Herbert Xu49636bb2005-10-23 17:18:00 +1000355{
356 write_lock_bh(&tbl->lock);
David Ahern859bd2e2018-10-11 20:33:49 -0700357 neigh_flush_dev(tbl, dev, skip_perm);
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +0200358 pneigh_ifdown_and_unlock(tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
360 del_timer_sync(&tbl->proxy_timer);
361 pneigh_queue_purge(&tbl->proxy_queue);
362 return 0;
363}
David Ahern859bd2e2018-10-11 20:33:49 -0700364
365int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev)
366{
367 __neigh_ifdown(tbl, dev, true);
368 return 0;
369}
370EXPORT_SYMBOL(neigh_carrier_down);
371
372int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
373{
374 __neigh_ifdown(tbl, dev, false);
375 return 0;
376}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900377EXPORT_SYMBOL(neigh_ifdown);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
David Ahern58956312018-12-07 12:24:57 -0800379static struct neighbour *neigh_alloc(struct neigh_table *tbl,
380 struct net_device *dev,
David Aherne997f8a2018-12-11 18:57:25 -0700381 bool exempt_from_gc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382{
383 struct neighbour *n = NULL;
384 unsigned long now = jiffies;
385 int entries;
386
David Aherne997f8a2018-12-11 18:57:25 -0700387 if (exempt_from_gc)
David Ahern58956312018-12-07 12:24:57 -0800388 goto do_alloc;
389
390 entries = atomic_inc_return(&tbl->gc_entries) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 if (entries >= tbl->gc_thresh3 ||
392 (entries >= tbl->gc_thresh2 &&
393 time_after(now, tbl->last_flush + 5 * HZ))) {
394 if (!neigh_forced_gc(tbl) &&
Rick Jonesfb811392015-08-07 11:10:37 -0700395 entries >= tbl->gc_thresh3) {
396 net_info_ratelimited("%s: neighbor table overflow!\n",
397 tbl->id);
398 NEIGH_CACHE_STAT_INC(tbl, table_fulls);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 goto out_entries;
Rick Jonesfb811392015-08-07 11:10:37 -0700400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 }
402
David Ahern58956312018-12-07 12:24:57 -0800403do_alloc:
YOSHIFUJI Hideaki / 吉藤英明08433ef2013-01-24 00:44:23 +0000404 n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 if (!n)
406 goto out_entries;
407
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700408 __skb_queue_head_init(&n->arp_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 rwlock_init(&n->lock);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +0000410 seqlock_init(&n->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 n->updated = n->used = now;
412 n->nud_state = NUD_NONE;
413 n->output = neigh_blackhole;
David S. Millerf6b72b622011-07-14 07:53:20 -0700414 seqlock_init(&n->hh.hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 n->parms = neigh_parms_clone(&tbl->parms);
Kees Cooke99e88a2017-10-16 14:43:17 -0700416 timer_setup(&n->timer, neigh_timer_handler, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
418 NEIGH_CACHE_STAT_INC(tbl, allocs);
419 n->tbl = tbl;
Reshetova, Elena9f237432017-06-30 13:07:55 +0300420 refcount_set(&n->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 n->dead = 1;
David Ahern8cc196d2018-12-10 13:54:07 -0800422 INIT_LIST_HEAD(&n->gc_list);
David Ahern58956312018-12-07 12:24:57 -0800423
424 atomic_inc(&tbl->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425out:
426 return n;
427
428out_entries:
David Aherne997f8a2018-12-11 18:57:25 -0700429 if (!exempt_from_gc)
David Ahern58956312018-12-07 12:24:57 -0800430 atomic_dec(&tbl->gc_entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 goto out;
432}
433
David S. Miller2c2aba62011-12-28 15:06:58 -0500434static void neigh_get_hash_rnd(u32 *x)
435{
Jason A. Donenfeldb3d0f782017-06-07 23:00:05 -0400436 *x = get_random_u32() | 1;
David S. Miller2c2aba62011-12-28 15:06:58 -0500437}
438
David S. Millercd089332011-07-11 01:28:12 -0700439static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440{
David S. Millercd089332011-07-11 01:28:12 -0700441 size_t size = (1 << shift) * sizeof(struct neighbour *);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000442 struct neigh_hash_table *ret;
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000443 struct neighbour __rcu **buckets;
David S. Miller2c2aba62011-12-28 15:06:58 -0500444 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000446 ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
447 if (!ret)
448 return NULL;
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300449 if (size <= PAGE_SIZE) {
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000450 buckets = kzalloc(size, GFP_ATOMIC);
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300451 } else {
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000452 buckets = (struct neighbour __rcu **)
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000453 __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
454 get_order(size));
Konstantin Khlebnikov01b833a2019-01-14 13:38:43 +0300455 kmemleak_alloc(buckets, size, 1, GFP_ATOMIC);
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300456 }
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000457 if (!buckets) {
458 kfree(ret);
459 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 }
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000461 ret->hash_buckets = buckets;
David S. Millercd089332011-07-11 01:28:12 -0700462 ret->hash_shift = shift;
David S. Miller2c2aba62011-12-28 15:06:58 -0500463 for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
464 neigh_get_hash_rnd(&ret->hash_rnd[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 return ret;
466}
467
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000468static void neigh_hash_free_rcu(struct rcu_head *head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000470 struct neigh_hash_table *nht = container_of(head,
471 struct neigh_hash_table,
472 rcu);
David S. Millercd089332011-07-11 01:28:12 -0700473 size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000474 struct neighbour __rcu **buckets = nht->hash_buckets;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300476 if (size <= PAGE_SIZE) {
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000477 kfree(buckets);
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300478 } else {
479 kmemleak_free(buckets);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000480 free_pages((unsigned long)buckets, get_order(size));
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300481 }
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000482 kfree(nht);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483}
484
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000485static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
David S. Millercd089332011-07-11 01:28:12 -0700486 unsigned long new_shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000488 unsigned int i, hash;
489 struct neigh_hash_table *new_nht, *old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
491 NEIGH_CACHE_STAT_INC(tbl, hash_grows);
492
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000493 old_nht = rcu_dereference_protected(tbl->nht,
494 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -0700495 new_nht = neigh_hash_alloc(new_shift);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000496 if (!new_nht)
497 return old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
David S. Millercd089332011-07-11 01:28:12 -0700499 for (i = 0; i < (1 << old_nht->hash_shift); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 struct neighbour *n, *next;
501
Eric Dumazet767e97e2010-10-06 17:49:21 -0700502 for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
503 lockdep_is_held(&tbl->lock));
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000504 n != NULL;
505 n = next) {
506 hash = tbl->hash(n->primary_key, n->dev,
507 new_nht->hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
David S. Millercd089332011-07-11 01:28:12 -0700509 hash >>= (32 - new_nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700510 next = rcu_dereference_protected(n->next,
511 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
Eric Dumazet767e97e2010-10-06 17:49:21 -0700513 rcu_assign_pointer(n->next,
514 rcu_dereference_protected(
515 new_nht->hash_buckets[hash],
516 lockdep_is_held(&tbl->lock)));
517 rcu_assign_pointer(new_nht->hash_buckets[hash], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 }
519 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000521 rcu_assign_pointer(tbl->nht, new_nht);
522 call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
523 return new_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524}
525
526struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
527 struct net_device *dev)
528{
529 struct neighbour *n;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900530
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 NEIGH_CACHE_STAT_INC(tbl, lookups);
532
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000533 rcu_read_lock_bh();
Eric W. Biederman60395a22015-03-03 17:10:44 -0600534 n = __neigh_lookup_noref(tbl, pkey, dev);
535 if (n) {
Reshetova, Elena9f237432017-06-30 13:07:55 +0300536 if (!refcount_inc_not_zero(&n->refcnt))
Eric W. Biederman60395a22015-03-03 17:10:44 -0600537 n = NULL;
538 NEIGH_CACHE_STAT_INC(tbl, hits);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700540
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000541 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 return n;
543}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900544EXPORT_SYMBOL(neigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
Eric W. Biederman426b5302008-01-24 00:13:18 -0800546struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
547 const void *pkey)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548{
549 struct neighbour *n;
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300550 unsigned int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800551 u32 hash_val;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000552 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
554 NEIGH_CACHE_STAT_INC(tbl, lookups);
555
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000556 rcu_read_lock_bh();
557 nht = rcu_dereference_bh(tbl->nht);
David S. Millercd089332011-07-11 01:28:12 -0700558 hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700559
560 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
561 n != NULL;
562 n = rcu_dereference_bh(n->next)) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800563 if (!memcmp(n->primary_key, pkey, key_len) &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900564 net_eq(dev_net(n->dev), net)) {
Reshetova, Elena9f237432017-06-30 13:07:55 +0300565 if (!refcount_inc_not_zero(&n->refcnt))
Eric Dumazet767e97e2010-10-06 17:49:21 -0700566 n = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 NEIGH_CACHE_STAT_INC(tbl, hits);
568 break;
569 }
570 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700571
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000572 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 return n;
574}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900575EXPORT_SYMBOL(neigh_lookup_nodev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
David Ahern58956312018-12-07 12:24:57 -0800577static struct neighbour *___neigh_create(struct neigh_table *tbl,
578 const void *pkey,
579 struct net_device *dev,
David Aherne997f8a2018-12-11 18:57:25 -0700580 bool exempt_from_gc, bool want_ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581{
David Aherne997f8a2018-12-11 18:57:25 -0700582 struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev, exempt_from_gc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 u32 hash_val;
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300584 unsigned int key_len = tbl->key_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 int error;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000586 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
David Ahernfc651002019-05-22 12:22:21 -0700588 trace_neigh_create(tbl, dev, pkey, n, exempt_from_gc);
589
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 if (!n) {
591 rc = ERR_PTR(-ENOBUFS);
592 goto out;
593 }
594
595 memcpy(n->primary_key, pkey, key_len);
596 n->dev = dev;
597 dev_hold(dev);
598
599 /* Protocol specific setup. */
600 if (tbl->constructor && (error = tbl->constructor(n)) < 0) {
601 rc = ERR_PTR(error);
602 goto out_neigh_release;
603 }
604
David Millerda6a8fa2011-07-25 00:01:38 +0000605 if (dev->netdev_ops->ndo_neigh_construct) {
Jiri Pirko503eebc2016-07-05 11:27:37 +0200606 error = dev->netdev_ops->ndo_neigh_construct(dev, n);
David Millerda6a8fa2011-07-25 00:01:38 +0000607 if (error < 0) {
608 rc = ERR_PTR(error);
609 goto out_neigh_release;
610 }
611 }
612
David S. Miller447f2192011-12-19 15:04:41 -0500613 /* Device specific setup. */
614 if (n->parms->neigh_setup &&
615 (error = n->parms->neigh_setup(n)) < 0) {
616 rc = ERR_PTR(error);
617 goto out_neigh_release;
618 }
619
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100620 n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
622 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000623 nht = rcu_dereference_protected(tbl->nht,
624 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
David S. Millercd089332011-07-11 01:28:12 -0700626 if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
627 nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
Jim Westfall096b9852018-01-14 04:18:50 -0800629 hash_val = tbl->hash(n->primary_key, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630
631 if (n->parms->dead) {
632 rc = ERR_PTR(-EINVAL);
633 goto out_tbl_unlock;
634 }
635
Eric Dumazet767e97e2010-10-06 17:49:21 -0700636 for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
637 lockdep_is_held(&tbl->lock));
638 n1 != NULL;
639 n1 = rcu_dereference_protected(n1->next,
640 lockdep_is_held(&tbl->lock))) {
Jim Westfall096b9852018-01-14 04:18:50 -0800641 if (dev == n1->dev && !memcmp(n1->primary_key, n->primary_key, key_len)) {
David S. Millera263b302012-07-02 02:02:15 -0700642 if (want_ref)
643 neigh_hold(n1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 rc = n1;
645 goto out_tbl_unlock;
646 }
647 }
648
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 n->dead = 0;
David Aherne997f8a2018-12-11 18:57:25 -0700650 if (!exempt_from_gc)
David Ahern8cc196d2018-12-10 13:54:07 -0800651 list_add_tail(&n->gc_list, &n->tbl->gc_list);
652
David S. Millera263b302012-07-02 02:02:15 -0700653 if (want_ref)
654 neigh_hold(n);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700655 rcu_assign_pointer(n->next,
656 rcu_dereference_protected(nht->hash_buckets[hash_val],
657 lockdep_is_held(&tbl->lock)));
658 rcu_assign_pointer(nht->hash_buckets[hash_val], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 write_unlock_bh(&tbl->lock);
Joe Perchesd5d427c2013-04-15 15:17:19 +0000660 neigh_dbg(2, "neigh %p is created\n", n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 rc = n;
662out:
663 return rc;
664out_tbl_unlock:
665 write_unlock_bh(&tbl->lock);
666out_neigh_release:
David Ahern64c6f4b2019-05-01 18:08:34 -0700667 if (!exempt_from_gc)
668 atomic_dec(&tbl->gc_entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 neigh_release(n);
670 goto out;
671}
David Ahern58956312018-12-07 12:24:57 -0800672
673struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
674 struct net_device *dev, bool want_ref)
675{
676 return ___neigh_create(tbl, pkey, dev, false, want_ref);
677}
David S. Millera263b302012-07-02 02:02:15 -0700678EXPORT_SYMBOL(__neigh_create);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300680static u32 pneigh_hash(const void *pkey, unsigned int key_len)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700681{
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700682 u32 hash_val = *(u32 *)(pkey + key_len - 4);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700683 hash_val ^= (hash_val >> 16);
684 hash_val ^= hash_val >> 8;
685 hash_val ^= hash_val >> 4;
686 hash_val &= PNEIGH_HASHMASK;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900687 return hash_val;
688}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700689
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900690static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
691 struct net *net,
692 const void *pkey,
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300693 unsigned int key_len,
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900694 struct net_device *dev)
695{
696 while (n) {
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700697 if (!memcmp(n->key, pkey, key_len) &&
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900698 net_eq(pneigh_net(n), net) &&
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700699 (n->dev == dev || !n->dev))
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900700 return n;
701 n = n->next;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700702 }
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900703 return NULL;
704}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700705
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900706struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
707 struct net *net, const void *pkey, struct net_device *dev)
708{
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300709 unsigned int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900710 u32 hash_val = pneigh_hash(pkey, key_len);
711
712 return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
713 net, pkey, key_len, dev);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700714}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900715EXPORT_SYMBOL_GPL(__pneigh_lookup);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700716
Eric W. Biederman426b5302008-01-24 00:13:18 -0800717struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
718 struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 struct net_device *dev, int creat)
720{
721 struct pneigh_entry *n;
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300722 unsigned int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900723 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
725 read_lock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900726 n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
727 net, pkey, key_len, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 read_unlock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900729
730 if (n || !creat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 goto out;
732
Pavel Emelyanov4ae28942007-10-15 12:54:15 -0700733 ASSERT_RTNL();
734
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
736 if (!n)
737 goto out;
738
David Ahern754d5da2018-12-19 15:53:22 -0800739 n->protocol = 0;
Eric W. Biedermanefd7ef12015-03-11 23:04:08 -0500740 write_pnet(&n->net, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 memcpy(n->key, pkey, key_len);
742 n->dev = dev;
743 if (dev)
744 dev_hold(dev);
745
746 if (tbl->pconstructor && tbl->pconstructor(n)) {
747 if (dev)
748 dev_put(dev);
749 kfree(n);
750 n = NULL;
751 goto out;
752 }
753
754 write_lock_bh(&tbl->lock);
755 n->next = tbl->phash_buckets[hash_val];
756 tbl->phash_buckets[hash_val] = n;
757 write_unlock_bh(&tbl->lock);
758out:
759 return n;
760}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900761EXPORT_SYMBOL(pneigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
763
Eric W. Biederman426b5302008-01-24 00:13:18 -0800764int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 struct net_device *dev)
766{
767 struct pneigh_entry *n, **np;
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300768 unsigned int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900769 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
771 write_lock_bh(&tbl->lock);
772 for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
773 np = &n->next) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800774 if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900775 net_eq(pneigh_net(n), net)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 *np = n->next;
777 write_unlock_bh(&tbl->lock);
778 if (tbl->pdestructor)
779 tbl->pdestructor(n);
780 if (n->dev)
781 dev_put(n->dev);
782 kfree(n);
783 return 0;
784 }
785 }
786 write_unlock_bh(&tbl->lock);
787 return -ENOENT;
788}
789
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +0200790static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
791 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792{
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +0200793 struct pneigh_entry *n, **np, *freelist = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 u32 h;
795
796 for (h = 0; h <= PNEIGH_HASHMASK; h++) {
797 np = &tbl->phash_buckets[h];
798 while ((n = *np) != NULL) {
799 if (!dev || n->dev == dev) {
800 *np = n->next;
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +0200801 n->next = freelist;
802 freelist = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 continue;
804 }
805 np = &n->next;
806 }
807 }
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +0200808 write_unlock_bh(&tbl->lock);
809 while ((n = freelist)) {
810 freelist = n->next;
811 n->next = NULL;
812 if (tbl->pdestructor)
813 tbl->pdestructor(n);
814 if (n->dev)
815 dev_put(n->dev);
816 kfree(n);
817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 return -ENOENT;
819}
820
Denis V. Lunev06f05112008-01-24 00:30:58 -0800821static void neigh_parms_destroy(struct neigh_parms *parms);
822
823static inline void neigh_parms_put(struct neigh_parms *parms)
824{
Reshetova, Elena63439442017-06-30 13:07:56 +0300825 if (refcount_dec_and_test(&parms->refcnt))
Denis V. Lunev06f05112008-01-24 00:30:58 -0800826 neigh_parms_destroy(parms);
827}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
829/*
830 * neighbour must already be out of the table;
831 *
832 */
833void neigh_destroy(struct neighbour *neigh)
834{
David Millerda6a8fa2011-07-25 00:01:38 +0000835 struct net_device *dev = neigh->dev;
836
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
838
839 if (!neigh->dead) {
Joe Perchese005d192012-05-16 19:58:40 +0000840 pr_warn("Destroying alive neighbour %p\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 dump_stack();
842 return;
843 }
844
845 if (neigh_del_timer(neigh))
Joe Perchese005d192012-05-16 19:58:40 +0000846 pr_warn("Impossible event\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700848 write_lock_bh(&neigh->lock);
849 __skb_queue_purge(&neigh->arp_queue);
850 write_unlock_bh(&neigh->lock);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000851 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
David S. Miller447f2192011-12-19 15:04:41 -0500853 if (dev->netdev_ops->ndo_neigh_destroy)
Jiri Pirko503eebc2016-07-05 11:27:37 +0200854 dev->netdev_ops->ndo_neigh_destroy(dev, neigh);
David S. Miller447f2192011-12-19 15:04:41 -0500855
David Millerda6a8fa2011-07-25 00:01:38 +0000856 dev_put(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 neigh_parms_put(neigh->parms);
858
Joe Perchesd5d427c2013-04-15 15:17:19 +0000859 neigh_dbg(2, "neigh %p is destroyed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860
861 atomic_dec(&neigh->tbl->entries);
David Miller5b8b0062011-07-25 00:01:22 +0000862 kfree_rcu(neigh, rcu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900864EXPORT_SYMBOL(neigh_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865
866/* Neighbour state is suspicious;
867 disable fast path.
868
869 Called with write_locked neigh.
870 */
871static void neigh_suspect(struct neighbour *neigh)
872{
Joe Perchesd5d427c2013-04-15 15:17:19 +0000873 neigh_dbg(2, "neigh %p is suspected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
875 neigh->output = neigh->ops->output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876}
877
878/* Neighbour state is OK;
879 enable fast path.
880
881 Called with write_locked neigh.
882 */
883static void neigh_connect(struct neighbour *neigh)
884{
Joe Perchesd5d427c2013-04-15 15:17:19 +0000885 neigh_dbg(2, "neigh %p is connected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886
887 neigh->output = neigh->ops->connected_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888}
889
Eric Dumazete4c4e442009-07-30 03:15:07 +0000890static void neigh_periodic_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891{
Eric Dumazete4c4e442009-07-30 03:15:07 +0000892 struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700893 struct neighbour *n;
894 struct neighbour __rcu **np;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000895 unsigned int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000896 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897
898 NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
899
Eric Dumazete4c4e442009-07-30 03:15:07 +0000900 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000901 nht = rcu_dereference_protected(tbl->nht,
902 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903
904 /*
905 * periodically recompute ReachableTime from random function
906 */
907
Eric Dumazete4c4e442009-07-30 03:15:07 +0000908 if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 struct neigh_parms *p;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000910 tbl->last_rand = jiffies;
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +0100911 list_for_each_entry(p, &tbl->parms_list, list)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 p->reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100913 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 }
915
Duan Jiongfeff9ab2014-02-27 17:14:41 +0800916 if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
917 goto out;
918
David S. Millercd089332011-07-11 01:28:12 -0700919 for (i = 0 ; i < (1 << nht->hash_shift); i++) {
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000920 np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
Eric Dumazet767e97e2010-10-06 17:49:21 -0700922 while ((n = rcu_dereference_protected(*np,
923 lockdep_is_held(&tbl->lock))) != NULL) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000924 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
Eric Dumazete4c4e442009-07-30 03:15:07 +0000926 write_lock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
Eric Dumazete4c4e442009-07-30 03:15:07 +0000928 state = n->nud_state;
Roopa Prabhu9ce33e42018-04-24 13:49:34 -0700929 if ((state & (NUD_PERMANENT | NUD_IN_TIMER)) ||
930 (n->flags & NTF_EXT_LEARNED)) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000931 write_unlock(&n->lock);
932 goto next_elt;
933 }
934
935 if (time_before(n->used, n->confirmed))
936 n->used = n->confirmed;
937
Reshetova, Elena9f237432017-06-30 13:07:55 +0300938 if (refcount_read(&n->refcnt) == 1 &&
Eric Dumazete4c4e442009-07-30 03:15:07 +0000939 (state == NUD_FAILED ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100940 time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000941 *np = n->next;
David Ahern58956312018-12-07 12:24:57 -0800942 neigh_mark_dead(n);
Eric Dumazete4c4e442009-07-30 03:15:07 +0000943 write_unlock(&n->lock);
944 neigh_cleanup_and_release(n);
945 continue;
946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 write_unlock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
949next_elt:
Eric Dumazete4c4e442009-07-30 03:15:07 +0000950 np = &n->next;
951 }
952 /*
953 * It's fine to release lock here, even if hash table
954 * grows while we are preempted.
955 */
956 write_unlock_bh(&tbl->lock);
957 cond_resched();
958 write_lock_bh(&tbl->lock);
Michel Machado84338a62012-02-21 16:04:13 -0500959 nht = rcu_dereference_protected(tbl->nht,
960 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 }
YOSHIFUJI Hideaki / 吉藤英明27246802013-01-22 05:20:05 +0000962out:
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100963 /* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks.
964 * ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2
965 * BASE_REACHABLE_TIME.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 */
viresh kumarf6180022014-01-22 12:23:33 +0530967 queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100968 NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1);
Eric Dumazete4c4e442009-07-30 03:15:07 +0000969 write_unlock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970}
971
972static __inline__ int neigh_max_probes(struct neighbour *n)
973{
974 struct neigh_parms *p = n->parms;
YOSHIFUJI Hideaki/吉藤英明8da86462015-03-19 22:41:46 +0900975 return NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) +
976 (n->nud_state & NUD_PROBE ? NEIGH_VAR(p, MCAST_REPROBES) :
977 NEIGH_VAR(p, MCAST_PROBES));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978}
979
Timo Teras5ef12d92009-06-11 04:16:28 -0700980static void neigh_invalidate(struct neighbour *neigh)
Eric Dumazet0a141502010-03-09 19:40:54 +0000981 __releases(neigh->lock)
982 __acquires(neigh->lock)
Timo Teras5ef12d92009-06-11 04:16:28 -0700983{
984 struct sk_buff *skb;
985
986 NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
Joe Perchesd5d427c2013-04-15 15:17:19 +0000987 neigh_dbg(2, "neigh %p is failed\n", neigh);
Timo Teras5ef12d92009-06-11 04:16:28 -0700988 neigh->updated = jiffies;
989
990 /* It is very thin place. report_unreachable is very complicated
991 routine. Particularly, it can hit the same neighbour entry!
992
993 So that, we try to be accurate and avoid dead loop. --ANK
994 */
995 while (neigh->nud_state == NUD_FAILED &&
996 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
997 write_unlock(&neigh->lock);
998 neigh->ops->error_report(neigh, skb);
999 write_lock(&neigh->lock);
1000 }
Eric Dumazetc9ab4d82013-06-28 02:37:42 -07001001 __skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001002 neigh->arp_queue_len_bytes = 0;
Timo Teras5ef12d92009-06-11 04:16:28 -07001003}
1004
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001005static void neigh_probe(struct neighbour *neigh)
1006 __releases(neigh->lock)
1007{
Hannes Frederic Sowa4ed377e2013-09-21 06:32:34 +02001008 struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001009 /* keep skb alive even if arp_queue overflows */
1010 if (skb)
Martin Zhang19125c12015-11-17 20:49:30 +08001011 skb = skb_clone(skb, GFP_ATOMIC);
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001012 write_unlock(&neigh->lock);
Eric Dumazet48481c82017-03-23 12:39:21 -07001013 if (neigh->ops->solicit)
1014 neigh->ops->solicit(neigh, skb);
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001015 atomic_inc(&neigh->probes);
Yang Wei87fff3ca2019-01-17 23:11:30 +08001016 consume_skb(skb);
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001017}
1018
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019/* Called when a timer expires for a neighbour entry. */
1020
Kees Cooke99e88a2017-10-16 14:43:17 -07001021static void neigh_timer_handler(struct timer_list *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022{
1023 unsigned long now, next;
Kees Cooke99e88a2017-10-16 14:43:17 -07001024 struct neighbour *neigh = from_timer(neigh, t, timer);
Eric Dumazet95c96172012-04-15 05:58:06 +00001025 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 int notify = 0;
1027
1028 write_lock(&neigh->lock);
1029
1030 state = neigh->nud_state;
1031 now = jiffies;
1032 next = now + HZ;
1033
David S. Miller045f7b32011-11-01 17:45:55 -04001034 if (!(state & NUD_IN_TIMER))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036
1037 if (state & NUD_REACHABLE) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001038 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 neigh->confirmed + neigh->parms->reachable_time)) {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001040 neigh_dbg(2, "neigh %p is still alive\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 next = neigh->confirmed + neigh->parms->reachable_time;
1042 } else if (time_before_eq(now,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001043 neigh->used +
1044 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001045 neigh_dbg(2, "neigh %p is delayed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001047 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 neigh_suspect(neigh);
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001049 next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 } else {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001051 neigh_dbg(2, "neigh %p is suspected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 neigh->nud_state = NUD_STALE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001053 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 neigh_suspect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -07001055 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 }
1057 } else if (state & NUD_DELAY) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001058 if (time_before_eq(now,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001059 neigh->confirmed +
1060 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001061 neigh_dbg(2, "neigh %p is now reachable\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 neigh->nud_state = NUD_REACHABLE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001063 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 neigh_connect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -07001065 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 next = neigh->confirmed + neigh->parms->reachable_time;
1067 } else {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001068 neigh_dbg(2, "neigh %p is probed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 neigh->nud_state = NUD_PROBE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001070 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 atomic_set(&neigh->probes, 0);
Erik Kline765c9c62015-05-18 19:44:41 +09001072 notify = 1;
Hangbin Liu19e16d22020-04-01 14:46:20 +08001073 next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
1074 HZ/100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 }
1076 } else {
1077 /* NUD_PROBE|NUD_INCOMPLETE */
Hangbin Liu19e16d22020-04-01 14:46:20 +08001078 next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME), HZ/100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 }
1080
1081 if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
1082 atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 neigh->nud_state = NUD_FAILED;
1084 notify = 1;
Timo Teras5ef12d92009-06-11 04:16:28 -07001085 neigh_invalidate(neigh);
Duan Jiong5e2c21d2014-02-27 17:03:03 +08001086 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 }
1088
1089 if (neigh->nud_state & NUD_IN_TIMER) {
Hangbin Liu96d10d52020-05-28 15:15:13 +08001090 if (time_before(next, jiffies + HZ/100))
1091 next = jiffies + HZ/100;
Herbert Xu6fb99742005-10-23 16:37:48 +10001092 if (!mod_timer(&neigh->timer, next))
1093 neigh_hold(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 }
1095 if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001096 neigh_probe(neigh);
David S. Miller9ff56602008-02-17 18:39:54 -08001097 } else {
David S. Miller69cc64d2008-02-11 21:45:44 -08001098out:
David S. Miller9ff56602008-02-17 18:39:54 -08001099 write_unlock(&neigh->lock);
1100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
Thomas Grafd961db32007-08-08 23:12:56 -07001102 if (notify)
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07001103 neigh_update_notify(neigh, 0);
Thomas Grafd961db32007-08-08 23:12:56 -07001104
Roopa Prabhu56dd18a2019-02-14 09:15:11 -08001105 trace_neigh_timer_handler(neigh, 0);
1106
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 neigh_release(neigh);
1108}
1109
1110int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
1111{
1112 int rc;
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001113 bool immediate_probe = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
1115 write_lock_bh(&neigh->lock);
1116
1117 rc = 0;
1118 if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
1119 goto out_unlock_bh;
Julian Anastasov2c51a972015-06-16 22:56:39 +03001120 if (neigh->dead)
1121 goto out_dead;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001124 if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
1125 NEIGH_VAR(neigh->parms, APP_PROBES)) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001126 unsigned long next, now = jiffies;
1127
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001128 atomic_set(&neigh->probes,
1129 NEIGH_VAR(neigh->parms, UCAST_PROBES));
Lorenzo Bianconi071c3792019-07-14 23:36:11 +02001130 neigh_del_timer(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 neigh->nud_state = NUD_INCOMPLETE;
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001132 neigh->updated = now;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001133 next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
Hangbin Liu19e16d22020-04-01 14:46:20 +08001134 HZ/100);
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001135 neigh_add_timer(neigh, next);
1136 immediate_probe = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 } else {
1138 neigh->nud_state = NUD_FAILED;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001139 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 write_unlock_bh(&neigh->lock);
1141
Wei Yongjunf3fbbe02009-02-25 00:37:32 +00001142 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 return 1;
1144 }
1145 } else if (neigh->nud_state & NUD_STALE) {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001146 neigh_dbg(2, "neigh %p is delayed\n", neigh);
Lorenzo Bianconi071c3792019-07-14 23:36:11 +02001147 neigh_del_timer(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001149 neigh->updated = jiffies;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001150 neigh_add_timer(neigh, jiffies +
1151 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 }
1153
1154 if (neigh->nud_state == NUD_INCOMPLETE) {
1155 if (skb) {
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001156 while (neigh->arp_queue_len_bytes + skb->truesize >
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001157 NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 struct sk_buff *buff;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001159
David S. Millerf72051b2008-09-23 01:11:18 -07001160 buff = __skb_dequeue(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001161 if (!buff)
1162 break;
1163 neigh->arp_queue_len_bytes -= buff->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 kfree_skb(buff);
Neil Horman9a6d2762008-07-16 20:50:49 -07001165 NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 }
Eric Dumazeta4731132010-05-27 16:09:39 -07001167 skb_dst_force(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 __skb_queue_tail(&neigh->arp_queue, skb);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001169 neigh->arp_queue_len_bytes += skb->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 }
1171 rc = 1;
1172 }
1173out_unlock_bh:
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001174 if (immediate_probe)
1175 neigh_probe(neigh);
1176 else
1177 write_unlock(&neigh->lock);
1178 local_bh_enable();
Roopa Prabhu56dd18a2019-02-14 09:15:11 -08001179 trace_neigh_event_send_done(neigh, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 return rc;
Julian Anastasov2c51a972015-06-16 22:56:39 +03001181
1182out_dead:
1183 if (neigh->nud_state & NUD_STALE)
1184 goto out_unlock_bh;
1185 write_unlock_bh(&neigh->lock);
1186 kfree_skb(skb);
Roopa Prabhu56dd18a2019-02-14 09:15:11 -08001187 trace_neigh_event_send_dead(neigh, 1);
Julian Anastasov2c51a972015-06-16 22:56:39 +03001188 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001190EXPORT_SYMBOL(__neigh_event_send);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
David S. Millerf6b72b622011-07-14 07:53:20 -07001192static void neigh_update_hhs(struct neighbour *neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193{
1194 struct hh_cache *hh;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001195 void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
Doug Kehn91a72a72010-07-14 18:02:16 -07001196 = NULL;
1197
1198 if (neigh->dev->header_ops)
1199 update = neigh->dev->header_ops->cache_update;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
1201 if (update) {
David S. Millerf6b72b622011-07-14 07:53:20 -07001202 hh = &neigh->hh;
Eric Dumazetc305c6ae2019-11-07 18:29:11 -08001203 if (READ_ONCE(hh->hh_len)) {
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001204 write_seqlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 update(hh, neigh->dev, neigh->ha);
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001206 write_sequnlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 }
1208 }
1209}
1210
1211
1212
1213/* Generic update routine.
1214 -- lladdr is new lladdr or NULL, if it is not supplied.
1215 -- new is new state.
1216 -- flags
1217 NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
1218 if it is different.
1219 NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001220 lladdr instead of overriding it
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 if it is different.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 NEIGH_UPDATE_F_ADMIN means that the change is administrative.
1223
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001224 NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 NTF_ROUTER flag.
1226 NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
1227 a router.
1228
1229 Caller MUST hold reference count on the entry.
1230 */
1231
David Ahern7a35a502018-12-05 20:02:29 -08001232static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
1233 u8 new, u32 flags, u32 nlmsg_pid,
1234 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235{
David Aherne997f8a2018-12-11 18:57:25 -07001236 bool ext_learn_change = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 u8 old;
1238 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 int notify = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 struct net_device *dev;
1241 int update_isrouter = 0;
1242
Roopa Prabhu56dd18a2019-02-14 09:15:11 -08001243 trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid);
1244
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 write_lock_bh(&neigh->lock);
1246
1247 dev = neigh->dev;
1248 old = neigh->nud_state;
1249 err = -EPERM;
1250
Chinmay Agarwaleb4e8fa2021-01-27 22:24:54 +05301251 if (neigh->dead) {
1252 NL_SET_ERR_MSG(extack, "Neighbor entry is now dead");
1253 new = old;
1254 goto out;
1255 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001256 if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 (old & (NUD_NOARP | NUD_PERMANENT)))
1258 goto out;
1259
David Aherne997f8a2018-12-11 18:57:25 -07001260 ext_learn_change = neigh_update_ext_learned(neigh, flags, &notify);
Roopa Prabhu9ce33e42018-04-24 13:49:34 -07001261
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 if (!(new & NUD_VALID)) {
1263 neigh_del_timer(neigh);
1264 if (old & NUD_CONNECTED)
1265 neigh_suspect(neigh);
David Ahern9c29a2f2018-12-11 18:57:21 -07001266 neigh->nud_state = new;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 notify = old & NUD_VALID;
Roopa Prabhud2fb4fb2018-10-20 18:09:31 -07001269 if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
Timo Teras5ef12d92009-06-11 04:16:28 -07001270 (new & NUD_FAILED)) {
1271 neigh_invalidate(neigh);
1272 notify = 1;
1273 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 goto out;
1275 }
1276
1277 /* Compare new lladdr with cached one */
1278 if (!dev->addr_len) {
1279 /* First case: device needs no address. */
1280 lladdr = neigh->ha;
1281 } else if (lladdr) {
1282 /* The second case: if something is already cached
1283 and a new address is proposed:
1284 - compare new & old
1285 - if they are different, check override flag
1286 */
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001287 if ((old & NUD_VALID) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 !memcmp(lladdr, neigh->ha, dev->addr_len))
1289 lladdr = neigh->ha;
1290 } else {
1291 /* No address is supplied; if we know something,
1292 use it, otherwise discard the request.
1293 */
1294 err = -EINVAL;
David Ahern7a35a502018-12-05 20:02:29 -08001295 if (!(old & NUD_VALID)) {
1296 NL_SET_ERR_MSG(extack, "No link layer address given");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 lladdr = neigh->ha;
1300 }
1301
Vasily Khoruzhickf0e0d042018-09-13 11:12:03 -07001302 /* Update confirmed timestamp for neighbour entry after we
1303 * received ARP packet even if it doesn't change IP to MAC binding.
1304 */
1305 if (new & NUD_CONNECTED)
1306 neigh->confirmed = jiffies;
1307
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 /* If entry was valid and address is not changed,
1309 do not change entry state, if new one is STALE.
1310 */
1311 err = 0;
1312 update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
1313 if (old & NUD_VALID) {
1314 if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
1315 update_isrouter = 0;
1316 if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
1317 (old & NUD_CONNECTED)) {
1318 lladdr = neigh->ha;
1319 new = NUD_STALE;
1320 } else
1321 goto out;
1322 } else {
Julian Anastasov0e7bbcc2016-07-27 09:56:50 +03001323 if (lladdr == neigh->ha && new == NUD_STALE &&
1324 !(flags & NEIGH_UPDATE_F_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 new = old;
1326 }
1327 }
1328
Vasily Khoruzhickf0e0d042018-09-13 11:12:03 -07001329 /* Update timestamp only once we know we will make a change to the
Ihar Hrachyshka77d71232017-05-16 08:44:24 -07001330 * neighbour entry. Otherwise we risk to move the locktime window with
1331 * noop updates and ignore relevant ARP updates.
1332 */
Vasily Khoruzhickf0e0d042018-09-13 11:12:03 -07001333 if (new != old || lladdr != neigh->ha)
Ihar Hrachyshka77d71232017-05-16 08:44:24 -07001334 neigh->updated = jiffies;
Ihar Hrachyshka77d71232017-05-16 08:44:24 -07001335
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 if (new != old) {
1337 neigh_del_timer(neigh);
Erik Kline765c9c62015-05-18 19:44:41 +09001338 if (new & NUD_PROBE)
1339 atomic_set(&neigh->probes, 0);
Pavel Emelyanova43d8992007-12-20 15:49:05 -08001340 if (new & NUD_IN_TIMER)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001341 neigh_add_timer(neigh, (jiffies +
1342 ((new & NUD_REACHABLE) ?
David S. Miller667347f2005-09-27 12:07:44 -07001343 neigh->parms->reachable_time :
1344 0)));
David Ahern9c29a2f2018-12-11 18:57:21 -07001345 neigh->nud_state = new;
Bob Gilligan53385d22013-12-15 13:39:56 -08001346 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 }
1348
1349 if (lladdr != neigh->ha) {
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001350 write_seqlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 memcpy(&neigh->ha, lladdr, dev->addr_len);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001352 write_sequnlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 neigh_update_hhs(neigh);
1354 if (!(new & NUD_CONNECTED))
1355 neigh->confirmed = jiffies -
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001356 (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 }
1359 if (new == old)
1360 goto out;
1361 if (new & NUD_CONNECTED)
1362 neigh_connect(neigh);
1363 else
1364 neigh_suspect(neigh);
1365 if (!(old & NUD_VALID)) {
1366 struct sk_buff *skb;
1367
1368 /* Again: avoid dead loop if something went wrong */
1369
1370 while (neigh->nud_state & NUD_VALID &&
1371 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
David S. Miller69cce1d2011-07-17 23:09:49 -07001372 struct dst_entry *dst = skb_dst(skb);
1373 struct neighbour *n2, *n1 = neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 write_unlock_bh(&neigh->lock);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001375
1376 rcu_read_lock();
David S. Miller13a43d92012-07-02 22:15:37 -07001377
1378 /* Why not just use 'neigh' as-is? The problem is that
1379 * things such as shaper, eql, and sch_teql can end up
1380 * using alternative, different, neigh objects to output
1381 * the packet in the output path. So what we need to do
1382 * here is re-lookup the top-level neigh in the path so
1383 * we can reinject the packet there.
1384 */
1385 n2 = NULL;
Tong Zhud47ec7a2021-03-19 14:33:37 -04001386 if (dst && dst->obsolete != DST_OBSOLETE_DEAD) {
David S. Miller13a43d92012-07-02 22:15:37 -07001387 n2 = dst_neigh_lookup_skb(dst, skb);
1388 if (n2)
1389 n1 = n2;
1390 }
David S. Miller8f40b162011-07-17 13:34:11 -07001391 n1->output(n1, skb);
David S. Miller13a43d92012-07-02 22:15:37 -07001392 if (n2)
1393 neigh_release(n2);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001394 rcu_read_unlock();
1395
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 write_lock_bh(&neigh->lock);
1397 }
Eric Dumazetc9ab4d82013-06-28 02:37:42 -07001398 __skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001399 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 }
1401out:
Roopa Prabhufc6e8072018-09-22 21:26:20 -07001402 if (update_isrouter)
1403 neigh_update_is_router(neigh, flags, &notify);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 write_unlock_bh(&neigh->lock);
Tom Tucker8d717402006-07-30 20:43:36 -07001405
David Aherne997f8a2018-12-11 18:57:25 -07001406 if (((new ^ old) & NUD_PERMANENT) || ext_learn_change)
David Ahern9c29a2f2018-12-11 18:57:21 -07001407 neigh_update_gc_list(neigh);
1408
Tom Tucker8d717402006-07-30 20:43:36 -07001409 if (notify)
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07001410 neigh_update_notify(neigh, nlmsg_pid);
Thomas Grafd961db32007-08-08 23:12:56 -07001411
Roopa Prabhu56dd18a2019-02-14 09:15:11 -08001412 trace_neigh_update_done(neigh, err);
1413
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 return err;
1415}
David Ahern7a35a502018-12-05 20:02:29 -08001416
1417int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
1418 u32 flags, u32 nlmsg_pid)
1419{
1420 return __neigh_update(neigh, lladdr, new, flags, nlmsg_pid, NULL);
1421}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001422EXPORT_SYMBOL(neigh_update);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
Jiri Benc7e980562013-12-11 13:48:20 +01001424/* Update the neigh to listen temporarily for probe responses, even if it is
1425 * in a NUD_FAILED state. The caller has to hold neigh->lock for writing.
1426 */
1427void __neigh_set_probe_once(struct neighbour *neigh)
1428{
Julian Anastasov2c51a972015-06-16 22:56:39 +03001429 if (neigh->dead)
1430 return;
Jiri Benc7e980562013-12-11 13:48:20 +01001431 neigh->updated = jiffies;
1432 if (!(neigh->nud_state & NUD_FAILED))
1433 return;
Duan Jiong2176d5d2014-05-09 13:16:48 +08001434 neigh->nud_state = NUD_INCOMPLETE;
1435 atomic_set(&neigh->probes, neigh_max_probes(neigh));
Jiri Benc7e980562013-12-11 13:48:20 +01001436 neigh_add_timer(neigh,
Hangbin Liu19e16d22020-04-01 14:46:20 +08001437 jiffies + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
1438 HZ/100));
Jiri Benc7e980562013-12-11 13:48:20 +01001439}
1440EXPORT_SYMBOL(__neigh_set_probe_once);
1441
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442struct neighbour *neigh_event_ns(struct neigh_table *tbl,
1443 u8 *lladdr, void *saddr,
1444 struct net_device *dev)
1445{
1446 struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
1447 lladdr || !dev->addr_len);
1448 if (neigh)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001449 neigh_update(neigh, lladdr, NUD_STALE,
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07001450 NEIGH_UPDATE_F_OVERRIDE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 return neigh;
1452}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001453EXPORT_SYMBOL(neigh_event_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454
Eric Dumazet34d101d2010-10-11 09:16:57 -07001455/* called with read_lock_bh(&n->lock); */
Eric W. Biedermanbdf53c52015-03-02 00:13:22 -06001456static void neigh_hh_init(struct neighbour *n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457{
Eric W. Biedermanbdf53c52015-03-02 00:13:22 -06001458 struct net_device *dev = n->dev;
1459 __be16 prot = n->tbl->protocol;
David S. Millerf6b72b622011-07-14 07:53:20 -07001460 struct hh_cache *hh = &n->hh;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001461
1462 write_lock_bh(&n->lock);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001463
David S. Millerf6b72b622011-07-14 07:53:20 -07001464 /* Only one thread can come in here and initialize the
1465 * hh_cache entry.
1466 */
David S. Millerb23b5452011-07-16 17:45:02 -07001467 if (!hh->hh_len)
1468 dev->header_ops->cache(n, hh, prot);
David S. Millerf6b72b622011-07-14 07:53:20 -07001469
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001470 write_unlock_bh(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471}
1472
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473/* Slow and careful. */
1474
David S. Miller8f40b162011-07-17 13:34:11 -07001475int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 int rc = 0;
1478
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 if (!neigh_event_send(neigh, skb)) {
1480 int err;
1481 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001482 unsigned int seq;
Eric Dumazet34d101d2010-10-11 09:16:57 -07001483
Eric Dumazetc305c6ae2019-11-07 18:29:11 -08001484 if (dev->header_ops->cache && !READ_ONCE(neigh->hh.hh_len))
Eric W. Biedermanbdf53c52015-03-02 00:13:22 -06001485 neigh_hh_init(neigh);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001486
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001487 do {
ramesh.nagappa@gmail.come1f16502012-10-05 19:10:15 +00001488 __skb_pull(skb, skb_network_offset(skb));
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001489 seq = read_seqbegin(&neigh->ha_lock);
1490 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1491 neigh->ha, NULL, skb->len);
1492 } while (read_seqretry(&neigh->ha_lock, seq));
Eric Dumazet34d101d2010-10-11 09:16:57 -07001493
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001495 rc = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 else
1497 goto out_kfree_skb;
1498 }
1499out:
1500 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501out_kfree_skb:
1502 rc = -EINVAL;
1503 kfree_skb(skb);
1504 goto out;
1505}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001506EXPORT_SYMBOL(neigh_resolve_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507
1508/* As fast as possible without hh cache */
1509
David S. Miller8f40b162011-07-17 13:34:11 -07001510int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001513 unsigned int seq;
David S. Miller8f40b162011-07-17 13:34:11 -07001514 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001516 do {
ramesh.nagappa@gmail.come1f16502012-10-05 19:10:15 +00001517 __skb_pull(skb, skb_network_offset(skb));
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001518 seq = read_seqbegin(&neigh->ha_lock);
1519 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1520 neigh->ha, NULL, skb->len);
1521 } while (read_seqretry(&neigh->ha_lock, seq));
1522
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001524 err = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 else {
1526 err = -EINVAL;
1527 kfree_skb(skb);
1528 }
1529 return err;
1530}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001531EXPORT_SYMBOL(neigh_connected_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532
David S. Miller8f40b162011-07-17 13:34:11 -07001533int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
1534{
1535 return dev_queue_xmit(skb);
1536}
1537EXPORT_SYMBOL(neigh_direct_output);
1538
Kees Cooke99e88a2017-10-16 14:43:17 -07001539static void neigh_proxy_process(struct timer_list *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540{
Kees Cooke99e88a2017-10-16 14:43:17 -07001541 struct neigh_table *tbl = from_timer(tbl, t, proxy_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 long sched_next = 0;
1543 unsigned long now = jiffies;
David S. Millerf72051b2008-09-23 01:11:18 -07001544 struct sk_buff *skb, *n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545
1546 spin_lock(&tbl->proxy_queue.lock);
1547
David S. Millerf72051b2008-09-23 01:11:18 -07001548 skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1549 long tdif = NEIGH_CB(skb)->sched_next - now;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 if (tdif <= 0) {
David S. Millerf72051b2008-09-23 01:11:18 -07001552 struct net_device *dev = skb->dev;
Eric Dumazet20e60742011-08-22 19:32:42 +00001553
David S. Millerf72051b2008-09-23 01:11:18 -07001554 __skb_unlink(skb, &tbl->proxy_queue);
Eric Dumazet20e60742011-08-22 19:32:42 +00001555 if (tbl->proxy_redo && netif_running(dev)) {
1556 rcu_read_lock();
David S. Millerf72051b2008-09-23 01:11:18 -07001557 tbl->proxy_redo(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001558 rcu_read_unlock();
1559 } else {
David S. Millerf72051b2008-09-23 01:11:18 -07001560 kfree_skb(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562
1563 dev_put(dev);
1564 } else if (!sched_next || tdif < sched_next)
1565 sched_next = tdif;
1566 }
1567 del_timer(&tbl->proxy_timer);
1568 if (sched_next)
1569 mod_timer(&tbl->proxy_timer, jiffies + sched_next);
1570 spin_unlock(&tbl->proxy_queue.lock);
1571}
1572
1573void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
1574 struct sk_buff *skb)
1575{
weichenchena533b702020-12-25 13:44:45 +08001576 unsigned long sched_next = jiffies +
1577 prandom_u32_max(NEIGH_VAR(p, PROXY_DELAY));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001579 if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 kfree_skb(skb);
1581 return;
1582 }
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001583
1584 NEIGH_CB(skb)->sched_next = sched_next;
1585 NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
1587 spin_lock(&tbl->proxy_queue.lock);
1588 if (del_timer(&tbl->proxy_timer)) {
1589 if (time_before(tbl->proxy_timer.expires, sched_next))
1590 sched_next = tbl->proxy_timer.expires;
1591 }
Eric Dumazetadf30902009-06-02 05:19:30 +00001592 skb_dst_drop(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 dev_hold(skb->dev);
1594 __skb_queue_tail(&tbl->proxy_queue, skb);
1595 mod_timer(&tbl->proxy_timer, sched_next);
1596 spin_unlock(&tbl->proxy_queue.lock);
1597}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001598EXPORT_SYMBOL(pneigh_enqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001600static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
Eric W. Biederman426b5302008-01-24 00:13:18 -08001601 struct net *net, int ifindex)
1602{
1603 struct neigh_parms *p;
1604
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001605 list_for_each_entry(p, &tbl->parms_list, list) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09001606 if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
Gao feng170d6f92013-06-20 10:01:33 +08001607 (!p->dev && !ifindex && net_eq(net, &init_net)))
Eric W. Biederman426b5302008-01-24 00:13:18 -08001608 return p;
1609 }
1610
1611 return NULL;
1612}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613
1614struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
1615 struct neigh_table *tbl)
1616{
Gao fengcf89d6b2013-06-20 10:01:32 +08001617 struct neigh_parms *p;
Stephen Hemminger00829822008-11-20 20:14:53 -08001618 struct net *net = dev_net(dev);
1619 const struct net_device_ops *ops = dev->netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620
Gao fengcf89d6b2013-06-20 10:01:32 +08001621 p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 if (p) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 p->tbl = tbl;
Reshetova, Elena63439442017-06-30 13:07:56 +03001624 refcount_set(&p->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 p->reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001626 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001627 dev_hold(dev);
1628 p->dev = dev;
Eric W. Biedermanefd7ef12015-03-11 23:04:08 -05001629 write_pnet(&p->net, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 p->sysctl_table = NULL;
Veaceslav Falico63134802013-08-02 19:07:38 +02001631
1632 if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
Veaceslav Falico63134802013-08-02 19:07:38 +02001633 dev_put(dev);
1634 kfree(p);
1635 return NULL;
1636 }
1637
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 write_lock_bh(&tbl->lock);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001639 list_add(&p->list, &tbl->parms.list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 write_unlock_bh(&tbl->lock);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01001641
1642 neigh_parms_data_state_cleanall(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 }
1644 return p;
1645}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001646EXPORT_SYMBOL(neigh_parms_alloc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647
1648static void neigh_rcu_free_parms(struct rcu_head *head)
1649{
1650 struct neigh_parms *parms =
1651 container_of(head, struct neigh_parms, rcu_head);
1652
1653 neigh_parms_put(parms);
1654}
1655
1656void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
1657{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 if (!parms || parms == &tbl->parms)
1659 return;
1660 write_lock_bh(&tbl->lock);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001661 list_del(&parms->list);
1662 parms->dead = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 write_unlock_bh(&tbl->lock);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001664 if (parms->dev)
1665 dev_put(parms->dev);
1666 call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001668EXPORT_SYMBOL(neigh_parms_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
Denis V. Lunev06f05112008-01-24 00:30:58 -08001670static void neigh_parms_destroy(struct neigh_parms *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671{
1672 kfree(parms);
1673}
1674
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001675static struct lock_class_key neigh_table_proxy_queue_class;
1676
WANG Congd7480fd2014-11-10 15:59:36 -08001677static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly;
1678
1679void neigh_table_init(int index, struct neigh_table *tbl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680{
1681 unsigned long now = jiffies;
1682 unsigned long phsize;
1683
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001684 INIT_LIST_HEAD(&tbl->parms_list);
David Ahern58956312018-12-07 12:24:57 -08001685 INIT_LIST_HEAD(&tbl->gc_list);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001686 list_add(&tbl->parms.list, &tbl->parms_list);
Eric Dumazete42ea982008-11-12 00:54:54 -08001687 write_pnet(&tbl->parms.net, &init_net);
Reshetova, Elena63439442017-06-30 13:07:56 +03001688 refcount_set(&tbl->parms.refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 tbl->parms.reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001690 neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 tbl->stats = alloc_percpu(struct neigh_statistics);
1693 if (!tbl->stats)
1694 panic("cannot create neighbour cache statistics");
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001695
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696#ifdef CONFIG_PROC_FS
Christoph Hellwig71a50532018-04-15 10:16:41 +02001697 if (!proc_create_seq_data(tbl->id, 0, init_net.proc_net_stat,
1698 &neigh_stat_seq_ops, tbl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 panic("cannot create neighbour proc dir entry");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700#endif
1701
David S. Millercd089332011-07-11 01:28:12 -07001702 RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703
1704 phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
Andrew Morton77d04bd2006-04-07 14:52:59 -07001705 tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001707 if (!tbl->nht || !tbl->phash_buckets)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 panic("cannot allocate neighbour cache hashes");
1709
YOSHIFUJI Hideaki / 吉藤英明08433ef2013-01-24 00:44:23 +00001710 if (!tbl->entry_size)
1711 tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
1712 tbl->key_len, NEIGH_PRIV_ALIGN);
1713 else
1714 WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
1715
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 rwlock_init(&tbl->lock);
Tejun Heo203b42f2012-08-21 13:18:23 -07001717 INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
viresh kumarf6180022014-01-22 12:23:33 +05301718 queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
1719 tbl->parms.reachable_time);
Kees Cooke99e88a2017-10-16 14:43:17 -07001720 timer_setup(&tbl->proxy_timer, neigh_proxy_process, 0);
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001721 skb_queue_head_init_class(&tbl->proxy_queue,
1722 &neigh_table_proxy_queue_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723
1724 tbl->last_flush = now;
1725 tbl->last_rand = now + tbl->parms.reachable_time * 20;
Simon Kelleybd89efc2006-05-12 14:56:08 -07001726
WANG Congd7480fd2014-11-10 15:59:36 -08001727 neigh_tables[index] = tbl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001729EXPORT_SYMBOL(neigh_table_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730
WANG Congd7480fd2014-11-10 15:59:36 -08001731int neigh_table_clear(int index, struct neigh_table *tbl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732{
WANG Congd7480fd2014-11-10 15:59:36 -08001733 neigh_tables[index] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 /* It is not clean... Fix it to unload IPv6 module safely */
Tejun Heoa5c30b32010-10-19 06:04:42 +00001735 cancel_delayed_work_sync(&tbl->gc_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 del_timer_sync(&tbl->proxy_timer);
1737 pneigh_queue_purge(&tbl->proxy_queue);
1738 neigh_ifdown(tbl, NULL);
1739 if (atomic_read(&tbl->entries))
Joe Perchese005d192012-05-16 19:58:40 +00001740 pr_crit("neighbour leakage\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741
Eric Dumazet6193d2b2011-01-19 22:02:47 +00001742 call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
1743 neigh_hash_free_rcu);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001744 tbl->nht = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745
1746 kfree(tbl->phash_buckets);
1747 tbl->phash_buckets = NULL;
1748
Alexey Dobriyan3f192b52007-11-05 21:28:13 -08001749 remove_proc_entry(tbl->id, init_net.proc_net_stat);
1750
Kirill Korotaev3fcde742006-09-01 01:34:10 -07001751 free_percpu(tbl->stats);
1752 tbl->stats = NULL;
1753
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 return 0;
1755}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001756EXPORT_SYMBOL(neigh_table_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757
WANG Congd7480fd2014-11-10 15:59:36 -08001758static struct neigh_table *neigh_find_table(int family)
1759{
1760 struct neigh_table *tbl = NULL;
1761
1762 switch (family) {
1763 case AF_INET:
1764 tbl = neigh_tables[NEIGH_ARP_TABLE];
1765 break;
1766 case AF_INET6:
1767 tbl = neigh_tables[NEIGH_ND_TABLE];
1768 break;
1769 case AF_DECnet:
1770 tbl = neigh_tables[NEIGH_DN_TABLE];
1771 break;
1772 }
1773
1774 return tbl;
1775}
1776
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08001777const struct nla_policy nda_policy[NDA_MAX+1] = {
Roopa Prabhu1274e1c2020-05-21 22:26:14 -07001778 [NDA_UNSPEC] = { .strict_start_type = NDA_NH_ID },
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08001779 [NDA_DST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
1780 [NDA_LLADDR] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
1781 [NDA_CACHEINFO] = { .len = sizeof(struct nda_cacheinfo) },
1782 [NDA_PROBES] = { .type = NLA_U32 },
1783 [NDA_VLAN] = { .type = NLA_U16 },
1784 [NDA_PORT] = { .type = NLA_U16 },
1785 [NDA_VNI] = { .type = NLA_U32 },
1786 [NDA_IFINDEX] = { .type = NLA_U32 },
1787 [NDA_MASTER] = { .type = NLA_U32 },
David Aherna9cd3432018-12-19 20:02:36 -08001788 [NDA_PROTOCOL] = { .type = NLA_U8 },
Roopa Prabhu1274e1c2020-05-21 22:26:14 -07001789 [NDA_NH_ID] = { .type = NLA_U32 },
Nikolay Aleksandrov899426b2020-06-23 23:47:16 +03001790 [NDA_FDB_EXT_ATTRS] = { .type = NLA_NESTED },
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08001791};
1792
David Ahernc21ef3e2017-04-16 09:48:24 -07001793static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
1794 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001796 struct net *net = sock_net(skb->sk);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001797 struct ndmsg *ndm;
1798 struct nlattr *dst_attr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 struct neigh_table *tbl;
WANG Congd7480fd2014-11-10 15:59:36 -08001800 struct neighbour *neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 struct net_device *dev = NULL;
Thomas Grafa14a49d2006-08-07 17:53:08 -07001802 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
Eric Dumazet110b2492010-10-04 04:27:36 +00001804 ASSERT_RTNL();
Thomas Grafa14a49d2006-08-07 17:53:08 -07001805 if (nlmsg_len(nlh) < sizeof(*ndm))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 goto out;
1807
Thomas Grafa14a49d2006-08-07 17:53:08 -07001808 dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
David Ahern7a35a502018-12-05 20:02:29 -08001809 if (!dst_attr) {
1810 NL_SET_ERR_MSG(extack, "Network address not specified");
Thomas Grafa14a49d2006-08-07 17:53:08 -07001811 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001812 }
Thomas Grafa14a49d2006-08-07 17:53:08 -07001813
1814 ndm = nlmsg_data(nlh);
1815 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001816 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001817 if (dev == NULL) {
1818 err = -ENODEV;
1819 goto out;
1820 }
1821 }
1822
WANG Congd7480fd2014-11-10 15:59:36 -08001823 tbl = neigh_find_table(ndm->ndm_family);
1824 if (tbl == NULL)
1825 return -EAFNOSUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826
David Ahern7a35a502018-12-05 20:02:29 -08001827 if (nla_len(dst_attr) < (int)tbl->key_len) {
1828 NL_SET_ERR_MSG(extack, "Invalid network address");
WANG Congd7480fd2014-11-10 15:59:36 -08001829 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001830 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831
WANG Congd7480fd2014-11-10 15:59:36 -08001832 if (ndm->ndm_flags & NTF_PROXY) {
1833 err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
Eric Dumazet110b2492010-10-04 04:27:36 +00001834 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 }
WANG Congd7480fd2014-11-10 15:59:36 -08001836
1837 if (dev == NULL)
1838 goto out;
1839
1840 neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1841 if (neigh == NULL) {
1842 err = -ENOENT;
1843 goto out;
1844 }
1845
David Ahern7a35a502018-12-05 20:02:29 -08001846 err = __neigh_update(neigh, NULL, NUD_FAILED,
1847 NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN,
1848 NETLINK_CB(skb).portid, extack);
Sowmini Varadhan50710342017-06-02 09:01:49 -07001849 write_lock_bh(&tbl->lock);
WANG Congd7480fd2014-11-10 15:59:36 -08001850 neigh_release(neigh);
Sowmini Varadhan50710342017-06-02 09:01:49 -07001851 neigh_remove_one(neigh, tbl);
1852 write_unlock_bh(&tbl->lock);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001853
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854out:
1855 return err;
1856}
1857
David Ahernc21ef3e2017-04-16 09:48:24 -07001858static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
1859 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860{
Roopa Prabhuf7aa74e2018-09-22 21:26:19 -07001861 int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE |
1862 NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001863 struct net *net = sock_net(skb->sk);
Thomas Graf5208deb2006-08-07 17:55:40 -07001864 struct ndmsg *ndm;
1865 struct nlattr *tb[NDA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 struct neigh_table *tbl;
1867 struct net_device *dev = NULL;
WANG Congd7480fd2014-11-10 15:59:36 -08001868 struct neighbour *neigh;
1869 void *dst, *lladdr;
David Aherndf9b0e32018-12-15 14:09:06 -08001870 u8 protocol = 0;
Thomas Graf5208deb2006-08-07 17:55:40 -07001871 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872
Eric Dumazet110b2492010-10-04 04:27:36 +00001873 ASSERT_RTNL();
Johannes Berg8cb08172019-04-26 14:07:28 +02001874 err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX,
1875 nda_policy, extack);
Thomas Graf5208deb2006-08-07 17:55:40 -07001876 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 goto out;
1878
Thomas Graf5208deb2006-08-07 17:55:40 -07001879 err = -EINVAL;
David Ahern7a35a502018-12-05 20:02:29 -08001880 if (!tb[NDA_DST]) {
1881 NL_SET_ERR_MSG(extack, "Network address not specified");
Thomas Graf5208deb2006-08-07 17:55:40 -07001882 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001883 }
Thomas Graf5208deb2006-08-07 17:55:40 -07001884
1885 ndm = nlmsg_data(nlh);
1886 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001887 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Graf5208deb2006-08-07 17:55:40 -07001888 if (dev == NULL) {
1889 err = -ENODEV;
1890 goto out;
1891 }
1892
David Ahern7a35a502018-12-05 20:02:29 -08001893 if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) {
1894 NL_SET_ERR_MSG(extack, "Invalid link address");
Eric Dumazet110b2492010-10-04 04:27:36 +00001895 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001896 }
Thomas Graf5208deb2006-08-07 17:55:40 -07001897 }
1898
WANG Congd7480fd2014-11-10 15:59:36 -08001899 tbl = neigh_find_table(ndm->ndm_family);
1900 if (tbl == NULL)
1901 return -EAFNOSUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902
David Ahern7a35a502018-12-05 20:02:29 -08001903 if (nla_len(tb[NDA_DST]) < (int)tbl->key_len) {
1904 NL_SET_ERR_MSG(extack, "Invalid network address");
WANG Congd7480fd2014-11-10 15:59:36 -08001905 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001906 }
1907
WANG Congd7480fd2014-11-10 15:59:36 -08001908 dst = nla_data(tb[NDA_DST]);
1909 lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910
David Aherna9cd3432018-12-19 20:02:36 -08001911 if (tb[NDA_PROTOCOL])
David Aherndf9b0e32018-12-15 14:09:06 -08001912 protocol = nla_get_u8(tb[NDA_PROTOCOL]);
David Aherndf9b0e32018-12-15 14:09:06 -08001913
WANG Congd7480fd2014-11-10 15:59:36 -08001914 if (ndm->ndm_flags & NTF_PROXY) {
1915 struct pneigh_entry *pn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916
WANG Congd7480fd2014-11-10 15:59:36 -08001917 err = -ENOBUFS;
1918 pn = pneigh_lookup(tbl, net, dst, dev, 1);
1919 if (pn) {
1920 pn->flags = ndm->ndm_flags;
David Aherndf9b0e32018-12-15 14:09:06 -08001921 if (protocol)
1922 pn->protocol = protocol;
Eric Biederman0c5c2d32009-03-04 00:03:08 -08001923 err = 0;
WANG Congd7480fd2014-11-10 15:59:36 -08001924 }
Eric Dumazet110b2492010-10-04 04:27:36 +00001925 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 }
1927
David Ahern7a35a502018-12-05 20:02:29 -08001928 if (!dev) {
1929 NL_SET_ERR_MSG(extack, "Device not specified");
WANG Congd7480fd2014-11-10 15:59:36 -08001930 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001931 }
WANG Congd7480fd2014-11-10 15:59:36 -08001932
David Ahernb8fb1ab2019-04-16 17:31:43 -07001933 if (tbl->allow_add && !tbl->allow_add(dev, extack)) {
1934 err = -EINVAL;
1935 goto out;
1936 }
1937
WANG Congd7480fd2014-11-10 15:59:36 -08001938 neigh = neigh_lookup(tbl, dst, dev);
1939 if (neigh == NULL) {
David Aherne997f8a2018-12-11 18:57:25 -07001940 bool exempt_from_gc;
1941
WANG Congd7480fd2014-11-10 15:59:36 -08001942 if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
1943 err = -ENOENT;
1944 goto out;
1945 }
1946
David Aherne997f8a2018-12-11 18:57:25 -07001947 exempt_from_gc = ndm->ndm_state & NUD_PERMANENT ||
1948 ndm->ndm_flags & NTF_EXT_LEARNED;
1949 neigh = ___neigh_create(tbl, dst, dev, exempt_from_gc, true);
WANG Congd7480fd2014-11-10 15:59:36 -08001950 if (IS_ERR(neigh)) {
1951 err = PTR_ERR(neigh);
1952 goto out;
1953 }
1954 } else {
1955 if (nlh->nlmsg_flags & NLM_F_EXCL) {
1956 err = -EEXIST;
1957 neigh_release(neigh);
1958 goto out;
1959 }
1960
1961 if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
Roopa Prabhuf7aa74e2018-09-22 21:26:19 -07001962 flags &= ~(NEIGH_UPDATE_F_OVERRIDE |
1963 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
WANG Congd7480fd2014-11-10 15:59:36 -08001964 }
1965
Roman Mashak38212bb2020-05-01 21:34:18 -04001966 if (protocol)
1967 neigh->protocol = protocol;
1968
Roopa Prabhu9ce33e42018-04-24 13:49:34 -07001969 if (ndm->ndm_flags & NTF_EXT_LEARNED)
1970 flags |= NEIGH_UPDATE_F_EXT_LEARNED;
1971
Roopa Prabhuf7aa74e2018-09-22 21:26:19 -07001972 if (ndm->ndm_flags & NTF_ROUTER)
1973 flags |= NEIGH_UPDATE_F_ISROUTER;
1974
WANG Congd7480fd2014-11-10 15:59:36 -08001975 if (ndm->ndm_flags & NTF_USE) {
1976 neigh_event_send(neigh, NULL);
1977 err = 0;
1978 } else
David Ahern7a35a502018-12-05 20:02:29 -08001979 err = __neigh_update(neigh, lladdr, ndm->ndm_state, flags,
1980 NETLINK_CB(skb).portid, extack);
David Aherndf9b0e32018-12-15 14:09:06 -08001981
WANG Congd7480fd2014-11-10 15:59:36 -08001982 neigh_release(neigh);
1983
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984out:
1985 return err;
1986}
1987
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001988static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
1989{
Thomas Grafca860fb2006-08-07 18:00:18 -07001990 struct nlattr *nest;
1991
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001992 nest = nla_nest_start_noflag(skb, NDTA_PARMS);
Thomas Grafca860fb2006-08-07 18:00:18 -07001993 if (nest == NULL)
1994 return -ENOBUFS;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001995
David S. Miller9a6308d2012-04-01 20:06:28 -04001996 if ((parms->dev &&
1997 nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
Reshetova, Elena63439442017-06-30 13:07:56 +03001998 nla_put_u32(skb, NDTPA_REFCNT, refcount_read(&parms->refcnt)) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001999 nla_put_u32(skb, NDTPA_QUEUE_LENBYTES,
2000 NEIGH_VAR(parms, QUEUE_LEN_BYTES)) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04002001 /* approximative value for deprecated QUEUE_LEN (in packets) */
2002 nla_put_u32(skb, NDTPA_QUEUE_LEN,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002003 NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) ||
2004 nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) ||
2005 nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) ||
2006 nla_put_u32(skb, NDTPA_UCAST_PROBES,
2007 NEIGH_VAR(parms, UCAST_PROBES)) ||
2008 nla_put_u32(skb, NDTPA_MCAST_PROBES,
2009 NEIGH_VAR(parms, MCAST_PROBES)) ||
YOSHIFUJI Hideaki/吉藤英明8da86462015-03-19 22:41:46 +09002010 nla_put_u32(skb, NDTPA_MCAST_REPROBES,
2011 NEIGH_VAR(parms, MCAST_REPROBES)) ||
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002012 nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time,
2013 NDTPA_PAD) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04002014 nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002015 NEIGH_VAR(parms, BASE_REACHABLE_TIME), NDTPA_PAD) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002016 nla_put_msecs(skb, NDTPA_GC_STALETIME,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002017 NEIGH_VAR(parms, GC_STALETIME), NDTPA_PAD) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04002018 nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002019 NEIGH_VAR(parms, DELAY_PROBE_TIME), NDTPA_PAD) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002020 nla_put_msecs(skb, NDTPA_RETRANS_TIME,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002021 NEIGH_VAR(parms, RETRANS_TIME), NDTPA_PAD) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002022 nla_put_msecs(skb, NDTPA_ANYCAST_DELAY,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002023 NEIGH_VAR(parms, ANYCAST_DELAY), NDTPA_PAD) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002024 nla_put_msecs(skb, NDTPA_PROXY_DELAY,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002025 NEIGH_VAR(parms, PROXY_DELAY), NDTPA_PAD) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002026 nla_put_msecs(skb, NDTPA_LOCKTIME,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002027 NEIGH_VAR(parms, LOCKTIME), NDTPA_PAD))
David S. Miller9a6308d2012-04-01 20:06:28 -04002028 goto nla_put_failure;
Thomas Grafca860fb2006-08-07 18:00:18 -07002029 return nla_nest_end(skb, nest);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002030
Thomas Grafca860fb2006-08-07 18:00:18 -07002031nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07002032 nla_nest_cancel(skb, nest);
2033 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002034}
2035
Thomas Grafca860fb2006-08-07 18:00:18 -07002036static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
2037 u32 pid, u32 seq, int type, int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002038{
2039 struct nlmsghdr *nlh;
2040 struct ndtmsg *ndtmsg;
2041
Thomas Grafca860fb2006-08-07 18:00:18 -07002042 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2043 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08002044 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002045
Thomas Grafca860fb2006-08-07 18:00:18 -07002046 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002047
2048 read_lock_bh(&tbl->lock);
2049 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07002050 ndtmsg->ndtm_pad1 = 0;
2051 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002052
David S. Miller9a6308d2012-04-01 20:06:28 -04002053 if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002054 nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval, NDTA_PAD) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04002055 nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
2056 nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
2057 nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
2058 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002059 {
2060 unsigned long now = jiffies;
Eric Dumazet9d027e32019-11-05 14:11:49 -08002061 long flush_delta = now - tbl->last_flush;
2062 long rand_delta = now - tbl->last_rand;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002063 struct neigh_hash_table *nht;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002064 struct ndt_config ndc = {
2065 .ndtc_key_len = tbl->key_len,
2066 .ndtc_entry_size = tbl->entry_size,
2067 .ndtc_entries = atomic_read(&tbl->entries),
2068 .ndtc_last_flush = jiffies_to_msecs(flush_delta),
2069 .ndtc_last_rand = jiffies_to_msecs(rand_delta),
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002070 .ndtc_proxy_qlen = tbl->proxy_queue.qlen,
2071 };
2072
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002073 rcu_read_lock_bh();
2074 nht = rcu_dereference_bh(tbl->nht);
David S. Miller2c2aba62011-12-28 15:06:58 -05002075 ndc.ndtc_hash_rnd = nht->hash_rnd[0];
David S. Millercd089332011-07-11 01:28:12 -07002076 ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002077 rcu_read_unlock_bh();
2078
David S. Miller9a6308d2012-04-01 20:06:28 -04002079 if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
2080 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002081 }
2082
2083 {
2084 int cpu;
2085 struct ndt_stats ndst;
2086
2087 memset(&ndst, 0, sizeof(ndst));
2088
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07002089 for_each_possible_cpu(cpu) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002090 struct neigh_statistics *st;
2091
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002092 st = per_cpu_ptr(tbl->stats, cpu);
2093 ndst.ndts_allocs += st->allocs;
2094 ndst.ndts_destroys += st->destroys;
2095 ndst.ndts_hash_grows += st->hash_grows;
2096 ndst.ndts_res_failed += st->res_failed;
2097 ndst.ndts_lookups += st->lookups;
2098 ndst.ndts_hits += st->hits;
2099 ndst.ndts_rcv_probes_mcast += st->rcv_probes_mcast;
2100 ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast;
2101 ndst.ndts_periodic_gc_runs += st->periodic_gc_runs;
2102 ndst.ndts_forced_gc_runs += st->forced_gc_runs;
Rick Jonesfb811392015-08-07 11:10:37 -07002103 ndst.ndts_table_fulls += st->table_fulls;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002104 }
2105
Nicolas Dichtelb6763382016-04-26 10:06:17 +02002106 if (nla_put_64bit(skb, NDTA_STATS, sizeof(ndst), &ndst,
2107 NDTA_PAD))
David S. Miller9a6308d2012-04-01 20:06:28 -04002108 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002109 }
2110
2111 BUG_ON(tbl->parms.dev);
2112 if (neightbl_fill_parms(skb, &tbl->parms) < 0)
Thomas Grafca860fb2006-08-07 18:00:18 -07002113 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002114
2115 read_unlock_bh(&tbl->lock);
Johannes Berg053c0952015-01-16 22:09:00 +01002116 nlmsg_end(skb, nlh);
2117 return 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002118
Thomas Grafca860fb2006-08-07 18:00:18 -07002119nla_put_failure:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002120 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08002121 nlmsg_cancel(skb, nlh);
2122 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002123}
2124
Thomas Grafca860fb2006-08-07 18:00:18 -07002125static int neightbl_fill_param_info(struct sk_buff *skb,
2126 struct neigh_table *tbl,
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002127 struct neigh_parms *parms,
Thomas Grafca860fb2006-08-07 18:00:18 -07002128 u32 pid, u32 seq, int type,
2129 unsigned int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002130{
2131 struct ndtmsg *ndtmsg;
2132 struct nlmsghdr *nlh;
2133
Thomas Grafca860fb2006-08-07 18:00:18 -07002134 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2135 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08002136 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002137
Thomas Grafca860fb2006-08-07 18:00:18 -07002138 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002139
2140 read_lock_bh(&tbl->lock);
2141 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07002142 ndtmsg->ndtm_pad1 = 0;
2143 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002144
Thomas Grafca860fb2006-08-07 18:00:18 -07002145 if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
2146 neightbl_fill_parms(skb, parms) < 0)
2147 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002148
2149 read_unlock_bh(&tbl->lock);
Johannes Berg053c0952015-01-16 22:09:00 +01002150 nlmsg_end(skb, nlh);
2151 return 0;
Thomas Grafca860fb2006-08-07 18:00:18 -07002152errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002153 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08002154 nlmsg_cancel(skb, nlh);
2155 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002156}
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002157
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002158static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07002159 [NDTA_NAME] = { .type = NLA_STRING },
2160 [NDTA_THRESH1] = { .type = NLA_U32 },
2161 [NDTA_THRESH2] = { .type = NLA_U32 },
2162 [NDTA_THRESH3] = { .type = NLA_U32 },
2163 [NDTA_GC_INTERVAL] = { .type = NLA_U64 },
2164 [NDTA_PARMS] = { .type = NLA_NESTED },
2165};
2166
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002167static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07002168 [NDTPA_IFINDEX] = { .type = NLA_U32 },
2169 [NDTPA_QUEUE_LEN] = { .type = NLA_U32 },
2170 [NDTPA_PROXY_QLEN] = { .type = NLA_U32 },
2171 [NDTPA_APP_PROBES] = { .type = NLA_U32 },
2172 [NDTPA_UCAST_PROBES] = { .type = NLA_U32 },
2173 [NDTPA_MCAST_PROBES] = { .type = NLA_U32 },
YOSHIFUJI Hideaki/吉藤英明8da86462015-03-19 22:41:46 +09002174 [NDTPA_MCAST_REPROBES] = { .type = NLA_U32 },
Thomas Graf6b3f8672006-08-07 17:58:53 -07002175 [NDTPA_BASE_REACHABLE_TIME] = { .type = NLA_U64 },
2176 [NDTPA_GC_STALETIME] = { .type = NLA_U64 },
2177 [NDTPA_DELAY_PROBE_TIME] = { .type = NLA_U64 },
2178 [NDTPA_RETRANS_TIME] = { .type = NLA_U64 },
2179 [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 },
2180 [NDTPA_PROXY_DELAY] = { .type = NLA_U64 },
2181 [NDTPA_LOCKTIME] = { .type = NLA_U64 },
2182};
2183
David Ahernc21ef3e2017-04-16 09:48:24 -07002184static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
2185 struct netlink_ext_ack *extack)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002186{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002187 struct net *net = sock_net(skb->sk);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002188 struct neigh_table *tbl;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002189 struct ndtmsg *ndtmsg;
2190 struct nlattr *tb[NDTA_MAX+1];
WANG Congd7480fd2014-11-10 15:59:36 -08002191 bool found = false;
2192 int err, tidx;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002193
Johannes Berg8cb08172019-04-26 14:07:28 +02002194 err = nlmsg_parse_deprecated(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
2195 nl_neightbl_policy, extack);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002196 if (err < 0)
2197 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002198
Thomas Graf6b3f8672006-08-07 17:58:53 -07002199 if (tb[NDTA_NAME] == NULL) {
2200 err = -EINVAL;
2201 goto errout;
2202 }
2203
2204 ndtmsg = nlmsg_data(nlh);
WANG Congd7480fd2014-11-10 15:59:36 -08002205
2206 for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2207 tbl = neigh_tables[tidx];
2208 if (!tbl)
2209 continue;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002210 if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
2211 continue;
WANG Congd7480fd2014-11-10 15:59:36 -08002212 if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) {
2213 found = true;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002214 break;
WANG Congd7480fd2014-11-10 15:59:36 -08002215 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002216 }
2217
WANG Congd7480fd2014-11-10 15:59:36 -08002218 if (!found)
2219 return -ENOENT;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002220
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002221 /*
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002222 * We acquire tbl->lock to be nice to the periodic timers and
2223 * make sure they always see a consistent set of values.
2224 */
2225 write_lock_bh(&tbl->lock);
2226
Thomas Graf6b3f8672006-08-07 17:58:53 -07002227 if (tb[NDTA_PARMS]) {
2228 struct nlattr *tbp[NDTPA_MAX+1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002229 struct neigh_parms *p;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002230 int i, ifindex = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002231
Johannes Berg8cb08172019-04-26 14:07:28 +02002232 err = nla_parse_nested_deprecated(tbp, NDTPA_MAX,
2233 tb[NDTA_PARMS],
2234 nl_ntbl_parm_policy, extack);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002235 if (err < 0)
2236 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002237
Thomas Graf6b3f8672006-08-07 17:58:53 -07002238 if (tbp[NDTPA_IFINDEX])
2239 ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002240
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07002241 p = lookup_neigh_parms(tbl, net, ifindex);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002242 if (p == NULL) {
2243 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002244 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002245 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002246
Thomas Graf6b3f8672006-08-07 17:58:53 -07002247 for (i = 1; i <= NDTPA_MAX; i++) {
2248 if (tbp[i] == NULL)
2249 continue;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002250
Thomas Graf6b3f8672006-08-07 17:58:53 -07002251 switch (i) {
2252 case NDTPA_QUEUE_LEN:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002253 NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
2254 nla_get_u32(tbp[i]) *
2255 SKB_TRUESIZE(ETH_FRAME_LEN));
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002256 break;
2257 case NDTPA_QUEUE_LENBYTES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002258 NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
2259 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002260 break;
2261 case NDTPA_PROXY_QLEN:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002262 NEIGH_VAR_SET(p, PROXY_QLEN,
2263 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002264 break;
2265 case NDTPA_APP_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002266 NEIGH_VAR_SET(p, APP_PROBES,
2267 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002268 break;
2269 case NDTPA_UCAST_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002270 NEIGH_VAR_SET(p, UCAST_PROBES,
2271 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002272 break;
2273 case NDTPA_MCAST_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002274 NEIGH_VAR_SET(p, MCAST_PROBES,
2275 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002276 break;
YOSHIFUJI Hideaki/吉藤英明8da86462015-03-19 22:41:46 +09002277 case NDTPA_MCAST_REPROBES:
2278 NEIGH_VAR_SET(p, MCAST_REPROBES,
2279 nla_get_u32(tbp[i]));
2280 break;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002281 case NDTPA_BASE_REACHABLE_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002282 NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,
2283 nla_get_msecs(tbp[i]));
Jean-Francois Remy4bf69802015-01-14 04:22:39 +01002284 /* update reachable_time as well, otherwise, the change will
2285 * only be effective after the next time neigh_periodic_work
2286 * decides to recompute it (can be multiple minutes)
2287 */
2288 p->reachable_time =
2289 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002290 break;
2291 case NDTPA_GC_STALETIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002292 NEIGH_VAR_SET(p, GC_STALETIME,
2293 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002294 break;
2295 case NDTPA_DELAY_PROBE_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002296 NEIGH_VAR_SET(p, DELAY_PROBE_TIME,
2297 nla_get_msecs(tbp[i]));
Ido Schimmel2a4501a2016-07-05 11:27:42 +02002298 call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002299 break;
2300 case NDTPA_RETRANS_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002301 NEIGH_VAR_SET(p, RETRANS_TIME,
2302 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002303 break;
2304 case NDTPA_ANYCAST_DELAY:
Jiri Pirko39774582014-01-14 15:46:07 +01002305 NEIGH_VAR_SET(p, ANYCAST_DELAY,
2306 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002307 break;
2308 case NDTPA_PROXY_DELAY:
Jiri Pirko39774582014-01-14 15:46:07 +01002309 NEIGH_VAR_SET(p, PROXY_DELAY,
2310 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002311 break;
2312 case NDTPA_LOCKTIME:
Jiri Pirko39774582014-01-14 15:46:07 +01002313 NEIGH_VAR_SET(p, LOCKTIME,
2314 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002315 break;
2316 }
2317 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002318 }
2319
Gao fengdc25c672013-06-20 10:01:34 +08002320 err = -ENOENT;
2321 if ((tb[NDTA_THRESH1] || tb[NDTA_THRESH2] ||
2322 tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]) &&
2323 !net_eq(net, &init_net))
2324 goto errout_tbl_lock;
2325
Thomas Graf6b3f8672006-08-07 17:58:53 -07002326 if (tb[NDTA_THRESH1])
2327 tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
2328
2329 if (tb[NDTA_THRESH2])
2330 tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
2331
2332 if (tb[NDTA_THRESH3])
2333 tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
2334
2335 if (tb[NDTA_GC_INTERVAL])
2336 tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2337
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002338 err = 0;
2339
Thomas Graf6b3f8672006-08-07 17:58:53 -07002340errout_tbl_lock:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002341 write_unlock_bh(&tbl->lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002342errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002343 return err;
2344}
2345
David Ahern9632d472018-10-07 20:16:37 -07002346static int neightbl_valid_dump_info(const struct nlmsghdr *nlh,
2347 struct netlink_ext_ack *extack)
2348{
2349 struct ndtmsg *ndtm;
2350
2351 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndtm))) {
2352 NL_SET_ERR_MSG(extack, "Invalid header for neighbor table dump request");
2353 return -EINVAL;
2354 }
2355
2356 ndtm = nlmsg_data(nlh);
2357 if (ndtm->ndtm_pad1 || ndtm->ndtm_pad2) {
2358 NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor table dump request");
2359 return -EINVAL;
2360 }
2361
2362 if (nlmsg_attrlen(nlh, sizeof(*ndtm))) {
2363 NL_SET_ERR_MSG(extack, "Invalid data after header in neighbor table dump request");
2364 return -EINVAL;
2365 }
2366
2367 return 0;
2368}
2369
Thomas Grafc8822a42007-03-22 11:50:06 -07002370static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002371{
David Ahern9632d472018-10-07 20:16:37 -07002372 const struct nlmsghdr *nlh = cb->nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002373 struct net *net = sock_net(skb->sk);
Thomas Grafca860fb2006-08-07 18:00:18 -07002374 int family, tidx, nidx = 0;
2375 int tbl_skip = cb->args[0];
2376 int neigh_skip = cb->args[1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002377 struct neigh_table *tbl;
2378
David Ahern9632d472018-10-07 20:16:37 -07002379 if (cb->strict_check) {
2380 int err = neightbl_valid_dump_info(nlh, cb->extack);
2381
2382 if (err < 0)
2383 return err;
2384 }
2385
2386 family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002387
WANG Congd7480fd2014-11-10 15:59:36 -08002388 for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002389 struct neigh_parms *p;
2390
WANG Congd7480fd2014-11-10 15:59:36 -08002391 tbl = neigh_tables[tidx];
2392 if (!tbl)
2393 continue;
2394
Thomas Grafca860fb2006-08-07 18:00:18 -07002395 if (tidx < tbl_skip || (family && tbl->family != family))
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002396 continue;
2397
Eric W. Biederman15e47302012-09-07 20:12:54 +00002398 if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
David Ahern9632d472018-10-07 20:16:37 -07002399 nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
David S. Miller7b46a642015-01-18 23:36:08 -05002400 NLM_F_MULTI) < 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002401 break;
2402
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01002403 nidx = 0;
2404 p = list_next_entry(&tbl->parms, list);
2405 list_for_each_entry_from(p, &tbl->parms_list, list) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002406 if (!net_eq(neigh_parms_net(p), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002407 continue;
2408
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002409 if (nidx < neigh_skip)
2410 goto next;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002411
Thomas Grafca860fb2006-08-07 18:00:18 -07002412 if (neightbl_fill_param_info(skb, tbl, p,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002413 NETLINK_CB(cb->skb).portid,
David Ahern9632d472018-10-07 20:16:37 -07002414 nlh->nlmsg_seq,
Thomas Grafca860fb2006-08-07 18:00:18 -07002415 RTM_NEWNEIGHTBL,
David S. Miller7b46a642015-01-18 23:36:08 -05002416 NLM_F_MULTI) < 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002417 goto out;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002418 next:
2419 nidx++;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002420 }
2421
Thomas Grafca860fb2006-08-07 18:00:18 -07002422 neigh_skip = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002423 }
2424out:
Thomas Grafca860fb2006-08-07 18:00:18 -07002425 cb->args[0] = tidx;
2426 cb->args[1] = nidx;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002427
2428 return skb->len;
2429}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
Thomas Graf8b8aec52006-08-07 17:56:37 -07002431static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
2432 u32 pid, u32 seq, int type, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433{
2434 unsigned long now = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 struct nda_cacheinfo ci;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002436 struct nlmsghdr *nlh;
2437 struct ndmsg *ndm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438
Thomas Graf8b8aec52006-08-07 17:56:37 -07002439 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2440 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08002441 return -EMSGSIZE;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002442
2443 ndm = nlmsg_data(nlh);
2444 ndm->ndm_family = neigh->ops->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07002445 ndm->ndm_pad1 = 0;
2446 ndm->ndm_pad2 = 0;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002447 ndm->ndm_flags = neigh->flags;
2448 ndm->ndm_type = neigh->type;
2449 ndm->ndm_ifindex = neigh->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450
David S. Miller9a6308d2012-04-01 20:06:28 -04002451 if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
2452 goto nla_put_failure;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002453
2454 read_lock_bh(&neigh->lock);
2455 ndm->ndm_state = neigh->nud_state;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00002456 if (neigh->nud_state & NUD_VALID) {
2457 char haddr[MAX_ADDR_LEN];
2458
2459 neigh_ha_snapshot(haddr, neigh, neigh->dev);
2460 if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
2461 read_unlock_bh(&neigh->lock);
2462 goto nla_put_failure;
2463 }
Thomas Graf8b8aec52006-08-07 17:56:37 -07002464 }
2465
Stephen Hemmingerb9f5f522008-06-03 16:03:15 -07002466 ci.ndm_used = jiffies_to_clock_t(now - neigh->used);
2467 ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2468 ci.ndm_updated = jiffies_to_clock_t(now - neigh->updated);
Reshetova, Elena9f237432017-06-30 13:07:55 +03002469 ci.ndm_refcnt = refcount_read(&neigh->refcnt) - 1;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002470 read_unlock_bh(&neigh->lock);
2471
David S. Miller9a6308d2012-04-01 20:06:28 -04002472 if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
2473 nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
2474 goto nla_put_failure;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002475
David Aherndf9b0e32018-12-15 14:09:06 -08002476 if (neigh->protocol && nla_put_u8(skb, NDA_PROTOCOL, neigh->protocol))
2477 goto nla_put_failure;
2478
Johannes Berg053c0952015-01-16 22:09:00 +01002479 nlmsg_end(skb, nlh);
2480 return 0;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002481
2482nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002483 nlmsg_cancel(skb, nlh);
2484 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485}
2486
Tony Zelenoff84920c12012-01-26 22:28:58 +00002487static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
2488 u32 pid, u32 seq, int type, unsigned int flags,
2489 struct neigh_table *tbl)
2490{
2491 struct nlmsghdr *nlh;
2492 struct ndmsg *ndm;
2493
2494 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2495 if (nlh == NULL)
2496 return -EMSGSIZE;
2497
2498 ndm = nlmsg_data(nlh);
2499 ndm->ndm_family = tbl->family;
2500 ndm->ndm_pad1 = 0;
2501 ndm->ndm_pad2 = 0;
2502 ndm->ndm_flags = pn->flags | NTF_PROXY;
Jun Zhao545469f2014-07-26 00:38:59 +08002503 ndm->ndm_type = RTN_UNICAST;
Konstantin Khlebnikov6adc5fd2015-12-01 01:14:48 +03002504 ndm->ndm_ifindex = pn->dev ? pn->dev->ifindex : 0;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002505 ndm->ndm_state = NUD_NONE;
2506
David S. Miller9a6308d2012-04-01 20:06:28 -04002507 if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
2508 goto nla_put_failure;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002509
David Aherndf9b0e32018-12-15 14:09:06 -08002510 if (pn->protocol && nla_put_u8(skb, NDA_PROTOCOL, pn->protocol))
2511 goto nla_put_failure;
2512
Johannes Berg053c0952015-01-16 22:09:00 +01002513 nlmsg_end(skb, nlh);
2514 return 0;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002515
2516nla_put_failure:
2517 nlmsg_cancel(skb, nlh);
2518 return -EMSGSIZE;
2519}
2520
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07002521static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid)
Thomas Grafd961db32007-08-08 23:12:56 -07002522{
2523 call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07002524 __neigh_notify(neigh, RTM_NEWNEIGH, 0, nlmsg_pid);
Thomas Grafd961db32007-08-08 23:12:56 -07002525}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526
David Ahern21fdd092015-09-29 09:32:03 -07002527static bool neigh_master_filtered(struct net_device *dev, int master_idx)
2528{
2529 struct net_device *master;
2530
2531 if (!master_idx)
2532 return false;
2533
Eric Dumazetaab456d2018-10-26 09:33:27 -07002534 master = dev ? netdev_master_upper_dev_get(dev) : NULL;
David Ahern21fdd092015-09-29 09:32:03 -07002535 if (!master || master->ifindex != master_idx)
2536 return true;
2537
2538 return false;
2539}
2540
David Ahern16660f02015-10-03 11:43:46 -07002541static bool neigh_ifindex_filtered(struct net_device *dev, int filter_idx)
2542{
Eric Dumazetaab456d2018-10-26 09:33:27 -07002543 if (filter_idx && (!dev || dev->ifindex != filter_idx))
David Ahern16660f02015-10-03 11:43:46 -07002544 return true;
2545
2546 return false;
2547}
2548
David Ahern6f52f802018-10-03 15:33:12 -07002549struct neigh_dump_filter {
2550 int master_idx;
2551 int dev_idx;
2552};
2553
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
David Ahern6f52f802018-10-03 15:33:12 -07002555 struct netlink_callback *cb,
2556 struct neigh_dump_filter *filter)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557{
Eric Dumazet767e97e2010-10-06 17:49:21 -07002558 struct net *net = sock_net(skb->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 struct neighbour *n;
2560 int rc, h, s_h = cb->args[1];
2561 int idx, s_idx = idx = cb->args[2];
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002562 struct neigh_hash_table *nht;
David Ahern21fdd092015-09-29 09:32:03 -07002563 unsigned int flags = NLM_F_MULTI;
David Ahern21fdd092015-09-29 09:32:03 -07002564
David Ahern6f52f802018-10-03 15:33:12 -07002565 if (filter->dev_idx || filter->master_idx)
2566 flags |= NLM_F_DUMP_FILTERED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002568 rcu_read_lock_bh();
2569 nht = rcu_dereference_bh(tbl->nht);
2570
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002571 for (h = s_h; h < (1 << nht->hash_shift); h++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 if (h > s_h)
2573 s_idx = 0;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002574 for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2575 n != NULL;
2576 n = rcu_dereference_bh(n->next)) {
Zhang Shengju18502ac2016-11-30 11:24:42 +08002577 if (idx < s_idx || !net_eq(dev_net(n->dev), net))
2578 goto next;
David Ahern6f52f802018-10-03 15:33:12 -07002579 if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
2580 neigh_master_filtered(n->dev, filter->master_idx))
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002581 goto next;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002582 if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 cb->nlh->nlmsg_seq,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07002584 RTM_NEWNEIGH,
David Ahern21fdd092015-09-29 09:32:03 -07002585 flags) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 rc = -1;
2587 goto out;
2588 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07002589next:
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002590 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 }
2593 rc = skb->len;
2594out:
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002595 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 cb->args[1] = h;
2597 cb->args[2] = idx;
2598 return rc;
2599}
2600
Tony Zelenoff84920c12012-01-26 22:28:58 +00002601static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
David Ahern6f52f802018-10-03 15:33:12 -07002602 struct netlink_callback *cb,
2603 struct neigh_dump_filter *filter)
Tony Zelenoff84920c12012-01-26 22:28:58 +00002604{
2605 struct pneigh_entry *n;
2606 struct net *net = sock_net(skb->sk);
2607 int rc, h, s_h = cb->args[3];
2608 int idx, s_idx = idx = cb->args[4];
David Ahern6f52f802018-10-03 15:33:12 -07002609 unsigned int flags = NLM_F_MULTI;
2610
2611 if (filter->dev_idx || filter->master_idx)
2612 flags |= NLM_F_DUMP_FILTERED;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002613
2614 read_lock_bh(&tbl->lock);
2615
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002616 for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
Tony Zelenoff84920c12012-01-26 22:28:58 +00002617 if (h > s_h)
2618 s_idx = 0;
2619 for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
Zhang Shengju18502ac2016-11-30 11:24:42 +08002620 if (idx < s_idx || pneigh_net(n) != net)
Tony Zelenoff84920c12012-01-26 22:28:58 +00002621 goto next;
David Ahern6f52f802018-10-03 15:33:12 -07002622 if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
2623 neigh_master_filtered(n->dev, filter->master_idx))
2624 goto next;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002625 if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
Tony Zelenoff84920c12012-01-26 22:28:58 +00002626 cb->nlh->nlmsg_seq,
David Ahern6f52f802018-10-03 15:33:12 -07002627 RTM_NEWNEIGH, flags, tbl) < 0) {
Tony Zelenoff84920c12012-01-26 22:28:58 +00002628 read_unlock_bh(&tbl->lock);
2629 rc = -1;
2630 goto out;
2631 }
2632 next:
2633 idx++;
2634 }
2635 }
2636
2637 read_unlock_bh(&tbl->lock);
2638 rc = skb->len;
2639out:
2640 cb->args[3] = h;
2641 cb->args[4] = idx;
2642 return rc;
2643
2644}
2645
David Ahern51183d22018-10-07 20:16:36 -07002646static int neigh_valid_dump_req(const struct nlmsghdr *nlh,
2647 bool strict_check,
2648 struct neigh_dump_filter *filter,
2649 struct netlink_ext_ack *extack)
2650{
2651 struct nlattr *tb[NDA_MAX + 1];
2652 int err, i;
2653
2654 if (strict_check) {
2655 struct ndmsg *ndm;
2656
2657 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
2658 NL_SET_ERR_MSG(extack, "Invalid header for neighbor dump request");
2659 return -EINVAL;
2660 }
2661
2662 ndm = nlmsg_data(nlh);
2663 if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_ifindex ||
David Ahernc0fde872018-12-19 16:54:38 -08002664 ndm->ndm_state || ndm->ndm_type) {
David Ahern51183d22018-10-07 20:16:36 -07002665 NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor dump request");
2666 return -EINVAL;
2667 }
2668
David Ahernc0fde872018-12-19 16:54:38 -08002669 if (ndm->ndm_flags & ~NTF_PROXY) {
2670 NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor dump request");
2671 return -EINVAL;
2672 }
2673
Johannes Berg8cb08172019-04-26 14:07:28 +02002674 err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg),
2675 tb, NDA_MAX, nda_policy,
2676 extack);
David Ahern51183d22018-10-07 20:16:36 -07002677 } else {
Johannes Berg8cb08172019-04-26 14:07:28 +02002678 err = nlmsg_parse_deprecated(nlh, sizeof(struct ndmsg), tb,
2679 NDA_MAX, nda_policy, extack);
David Ahern51183d22018-10-07 20:16:36 -07002680 }
2681 if (err < 0)
2682 return err;
2683
2684 for (i = 0; i <= NDA_MAX; ++i) {
2685 if (!tb[i])
2686 continue;
2687
2688 /* all new attributes should require strict_check */
2689 switch (i) {
2690 case NDA_IFINDEX:
David Ahern51183d22018-10-07 20:16:36 -07002691 filter->dev_idx = nla_get_u32(tb[i]);
2692 break;
2693 case NDA_MASTER:
David Ahern51183d22018-10-07 20:16:36 -07002694 filter->master_idx = nla_get_u32(tb[i]);
2695 break;
2696 default:
2697 if (strict_check) {
2698 NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor dump request");
2699 return -EINVAL;
2700 }
2701 }
2702 }
2703
2704 return 0;
2705}
2706
Thomas Grafc8822a42007-03-22 11:50:06 -07002707static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708{
David Ahern6f52f802018-10-03 15:33:12 -07002709 const struct nlmsghdr *nlh = cb->nlh;
2710 struct neigh_dump_filter filter = {};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 struct neigh_table *tbl;
2712 int t, family, s_t;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002713 int proxy = 0;
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002714 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715
David Ahern6f52f802018-10-03 15:33:12 -07002716 family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002717
2718 /* check for full ndmsg structure presence, family member is
2719 * the same for both structures
2720 */
David Ahern6f52f802018-10-03 15:33:12 -07002721 if (nlmsg_len(nlh) >= sizeof(struct ndmsg) &&
2722 ((struct ndmsg *)nlmsg_data(nlh))->ndm_flags == NTF_PROXY)
Tony Zelenoff84920c12012-01-26 22:28:58 +00002723 proxy = 1;
2724
David Ahern51183d22018-10-07 20:16:36 -07002725 err = neigh_valid_dump_req(nlh, cb->strict_check, &filter, cb->extack);
2726 if (err < 0 && cb->strict_check)
2727 return err;
2728
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 s_t = cb->args[0];
2730
WANG Congd7480fd2014-11-10 15:59:36 -08002731 for (t = 0; t < NEIGH_NR_TABLES; t++) {
2732 tbl = neigh_tables[t];
2733
2734 if (!tbl)
2735 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 if (t < s_t || (family && tbl->family != family))
2737 continue;
2738 if (t > s_t)
2739 memset(&cb->args[1], 0, sizeof(cb->args) -
2740 sizeof(cb->args[0]));
Tony Zelenoff84920c12012-01-26 22:28:58 +00002741 if (proxy)
David Ahern6f52f802018-10-03 15:33:12 -07002742 err = pneigh_dump_table(tbl, skb, cb, &filter);
Tony Zelenoff84920c12012-01-26 22:28:58 +00002743 else
David Ahern6f52f802018-10-03 15:33:12 -07002744 err = neigh_dump_table(tbl, skb, cb, &filter);
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002745 if (err < 0)
2746 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748
2749 cb->args[0] = t;
2750 return skb->len;
2751}
2752
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08002753static int neigh_valid_get_req(const struct nlmsghdr *nlh,
2754 struct neigh_table **tbl,
2755 void **dst, int *dev_idx, u8 *ndm_flags,
2756 struct netlink_ext_ack *extack)
2757{
2758 struct nlattr *tb[NDA_MAX + 1];
2759 struct ndmsg *ndm;
2760 int err, i;
2761
2762 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
2763 NL_SET_ERR_MSG(extack, "Invalid header for neighbor get request");
2764 return -EINVAL;
2765 }
2766
2767 ndm = nlmsg_data(nlh);
2768 if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_state ||
2769 ndm->ndm_type) {
2770 NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor get request");
2771 return -EINVAL;
2772 }
2773
2774 if (ndm->ndm_flags & ~NTF_PROXY) {
2775 NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor get request");
2776 return -EINVAL;
2777 }
2778
Johannes Berg8cb08172019-04-26 14:07:28 +02002779 err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb,
2780 NDA_MAX, nda_policy, extack);
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08002781 if (err < 0)
2782 return err;
2783
2784 *ndm_flags = ndm->ndm_flags;
2785 *dev_idx = ndm->ndm_ifindex;
2786 *tbl = neigh_find_table(ndm->ndm_family);
2787 if (*tbl == NULL) {
2788 NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
2789 return -EAFNOSUPPORT;
2790 }
2791
2792 for (i = 0; i <= NDA_MAX; ++i) {
2793 if (!tb[i])
2794 continue;
2795
2796 switch (i) {
2797 case NDA_DST:
2798 if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
2799 NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
2800 return -EINVAL;
2801 }
2802 *dst = nla_data(tb[i]);
2803 break;
2804 default:
2805 NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request");
2806 return -EINVAL;
2807 }
2808 }
2809
2810 return 0;
2811}
2812
2813static inline size_t neigh_nlmsg_size(void)
2814{
2815 return NLMSG_ALIGN(sizeof(struct ndmsg))
2816 + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
2817 + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
2818 + nla_total_size(sizeof(struct nda_cacheinfo))
2819 + nla_total_size(4) /* NDA_PROBES */
2820 + nla_total_size(1); /* NDA_PROTOCOL */
2821}
2822
2823static int neigh_get_reply(struct net *net, struct neighbour *neigh,
2824 u32 pid, u32 seq)
2825{
2826 struct sk_buff *skb;
2827 int err = 0;
2828
2829 skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL);
2830 if (!skb)
2831 return -ENOBUFS;
2832
2833 err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0);
2834 if (err) {
2835 kfree_skb(skb);
2836 goto errout;
2837 }
2838
2839 err = rtnl_unicast(skb, net, pid);
2840errout:
2841 return err;
2842}
2843
2844static inline size_t pneigh_nlmsg_size(void)
2845{
2846 return NLMSG_ALIGN(sizeof(struct ndmsg))
Colin Ian King463561e2018-12-20 16:50:50 +00002847 + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08002848 + nla_total_size(1); /* NDA_PROTOCOL */
2849}
2850
2851static int pneigh_get_reply(struct net *net, struct pneigh_entry *neigh,
2852 u32 pid, u32 seq, struct neigh_table *tbl)
2853{
2854 struct sk_buff *skb;
2855 int err = 0;
2856
2857 skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL);
2858 if (!skb)
2859 return -ENOBUFS;
2860
2861 err = pneigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0, tbl);
2862 if (err) {
2863 kfree_skb(skb);
2864 goto errout;
2865 }
2866
2867 err = rtnl_unicast(skb, net, pid);
2868errout:
2869 return err;
2870}
2871
2872static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
2873 struct netlink_ext_ack *extack)
2874{
2875 struct net *net = sock_net(in_skb->sk);
2876 struct net_device *dev = NULL;
2877 struct neigh_table *tbl = NULL;
2878 struct neighbour *neigh;
2879 void *dst = NULL;
2880 u8 ndm_flags = 0;
2881 int dev_idx = 0;
2882 int err;
2883
2884 err = neigh_valid_get_req(nlh, &tbl, &dst, &dev_idx, &ndm_flags,
2885 extack);
2886 if (err < 0)
2887 return err;
2888
2889 if (dev_idx) {
2890 dev = __dev_get_by_index(net, dev_idx);
2891 if (!dev) {
2892 NL_SET_ERR_MSG(extack, "Unknown device ifindex");
2893 return -ENODEV;
2894 }
2895 }
2896
2897 if (!dst) {
2898 NL_SET_ERR_MSG(extack, "Network address not specified");
2899 return -EINVAL;
2900 }
2901
2902 if (ndm_flags & NTF_PROXY) {
2903 struct pneigh_entry *pn;
2904
2905 pn = pneigh_lookup(tbl, net, dst, dev, 0);
2906 if (!pn) {
2907 NL_SET_ERR_MSG(extack, "Proxy neighbour entry not found");
2908 return -ENOENT;
2909 }
2910 return pneigh_get_reply(net, pn, NETLINK_CB(in_skb).portid,
2911 nlh->nlmsg_seq, tbl);
2912 }
2913
2914 if (!dev) {
2915 NL_SET_ERR_MSG(extack, "No device specified");
2916 return -EINVAL;
2917 }
2918
2919 neigh = neigh_lookup(tbl, dst, dev);
2920 if (!neigh) {
2921 NL_SET_ERR_MSG(extack, "Neighbour entry not found");
2922 return -ENOENT;
2923 }
2924
2925 err = neigh_get_reply(net, neigh, NETLINK_CB(in_skb).portid,
2926 nlh->nlmsg_seq);
2927
2928 neigh_release(neigh);
2929
2930 return err;
2931}
2932
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
2934{
2935 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002936 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002938 rcu_read_lock_bh();
2939 nht = rcu_dereference_bh(tbl->nht);
2940
Eric Dumazet767e97e2010-10-06 17:49:21 -07002941 read_lock(&tbl->lock); /* avoid resizes */
David S. Millercd089332011-07-11 01:28:12 -07002942 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 struct neighbour *n;
2944
Eric Dumazet767e97e2010-10-06 17:49:21 -07002945 for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
2946 n != NULL;
2947 n = rcu_dereference_bh(n->next))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 cb(n, cookie);
2949 }
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002950 read_unlock(&tbl->lock);
2951 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952}
2953EXPORT_SYMBOL(neigh_for_each);
2954
2955/* The tbl->lock must be held as a writer and BH disabled. */
2956void __neigh_for_each_release(struct neigh_table *tbl,
2957 int (*cb)(struct neighbour *))
2958{
2959 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002960 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002962 nht = rcu_dereference_protected(tbl->nht,
2963 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -07002964 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002965 struct neighbour *n;
2966 struct neighbour __rcu **np;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002968 np = &nht->hash_buckets[chain];
Eric Dumazet767e97e2010-10-06 17:49:21 -07002969 while ((n = rcu_dereference_protected(*np,
2970 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 int release;
2972
2973 write_lock(&n->lock);
2974 release = cb(n);
2975 if (release) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002976 rcu_assign_pointer(*np,
2977 rcu_dereference_protected(n->next,
2978 lockdep_is_held(&tbl->lock)));
David Ahern58956312018-12-07 12:24:57 -08002979 neigh_mark_dead(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 } else
2981 np = &n->next;
2982 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -07002983 if (release)
2984 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 }
2986 }
2987}
2988EXPORT_SYMBOL(__neigh_for_each_release);
2989
Eric W. Biedermanb79bda32015-03-07 16:25:56 -06002990int neigh_xmit(int index, struct net_device *dev,
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06002991 const void *addr, struct sk_buff *skb)
2992{
Eric W. Biedermanb79bda32015-03-07 16:25:56 -06002993 int err = -EAFNOSUPPORT;
2994 if (likely(index < NEIGH_NR_TABLES)) {
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06002995 struct neigh_table *tbl;
2996 struct neighbour *neigh;
2997
Eric W. Biedermanb79bda32015-03-07 16:25:56 -06002998 tbl = neigh_tables[index];
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06002999 if (!tbl)
3000 goto out;
David Barrosob560f032016-06-28 11:16:43 +03003001 rcu_read_lock_bh();
David Ahern4b2a2bf2019-05-01 18:18:42 -07003002 if (index == NEIGH_ARP_TABLE) {
3003 u32 key = *((u32 *)addr);
3004
3005 neigh = __ipv4_neigh_lookup_noref(dev, key);
3006 } else {
3007 neigh = __neigh_lookup_noref(tbl, addr, dev);
3008 }
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06003009 if (!neigh)
3010 neigh = __neigh_create(tbl, addr, dev, false);
3011 err = PTR_ERR(neigh);
David Barrosob560f032016-06-28 11:16:43 +03003012 if (IS_ERR(neigh)) {
3013 rcu_read_unlock_bh();
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06003014 goto out_kfree_skb;
David Barrosob560f032016-06-28 11:16:43 +03003015 }
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06003016 err = neigh->output(neigh, skb);
David Barrosob560f032016-06-28 11:16:43 +03003017 rcu_read_unlock_bh();
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06003018 }
Eric W. Biedermanb79bda32015-03-07 16:25:56 -06003019 else if (index == NEIGH_LINK_TABLE) {
3020 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
3021 addr, NULL, skb->len);
3022 if (err < 0)
3023 goto out_kfree_skb;
3024 err = dev_queue_xmit(skb);
3025 }
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06003026out:
3027 return err;
3028out_kfree_skb:
3029 kfree_skb(skb);
3030 goto out;
3031}
3032EXPORT_SYMBOL(neigh_xmit);
3033
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034#ifdef CONFIG_PROC_FS
3035
3036static struct neighbour *neigh_get_first(struct seq_file *seq)
3037{
3038 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09003039 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003040 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 struct neighbour *n = NULL;
Colin Ian Kingf530eed2019-07-26 10:46:11 +01003042 int bucket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043
3044 state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
David S. Millercd089332011-07-11 01:28:12 -07003045 for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07003046 n = rcu_dereference_bh(nht->hash_buckets[bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047
3048 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09003049 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08003050 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 if (state->neigh_sub_iter) {
3052 loff_t fakep = 0;
3053 void *v;
3054
3055 v = state->neigh_sub_iter(state, n, &fakep);
3056 if (!v)
3057 goto next;
3058 }
3059 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
3060 break;
3061 if (n->nud_state & ~NUD_NOARP)
3062 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07003063next:
3064 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 }
3066
3067 if (n)
3068 break;
3069 }
3070 state->bucket = bucket;
3071
3072 return n;
3073}
3074
3075static struct neighbour *neigh_get_next(struct seq_file *seq,
3076 struct neighbour *n,
3077 loff_t *pos)
3078{
3079 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09003080 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003081 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082
3083 if (state->neigh_sub_iter) {
3084 void *v = state->neigh_sub_iter(state, n, pos);
3085 if (v)
3086 return n;
3087 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07003088 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089
3090 while (1) {
3091 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09003092 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08003093 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 if (state->neigh_sub_iter) {
3095 void *v = state->neigh_sub_iter(state, n, pos);
3096 if (v)
3097 return n;
3098 goto next;
3099 }
3100 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
3101 break;
3102
3103 if (n->nud_state & ~NUD_NOARP)
3104 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07003105next:
3106 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 }
3108
3109 if (n)
3110 break;
3111
David S. Millercd089332011-07-11 01:28:12 -07003112 if (++state->bucket >= (1 << nht->hash_shift))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 break;
3114
Eric Dumazet767e97e2010-10-06 17:49:21 -07003115 n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 }
3117
3118 if (n && pos)
3119 --(*pos);
3120 return n;
3121}
3122
3123static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
3124{
3125 struct neighbour *n = neigh_get_first(seq);
3126
3127 if (n) {
Chris Larson745e2032008-08-03 01:10:55 -07003128 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 while (*pos) {
3130 n = neigh_get_next(seq, n, pos);
3131 if (!n)
3132 break;
3133 }
3134 }
3135 return *pos ? NULL : n;
3136}
3137
3138static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
3139{
3140 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09003141 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 struct neigh_table *tbl = state->tbl;
3143 struct pneigh_entry *pn = NULL;
3144 int bucket = state->bucket;
3145
3146 state->flags |= NEIGH_SEQ_IS_PNEIGH;
3147 for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
3148 pn = tbl->phash_buckets[bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09003149 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08003150 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 if (pn)
3152 break;
3153 }
3154 state->bucket = bucket;
3155
3156 return pn;
3157}
3158
3159static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
3160 struct pneigh_entry *pn,
3161 loff_t *pos)
3162{
3163 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09003164 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 struct neigh_table *tbl = state->tbl;
3166
Jorge Boncompte [DTI2]df07a942011-11-25 13:24:49 -05003167 do {
3168 pn = pn->next;
3169 } while (pn && !net_eq(pneigh_net(pn), net));
3170
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 while (!pn) {
3172 if (++state->bucket > PNEIGH_HASHMASK)
3173 break;
3174 pn = tbl->phash_buckets[state->bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09003175 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08003176 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 if (pn)
3178 break;
3179 }
3180
3181 if (pn && pos)
3182 --(*pos);
3183
3184 return pn;
3185}
3186
3187static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
3188{
3189 struct pneigh_entry *pn = pneigh_get_first(seq);
3190
3191 if (pn) {
Chris Larson745e2032008-08-03 01:10:55 -07003192 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 while (*pos) {
3194 pn = pneigh_get_next(seq, pn, pos);
3195 if (!pn)
3196 break;
3197 }
3198 }
3199 return *pos ? NULL : pn;
3200}
3201
3202static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
3203{
3204 struct neigh_seq_state *state = seq->private;
3205 void *rc;
Chris Larson745e2032008-08-03 01:10:55 -07003206 loff_t idxpos = *pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207
Chris Larson745e2032008-08-03 01:10:55 -07003208 rc = neigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
Chris Larson745e2032008-08-03 01:10:55 -07003210 rc = pneigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211
3212 return rc;
3213}
3214
3215void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags)
Eric Dumazetf3e92cb2019-06-15 16:28:48 -07003216 __acquires(tbl->lock)
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003217 __acquires(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218{
3219 struct neigh_seq_state *state = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220
3221 state->tbl = tbl;
3222 state->bucket = 0;
3223 state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
3224
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003225 rcu_read_lock_bh();
3226 state->nht = rcu_dereference_bh(tbl->nht);
Eric Dumazetf3e92cb2019-06-15 16:28:48 -07003227 read_lock(&tbl->lock);
Eric Dumazet767e97e2010-10-06 17:49:21 -07003228
Chris Larson745e2032008-08-03 01:10:55 -07003229 return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230}
3231EXPORT_SYMBOL(neigh_seq_start);
3232
3233void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
3234{
3235 struct neigh_seq_state *state;
3236 void *rc;
3237
3238 if (v == SEQ_START_TOKEN) {
Chris Larsonbff69732008-08-03 01:02:41 -07003239 rc = neigh_get_first(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 goto out;
3241 }
3242
3243 state = seq->private;
3244 if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
3245 rc = neigh_get_next(seq, v, NULL);
3246 if (rc)
3247 goto out;
3248 if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
3249 rc = pneigh_get_first(seq);
3250 } else {
3251 BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
3252 rc = pneigh_get_next(seq, v, NULL);
3253 }
3254out:
3255 ++(*pos);
3256 return rc;
3257}
3258EXPORT_SYMBOL(neigh_seq_next);
3259
3260void neigh_seq_stop(struct seq_file *seq, void *v)
Eric Dumazetf3e92cb2019-06-15 16:28:48 -07003261 __releases(tbl->lock)
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003262 __releases(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263{
Eric Dumazetf3e92cb2019-06-15 16:28:48 -07003264 struct neigh_seq_state *state = seq->private;
3265 struct neigh_table *tbl = state->tbl;
3266
3267 read_unlock(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003268 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269}
3270EXPORT_SYMBOL(neigh_seq_stop);
3271
3272/* statistics via seq_file */
3273
3274static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
3275{
Christoph Hellwig71a50532018-04-15 10:16:41 +02003276 struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 int cpu;
3278
3279 if (*pos == 0)
3280 return SEQ_START_TOKEN;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09003281
Rusty Russell0f23174a2008-12-29 12:23:42 +00003282 for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 if (!cpu_possible(cpu))
3284 continue;
3285 *pos = cpu+1;
3286 return per_cpu_ptr(tbl->stats, cpu);
3287 }
3288 return NULL;
3289}
3290
3291static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
3292{
Christoph Hellwig71a50532018-04-15 10:16:41 +02003293 struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 int cpu;
3295
Rusty Russell0f23174a2008-12-29 12:23:42 +00003296 for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 if (!cpu_possible(cpu))
3298 continue;
3299 *pos = cpu+1;
3300 return per_cpu_ptr(tbl->stats, cpu);
3301 }
Vasily Averin1e3f9f02020-01-23 10:11:28 +03003302 (*pos)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 return NULL;
3304}
3305
3306static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
3307{
3308
3309}
3310
3311static int neigh_stat_seq_show(struct seq_file *seq, void *v)
3312{
Christoph Hellwig71a50532018-04-15 10:16:41 +02003313 struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 struct neigh_statistics *st = v;
3315
3316 if (v == SEQ_START_TOKEN) {
Rick Jonesfb811392015-08-07 11:10:37 -07003317 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");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 return 0;
3319 }
3320
3321 seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx "
Rick Jonesfb811392015-08-07 11:10:37 -07003322 "%08lx %08lx %08lx %08lx %08lx %08lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 atomic_read(&tbl->entries),
3324
3325 st->allocs,
3326 st->destroys,
3327 st->hash_grows,
3328
3329 st->lookups,
3330 st->hits,
3331
3332 st->res_failed,
3333
3334 st->rcv_probes_mcast,
3335 st->rcv_probes_ucast,
3336
3337 st->periodic_gc_runs,
Neil Horman9a6d2762008-07-16 20:50:49 -07003338 st->forced_gc_runs,
Rick Jonesfb811392015-08-07 11:10:37 -07003339 st->unres_discards,
3340 st->table_fulls
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 );
3342
3343 return 0;
3344}
3345
Stephen Hemmingerf6908082007-03-12 14:34:29 -07003346static const struct seq_operations neigh_stat_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 .start = neigh_stat_seq_start,
3348 .next = neigh_stat_seq_next,
3349 .stop = neigh_stat_seq_stop,
3350 .show = neigh_stat_seq_show,
3351};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352#endif /* CONFIG_PROC_FS */
3353
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07003354static void __neigh_notify(struct neighbour *n, int type, int flags,
3355 u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09003357 struct net *net = dev_net(n->dev);
Thomas Graf8b8aec52006-08-07 17:56:37 -07003358 struct sk_buff *skb;
Thomas Grafb8673312006-08-15 00:33:14 -07003359 int err = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360
Thomas Graf339bf982006-11-10 14:10:15 -08003361 skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
Thomas Graf8b8aec52006-08-07 17:56:37 -07003362 if (skb == NULL)
Thomas Grafb8673312006-08-15 00:33:14 -07003363 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07003365 err = neigh_fill_info(skb, n, pid, 0, type, flags);
Patrick McHardy26932562007-01-31 23:16:40 -08003366 if (err < 0) {
3367 /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
3368 WARN_ON(err == -EMSGSIZE);
3369 kfree_skb(skb);
3370 goto errout;
3371 }
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08003372 rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
3373 return;
Thomas Grafb8673312006-08-15 00:33:14 -07003374errout:
3375 if (err < 0)
Eric W. Biederman426b5302008-01-24 00:13:18 -08003376 rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
Thomas Grafb8673312006-08-15 00:33:14 -07003377}
3378
3379void neigh_app_ns(struct neighbour *n)
3380{
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07003381 __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003383EXPORT_SYMBOL(neigh_app_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384
3385#ifdef CONFIG_SYSCTL
Cong Wangb93196d2012-12-06 10:04:04 +08003386static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387
Joe Perchesfe2c6332013-06-11 23:04:25 -07003388static int proc_unres_qlen(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003389 void *buffer, size_t *lenp, loff_t *ppos)
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003390{
3391 int size, ret;
Joe Perchesfe2c6332013-06-11 23:04:25 -07003392 struct ctl_table tmp = *ctl;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003393
Matteo Croceeec48442019-07-18 15:58:50 -07003394 tmp.extra1 = SYSCTL_ZERO;
Shan Weice46cc62012-12-04 18:49:15 +00003395 tmp.extra2 = &unres_qlen_max;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003396 tmp.data = &size;
Shan Weice46cc62012-12-04 18:49:15 +00003397
3398 size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN);
3399 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
3400
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003401 if (write && !ret)
3402 *(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
3403 return ret;
3404}
3405
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003406static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
3407 int family)
3408{
Jiri Pirkobba24892013-12-07 19:26:57 +01003409 switch (family) {
3410 case AF_INET:
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003411 return __in_dev_arp_parms_get_rcu(dev);
Jiri Pirkobba24892013-12-07 19:26:57 +01003412 case AF_INET6:
3413 return __in6_dev_nd_parms_get_rcu(dev);
3414 }
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003415 return NULL;
3416}
3417
3418static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
3419 int index)
3420{
3421 struct net_device *dev;
3422 int family = neigh_parms_family(p);
3423
3424 rcu_read_lock();
3425 for_each_netdev_rcu(net, dev) {
3426 struct neigh_parms *dst_p =
3427 neigh_get_dev_parms_rcu(dev, family);
3428
3429 if (dst_p && !test_bit(index, dst_p->data_state))
3430 dst_p->data[index] = p->data[index];
3431 }
3432 rcu_read_unlock();
3433}
3434
3435static void neigh_proc_update(struct ctl_table *ctl, int write)
3436{
3437 struct net_device *dev = ctl->extra1;
3438 struct neigh_parms *p = ctl->extra2;
Jiri Pirko77d47af2013-12-10 23:55:07 +01003439 struct net *net = neigh_parms_net(p);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003440 int index = (int *) ctl->data - p->data;
3441
3442 if (!write)
3443 return;
3444
3445 set_bit(index, p->data_state);
Marcus Huewe7627ae62017-02-15 01:00:36 +01003446 if (index == NEIGH_VAR_DELAY_PROBE_TIME)
3447 call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003448 if (!dev) /* NULL dev means this is default value */
3449 neigh_copy_dflt_parms(net, p, index);
3450}
3451
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003452static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003453 void *buffer, size_t *lenp,
3454 loff_t *ppos)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003455{
3456 struct ctl_table tmp = *ctl;
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003457 int ret;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003458
Matteo Croceeec48442019-07-18 15:58:50 -07003459 tmp.extra1 = SYSCTL_ZERO;
3460 tmp.extra2 = SYSCTL_INT_MAX;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003461
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003462 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
3463 neigh_proc_update(ctl, write);
3464 return ret;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003465}
3466
Christoph Hellwig32927392020-04-24 08:43:38 +02003467int neigh_proc_dointvec(struct ctl_table *ctl, int write, void *buffer,
3468 size_t *lenp, loff_t *ppos)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003469{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003470 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
3471
3472 neigh_proc_update(ctl, write);
3473 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003474}
3475EXPORT_SYMBOL(neigh_proc_dointvec);
3476
Christoph Hellwig32927392020-04-24 08:43:38 +02003477int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, void *buffer,
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003478 size_t *lenp, loff_t *ppos)
3479{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003480 int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
3481
3482 neigh_proc_update(ctl, write);
3483 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003484}
3485EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
3486
3487static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003488 void *buffer, size_t *lenp,
3489 loff_t *ppos)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003490{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003491 int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
3492
3493 neigh_proc_update(ctl, write);
3494 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003495}
3496
3497int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003498 void *buffer, size_t *lenp, loff_t *ppos)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003499{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003500 int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
3501
3502 neigh_proc_update(ctl, write);
3503 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003504}
3505EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
3506
3507static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003508 void *buffer, size_t *lenp,
3509 loff_t *ppos)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003510{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003511 int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
3512
3513 neigh_proc_update(ctl, write);
3514 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003515}
3516
Jean-Francois Remy4bf69802015-01-14 04:22:39 +01003517static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003518 void *buffer, size_t *lenp,
3519 loff_t *ppos)
Jean-Francois Remy4bf69802015-01-14 04:22:39 +01003520{
3521 struct neigh_parms *p = ctl->extra2;
3522 int ret;
3523
3524 if (strcmp(ctl->procname, "base_reachable_time") == 0)
3525 ret = neigh_proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
3526 else if (strcmp(ctl->procname, "base_reachable_time_ms") == 0)
3527 ret = neigh_proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
3528 else
3529 ret = -1;
3530
3531 if (write && ret == 0) {
3532 /* update reachable_time as well, otherwise, the change will
3533 * only be effective after the next time neigh_periodic_work
3534 * decides to recompute it
3535 */
3536 p->reachable_time =
3537 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
3538 }
3539 return ret;
3540}
3541
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003542#define NEIGH_PARMS_DATA_OFFSET(index) \
3543 (&((struct neigh_parms *) 0)->data[index])
3544
3545#define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \
3546 [NEIGH_VAR_ ## attr] = { \
3547 .procname = name, \
3548 .data = NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \
3549 .maxlen = sizeof(int), \
3550 .mode = mval, \
3551 .proc_handler = proc, \
3552 }
3553
3554#define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \
3555 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax)
3556
3557#define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003558 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003559
3560#define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003561 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003562
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003563#define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003564 NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003565
3566#define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003567 NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_unres_qlen)
Eric W. Biederman54716e32010-02-14 03:27:03 +00003568
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569static struct neigh_sysctl_table {
3570 struct ctl_table_header *sysctl_header;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003571 struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
Brian Haleyab32ea52006-09-22 14:15:41 -07003572} neigh_sysctl_template __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573 .neigh_vars = {
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003574 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"),
3575 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"),
3576 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"),
YOSHIFUJI Hideaki/吉藤英明8da86462015-03-19 22:41:46 +09003577 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_REPROBES, "mcast_resolicit"),
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003578 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),
3579 NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),
3580 NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"),
3581 NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"),
3582 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"),
3583 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"),
3584 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"),
3585 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"),
3586 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"),
3587 NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"),
3588 NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"),
3589 NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"),
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003590 [NEIGH_VAR_GC_INTERVAL] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 .procname = "gc_interval",
3592 .maxlen = sizeof(int),
3593 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003594 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003596 [NEIGH_VAR_GC_THRESH1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 .procname = "gc_thresh1",
3598 .maxlen = sizeof(int),
3599 .mode = 0644,
Matteo Croceeec48442019-07-18 15:58:50 -07003600 .extra1 = SYSCTL_ZERO,
3601 .extra2 = SYSCTL_INT_MAX,
Francesco Fusco555445c2013-07-24 10:39:06 +02003602 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003604 [NEIGH_VAR_GC_THRESH2] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 .procname = "gc_thresh2",
3606 .maxlen = sizeof(int),
3607 .mode = 0644,
Matteo Croceeec48442019-07-18 15:58:50 -07003608 .extra1 = SYSCTL_ZERO,
3609 .extra2 = SYSCTL_INT_MAX,
Francesco Fusco555445c2013-07-24 10:39:06 +02003610 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003612 [NEIGH_VAR_GC_THRESH3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 .procname = "gc_thresh3",
3614 .maxlen = sizeof(int),
3615 .mode = 0644,
Matteo Croceeec48442019-07-18 15:58:50 -07003616 .extra1 = SYSCTL_ZERO,
3617 .extra2 = SYSCTL_INT_MAX,
Francesco Fusco555445c2013-07-24 10:39:06 +02003618 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 },
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11003620 {},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 },
3622};
3623
3624int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
Jiri Pirko73af6142013-12-07 19:26:55 +01003625 proc_handler *handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626{
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003627 int i;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003628 struct neigh_sysctl_table *t;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003629 const char *dev_name_source;
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003630 char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
Jiri Pirko73af6142013-12-07 19:26:55 +01003631 char *p_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003633 t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 if (!t)
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003635 goto err;
3636
Jiri Pirkob194c1f2014-02-21 14:52:57 +01003637 for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003638 t->neigh_vars[i].data += (long) p;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003639 t->neigh_vars[i].extra1 = dev;
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003640 t->neigh_vars[i].extra2 = p;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642
3643 if (dev) {
3644 dev_name_source = dev->name;
Eric W. Biedermand12af672007-10-18 03:05:25 -07003645 /* Terminate the table early */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003646 memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
3647 sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 } else {
Mathias Krause9ecf07a2014-07-12 22:36:44 +02003649 struct neigh_table *tbl = p->tbl;
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003650 dev_name_source = "default";
Mathias Krause9ecf07a2014-07-12 22:36:44 +02003651 t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = &tbl->gc_interval;
3652 t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = &tbl->gc_thresh1;
3653 t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = &tbl->gc_thresh2;
3654 t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = &tbl->gc_thresh3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 }
3656
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003657 if (handler) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 /* RetransTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003659 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660 /* ReachableTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003661 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662 /* RetransTime (in milliseconds)*/
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003663 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 /* ReachableTime (in milliseconds) */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003665 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
Jean-Francois Remy4bf69802015-01-14 04:22:39 +01003666 } else {
3667 /* Those handlers will update p->reachable_time after
3668 * base_reachable_time(_ms) is set to ensure the new timer starts being
3669 * applied after the next neighbour update instead of waiting for
3670 * neigh_periodic_work to update its value (can be multiple minutes)
3671 * So any handler that replaces them should do this as well
3672 */
3673 /* ReachableTime */
3674 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler =
3675 neigh_proc_base_reachable_time;
3676 /* ReachableTime (in milliseconds) */
3677 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler =
3678 neigh_proc_base_reachable_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 }
3680
Eric W. Biederman464dc802012-11-16 03:02:59 +00003681 /* Don't export sysctls to unprivileged users */
3682 if (neigh_parms_net(p)->user_ns != &init_user_ns)
3683 t->neigh_vars[0].procname = NULL;
3684
Jiri Pirko73af6142013-12-07 19:26:55 +01003685 switch (neigh_parms_family(p)) {
3686 case AF_INET:
3687 p_name = "ipv4";
3688 break;
3689 case AF_INET6:
3690 p_name = "ipv6";
3691 break;
3692 default:
3693 BUG();
3694 }
3695
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003696 snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
3697 p_name, dev_name_source);
Denis V. Lunev4ab438f2008-02-28 20:48:01 -08003698 t->sysctl_header =
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003699 register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003700 if (!t->sysctl_header)
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003701 goto free;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003702
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 p->sysctl_table = t;
3704 return 0;
3705
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003706free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 kfree(t);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003708err:
3709 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003711EXPORT_SYMBOL(neigh_sysctl_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712
3713void neigh_sysctl_unregister(struct neigh_parms *p)
3714{
3715 if (p->sysctl_table) {
3716 struct neigh_sysctl_table *t = p->sysctl_table;
3717 p->sysctl_table = NULL;
Eric W. Biederman5dd3df12012-04-19 13:24:33 +00003718 unregister_net_sysctl_table(t->sysctl_header);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 kfree(t);
3720 }
3721}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003722EXPORT_SYMBOL(neigh_sysctl_unregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723
3724#endif /* CONFIG_SYSCTL */
3725
Thomas Grafc8822a42007-03-22 11:50:06 -07003726static int __init neigh_init(void)
3727{
Florian Westphalb97bac62017-08-09 20:41:48 +02003728 rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0);
3729 rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0);
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08003730 rtnl_register(PF_UNSPEC, RTM_GETNEIGH, neigh_get, neigh_dump_info, 0);
Thomas Grafc8822a42007-03-22 11:50:06 -07003731
Greg Rosec7ac8672011-06-10 01:27:09 +00003732 rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
Florian Westphalb97bac62017-08-09 20:41:48 +02003733 0);
3734 rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, 0);
Thomas Grafc8822a42007-03-22 11:50:06 -07003735
3736 return 0;
3737}
3738
3739subsys_initcall(neigh_init);