blob: 6d2d557442dc69b403cdbf98b4b8f5d593287121 [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
Joe Perchesd5d427c2013-04-15 15:17:19 +000044#define DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#define NEIGH_DEBUG 1
Joe Perchesd5d427c2013-04-15 15:17:19 +000046#define neigh_dbg(level, fmt, ...) \
47do { \
48 if (level <= NEIGH_DEBUG) \
49 pr_debug(fmt, ##__VA_ARGS__); \
50} while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#define PNEIGH_HASHMASK 0xF
53
Kees Cooke99e88a2017-10-16 14:43:17 -070054static void neigh_timer_handler(struct timer_list *t);
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -070055static void __neigh_notify(struct neighbour *n, int type, int flags,
56 u32 pid);
57static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid);
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +020058static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
59 struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Amos Waterland45fc3b12005-09-24 16:53:16 -070061#ifdef CONFIG_PROC_FS
Christoph Hellwig71a50532018-04-15 10:16:41 +020062static const struct seq_operations neigh_stat_seq_ops;
Amos Waterland45fc3b12005-09-24 16:53:16 -070063#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65/*
66 Neighbour hash table buckets are protected with rwlock tbl->lock.
67
68 - All the scans/updates to hash buckets MUST be made under this lock.
69 - NOTHING clever should be made under this lock: no callbacks
70 to protocol backends, no attempts to send something to network.
71 It will result in deadlocks, if backend/driver wants to use neighbour
72 cache.
73 - If the entry requires some non-trivial actions, increase
74 its reference count and release table lock.
75
76 Neighbour entries are protected:
77 - with reference count.
78 - with rwlock neigh->lock
79
80 Reference count prevents destruction.
81
82 neigh->lock mainly serializes ll address data and its validity state.
83 However, the same lock is used to protect another entry fields:
84 - timer
85 - resolution queue
86
87 Again, nothing clever shall be made under neigh->lock,
88 the most complicated procedure, which we allow is dev->hard_header.
89 It is supposed, that dev->hard_header is simplistic and does
90 not make callbacks to neighbour tables.
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 */
92
David S. Miller8f40b162011-07-17 13:34:11 -070093static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -070094{
95 kfree_skb(skb);
96 return -ENETDOWN;
97}
98
Thomas Graf4f494552007-08-08 23:12:36 -070099static void neigh_cleanup_and_release(struct neighbour *neigh)
100{
Roopa Prabhu56dd18a2019-02-14 09:15:11 -0800101 trace_neigh_cleanup_and_release(neigh, 0);
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -0700102 __neigh_notify(neigh, RTM_DELNEIGH, 0, 0);
Ido Schimmel53f800e2016-12-23 09:32:48 +0100103 call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
Thomas Graf4f494552007-08-08 23:12:36 -0700104 neigh_release(neigh);
105}
106
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107/*
108 * It is random distribution in the interval (1/2)*base...(3/2)*base.
109 * It corresponds to default IPv6 settings and is not overridable,
110 * because it is really reasonable choice.
111 */
112
113unsigned long neigh_rand_reach_time(unsigned long base)
114{
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500115 return base ? (prandom_u32() % base) + (base >> 1) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900117EXPORT_SYMBOL(neigh_rand_reach_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
David Ahern58956312018-12-07 12:24:57 -0800119static void neigh_mark_dead(struct neighbour *n)
120{
121 n->dead = 1;
122 if (!list_empty(&n->gc_list)) {
123 list_del_init(&n->gc_list);
124 atomic_dec(&n->tbl->gc_entries);
125 }
126}
127
David Ahern9c29a2f2018-12-11 18:57:21 -0700128static void neigh_update_gc_list(struct neighbour *n)
David Ahern58956312018-12-07 12:24:57 -0800129{
David Aherne997f8a2018-12-11 18:57:25 -0700130 bool on_gc_list, exempt_from_gc;
David Ahern58956312018-12-07 12:24:57 -0800131
David Ahern9c29a2f2018-12-11 18:57:21 -0700132 write_lock_bh(&n->tbl->lock);
133 write_lock(&n->lock);
David Ahern58956312018-12-07 12:24:57 -0800134
David Aherne997f8a2018-12-11 18:57:25 -0700135 /* remove from the gc list if new state is permanent or if neighbor
136 * is externally learned; otherwise entry should be on the gc list
David Ahern58956312018-12-07 12:24:57 -0800137 */
David Aherne997f8a2018-12-11 18:57:25 -0700138 exempt_from_gc = n->nud_state & NUD_PERMANENT ||
139 n->flags & NTF_EXT_LEARNED;
David Ahern9c29a2f2018-12-11 18:57:21 -0700140 on_gc_list = !list_empty(&n->gc_list);
David Ahern8cc196d2018-12-10 13:54:07 -0800141
David Aherne997f8a2018-12-11 18:57:25 -0700142 if (exempt_from_gc && on_gc_list) {
David Ahern9c29a2f2018-12-11 18:57:21 -0700143 list_del_init(&n->gc_list);
David Ahern58956312018-12-07 12:24:57 -0800144 atomic_dec(&n->tbl->gc_entries);
David Aherne997f8a2018-12-11 18:57:25 -0700145 } else if (!exempt_from_gc && !on_gc_list) {
David Ahern58956312018-12-07 12:24:57 -0800146 /* add entries to the tail; cleaning removes from the front */
147 list_add_tail(&n->gc_list, &n->tbl->gc_list);
148 atomic_inc(&n->tbl->gc_entries);
149 }
David Ahern9c29a2f2018-12-11 18:57:21 -0700150
151 write_unlock(&n->lock);
152 write_unlock_bh(&n->tbl->lock);
David Ahern58956312018-12-07 12:24:57 -0800153}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
David Aherne997f8a2018-12-11 18:57:25 -0700155static bool neigh_update_ext_learned(struct neighbour *neigh, u32 flags,
David Ahern526f1b52018-12-11 18:57:24 -0700156 int *notify)
157{
David Aherne997f8a2018-12-11 18:57:25 -0700158 bool rc = false;
David Ahern526f1b52018-12-11 18:57:24 -0700159 u8 ndm_flags;
160
161 if (!(flags & NEIGH_UPDATE_F_ADMIN))
David Aherne997f8a2018-12-11 18:57:25 -0700162 return rc;
David Ahern526f1b52018-12-11 18:57:24 -0700163
164 ndm_flags = (flags & NEIGH_UPDATE_F_EXT_LEARNED) ? NTF_EXT_LEARNED : 0;
165 if ((neigh->flags ^ ndm_flags) & NTF_EXT_LEARNED) {
166 if (ndm_flags & NTF_EXT_LEARNED)
167 neigh->flags |= NTF_EXT_LEARNED;
168 else
169 neigh->flags &= ~NTF_EXT_LEARNED;
David Aherne997f8a2018-12-11 18:57:25 -0700170 rc = true;
David Ahern526f1b52018-12-11 18:57:24 -0700171 *notify = 1;
172 }
David Aherne997f8a2018-12-11 18:57:25 -0700173
174 return rc;
David Ahern526f1b52018-12-11 18:57:24 -0700175}
176
David Ahern7e6f1822018-12-11 18:57:23 -0700177static bool neigh_del(struct neighbour *n, struct neighbour __rcu **np,
178 struct neigh_table *tbl)
Sowmini Varadhan50710342017-06-02 09:01:49 -0700179{
180 bool retval = false;
181
182 write_lock(&n->lock);
David Ahern7e6f1822018-12-11 18:57:23 -0700183 if (refcount_read(&n->refcnt) == 1) {
Sowmini Varadhan50710342017-06-02 09:01:49 -0700184 struct neighbour *neigh;
185
186 neigh = rcu_dereference_protected(n->next,
187 lockdep_is_held(&tbl->lock));
188 rcu_assign_pointer(*np, neigh);
David Ahern58956312018-12-07 12:24:57 -0800189 neigh_mark_dead(n);
Sowmini Varadhan50710342017-06-02 09:01:49 -0700190 retval = true;
191 }
192 write_unlock(&n->lock);
193 if (retval)
194 neigh_cleanup_and_release(n);
195 return retval;
196}
197
198bool neigh_remove_one(struct neighbour *ndel, struct neigh_table *tbl)
199{
200 struct neigh_hash_table *nht;
201 void *pkey = ndel->primary_key;
202 u32 hash_val;
203 struct neighbour *n;
204 struct neighbour __rcu **np;
205
206 nht = rcu_dereference_protected(tbl->nht,
207 lockdep_is_held(&tbl->lock));
208 hash_val = tbl->hash(pkey, ndel->dev, nht->hash_rnd);
209 hash_val = hash_val >> (32 - nht->hash_shift);
210
211 np = &nht->hash_buckets[hash_val];
212 while ((n = rcu_dereference_protected(*np,
213 lockdep_is_held(&tbl->lock)))) {
214 if (n == ndel)
David Ahern7e6f1822018-12-11 18:57:23 -0700215 return neigh_del(n, np, tbl);
Sowmini Varadhan50710342017-06-02 09:01:49 -0700216 np = &n->next;
217 }
218 return false;
219}
220
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221static int neigh_forced_gc(struct neigh_table *tbl)
222{
David Ahern58956312018-12-07 12:24:57 -0800223 int max_clean = atomic_read(&tbl->gc_entries) - tbl->gc_thresh2;
224 unsigned long tref = jiffies - 5 * HZ;
David Ahern58956312018-12-07 12:24:57 -0800225 struct neighbour *n, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 int shrunk = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
228 NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
229
230 write_lock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
David Ahern58956312018-12-07 12:24:57 -0800232 list_for_each_entry_safe(n, tmp, &tbl->gc_list, gc_list) {
233 if (refcount_read(&n->refcnt) == 1) {
234 bool remove = false;
235
236 write_lock(&n->lock);
David Ahern758a7f02018-12-11 18:57:22 -0700237 if ((n->nud_state == NUD_FAILED) ||
Jeff Dike8cf88212020-11-12 20:58:15 -0500238 (tbl->is_multicast &&
239 tbl->is_multicast(n->primary_key)) ||
David Aherne997f8a2018-12-11 18:57:25 -0700240 time_after(tref, n->updated))
David Ahern58956312018-12-07 12:24:57 -0800241 remove = true;
242 write_unlock(&n->lock);
243
244 if (remove && neigh_remove_one(n, tbl))
245 shrunk++;
246 if (shrunk >= max_clean)
247 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 }
249 }
250
251 tbl->last_flush = jiffies;
252
253 write_unlock_bh(&tbl->lock);
254
255 return shrunk;
256}
257
Pavel Emelyanova43d8992007-12-20 15:49:05 -0800258static void neigh_add_timer(struct neighbour *n, unsigned long when)
259{
260 neigh_hold(n);
261 if (unlikely(mod_timer(&n->timer, when))) {
262 printk("NEIGH: BUG, double timer add, state is %x\n",
263 n->nud_state);
264 dump_stack();
265 }
266}
267
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268static int neigh_del_timer(struct neighbour *n)
269{
270 if ((n->nud_state & NUD_IN_TIMER) &&
271 del_timer(&n->timer)) {
272 neigh_release(n);
273 return 1;
274 }
275 return 0;
276}
277
278static void pneigh_queue_purge(struct sk_buff_head *list)
279{
280 struct sk_buff *skb;
281
282 while ((skb = skb_dequeue(list)) != NULL) {
283 dev_put(skb->dev);
284 kfree_skb(skb);
285 }
286}
287
David Ahern859bd2e2018-10-11 20:33:49 -0700288static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev,
289 bool skip_perm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290{
291 int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000292 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000294 nht = rcu_dereference_protected(tbl->nht,
295 lockdep_is_held(&tbl->lock));
296
David S. Millercd089332011-07-11 01:28:12 -0700297 for (i = 0; i < (1 << nht->hash_shift); i++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700298 struct neighbour *n;
299 struct neighbour __rcu **np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
Eric Dumazet767e97e2010-10-06 17:49:21 -0700301 while ((n = rcu_dereference_protected(*np,
302 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 if (dev && n->dev != dev) {
304 np = &n->next;
305 continue;
306 }
David Ahern859bd2e2018-10-11 20:33:49 -0700307 if (skip_perm && n->nud_state & NUD_PERMANENT) {
308 np = &n->next;
309 continue;
310 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700311 rcu_assign_pointer(*np,
312 rcu_dereference_protected(n->next,
313 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 write_lock(&n->lock);
315 neigh_del_timer(n);
David Ahern58956312018-12-07 12:24:57 -0800316 neigh_mark_dead(n);
Reshetova, Elena9f237432017-06-30 13:07:55 +0300317 if (refcount_read(&n->refcnt) != 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 /* The most unpleasant situation.
319 We must destroy neighbour entry,
320 but someone still uses it.
321
322 The destroy will be delayed until
323 the last user releases us, but
324 we must kill timers etc. and move
325 it to safe state.
326 */
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700327 __skb_queue_purge(&n->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000328 n->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 n->output = neigh_blackhole;
330 if (n->nud_state & NUD_VALID)
331 n->nud_state = NUD_NOARP;
332 else
333 n->nud_state = NUD_NONE;
Joe Perchesd5d427c2013-04-15 15:17:19 +0000334 neigh_dbg(2, "neigh %p is stray\n", n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 }
336 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700337 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 }
339 }
Herbert Xu49636bb2005-10-23 17:18:00 +1000340}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Herbert Xu49636bb2005-10-23 17:18:00 +1000342void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
343{
344 write_lock_bh(&tbl->lock);
David Ahern859bd2e2018-10-11 20:33:49 -0700345 neigh_flush_dev(tbl, dev, false);
Herbert Xu49636bb2005-10-23 17:18:00 +1000346 write_unlock_bh(&tbl->lock);
347}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900348EXPORT_SYMBOL(neigh_changeaddr);
Herbert Xu49636bb2005-10-23 17:18:00 +1000349
David Ahern859bd2e2018-10-11 20:33:49 -0700350static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
351 bool skip_perm)
Herbert Xu49636bb2005-10-23 17:18:00 +1000352{
353 write_lock_bh(&tbl->lock);
David Ahern859bd2e2018-10-11 20:33:49 -0700354 neigh_flush_dev(tbl, dev, skip_perm);
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +0200355 pneigh_ifdown_and_unlock(tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
357 del_timer_sync(&tbl->proxy_timer);
358 pneigh_queue_purge(&tbl->proxy_queue);
359 return 0;
360}
David Ahern859bd2e2018-10-11 20:33:49 -0700361
362int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev)
363{
364 __neigh_ifdown(tbl, dev, true);
365 return 0;
366}
367EXPORT_SYMBOL(neigh_carrier_down);
368
369int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
370{
371 __neigh_ifdown(tbl, dev, false);
372 return 0;
373}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900374EXPORT_SYMBOL(neigh_ifdown);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
David Ahern58956312018-12-07 12:24:57 -0800376static struct neighbour *neigh_alloc(struct neigh_table *tbl,
377 struct net_device *dev,
David Aherne997f8a2018-12-11 18:57:25 -0700378 bool exempt_from_gc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
380 struct neighbour *n = NULL;
381 unsigned long now = jiffies;
382 int entries;
383
David Aherne997f8a2018-12-11 18:57:25 -0700384 if (exempt_from_gc)
David Ahern58956312018-12-07 12:24:57 -0800385 goto do_alloc;
386
387 entries = atomic_inc_return(&tbl->gc_entries) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 if (entries >= tbl->gc_thresh3 ||
389 (entries >= tbl->gc_thresh2 &&
390 time_after(now, tbl->last_flush + 5 * HZ))) {
391 if (!neigh_forced_gc(tbl) &&
Rick Jonesfb811392015-08-07 11:10:37 -0700392 entries >= tbl->gc_thresh3) {
393 net_info_ratelimited("%s: neighbor table overflow!\n",
394 tbl->id);
395 NEIGH_CACHE_STAT_INC(tbl, table_fulls);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 goto out_entries;
Rick Jonesfb811392015-08-07 11:10:37 -0700397 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 }
399
David Ahern58956312018-12-07 12:24:57 -0800400do_alloc:
YOSHIFUJI Hideaki / 吉藤英明08433ef2013-01-24 00:44:23 +0000401 n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 if (!n)
403 goto out_entries;
404
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700405 __skb_queue_head_init(&n->arp_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 rwlock_init(&n->lock);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +0000407 seqlock_init(&n->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 n->updated = n->used = now;
409 n->nud_state = NUD_NONE;
410 n->output = neigh_blackhole;
David S. Millerf6b72b622011-07-14 07:53:20 -0700411 seqlock_init(&n->hh.hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 n->parms = neigh_parms_clone(&tbl->parms);
Kees Cooke99e88a2017-10-16 14:43:17 -0700413 timer_setup(&n->timer, neigh_timer_handler, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
415 NEIGH_CACHE_STAT_INC(tbl, allocs);
416 n->tbl = tbl;
Reshetova, Elena9f237432017-06-30 13:07:55 +0300417 refcount_set(&n->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 n->dead = 1;
David Ahern8cc196d2018-12-10 13:54:07 -0800419 INIT_LIST_HEAD(&n->gc_list);
David Ahern58956312018-12-07 12:24:57 -0800420
421 atomic_inc(&tbl->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422out:
423 return n;
424
425out_entries:
David Aherne997f8a2018-12-11 18:57:25 -0700426 if (!exempt_from_gc)
David Ahern58956312018-12-07 12:24:57 -0800427 atomic_dec(&tbl->gc_entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 goto out;
429}
430
David S. Miller2c2aba62011-12-28 15:06:58 -0500431static void neigh_get_hash_rnd(u32 *x)
432{
Jason A. Donenfeldb3d0f782017-06-07 23:00:05 -0400433 *x = get_random_u32() | 1;
David S. Miller2c2aba62011-12-28 15:06:58 -0500434}
435
David S. Millercd089332011-07-11 01:28:12 -0700436static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
David S. Millercd089332011-07-11 01:28:12 -0700438 size_t size = (1 << shift) * sizeof(struct neighbour *);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000439 struct neigh_hash_table *ret;
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000440 struct neighbour __rcu **buckets;
David S. Miller2c2aba62011-12-28 15:06:58 -0500441 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000443 ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
444 if (!ret)
445 return NULL;
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300446 if (size <= PAGE_SIZE) {
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000447 buckets = kzalloc(size, GFP_ATOMIC);
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300448 } else {
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000449 buckets = (struct neighbour __rcu **)
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000450 __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
451 get_order(size));
Konstantin Khlebnikov01b833a2019-01-14 13:38:43 +0300452 kmemleak_alloc(buckets, size, 1, GFP_ATOMIC);
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300453 }
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000454 if (!buckets) {
455 kfree(ret);
456 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 }
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000458 ret->hash_buckets = buckets;
David S. Millercd089332011-07-11 01:28:12 -0700459 ret->hash_shift = shift;
David S. Miller2c2aba62011-12-28 15:06:58 -0500460 for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
461 neigh_get_hash_rnd(&ret->hash_rnd[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 return ret;
463}
464
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000465static void neigh_hash_free_rcu(struct rcu_head *head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000467 struct neigh_hash_table *nht = container_of(head,
468 struct neigh_hash_table,
469 rcu);
David S. Millercd089332011-07-11 01:28:12 -0700470 size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000471 struct neighbour __rcu **buckets = nht->hash_buckets;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300473 if (size <= PAGE_SIZE) {
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000474 kfree(buckets);
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300475 } else {
476 kmemleak_free(buckets);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000477 free_pages((unsigned long)buckets, get_order(size));
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300478 }
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000479 kfree(nht);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480}
481
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000482static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
David S. Millercd089332011-07-11 01:28:12 -0700483 unsigned long new_shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000485 unsigned int i, hash;
486 struct neigh_hash_table *new_nht, *old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
488 NEIGH_CACHE_STAT_INC(tbl, hash_grows);
489
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000490 old_nht = rcu_dereference_protected(tbl->nht,
491 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -0700492 new_nht = neigh_hash_alloc(new_shift);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000493 if (!new_nht)
494 return old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
David S. Millercd089332011-07-11 01:28:12 -0700496 for (i = 0; i < (1 << old_nht->hash_shift); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 struct neighbour *n, *next;
498
Eric Dumazet767e97e2010-10-06 17:49:21 -0700499 for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
500 lockdep_is_held(&tbl->lock));
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000501 n != NULL;
502 n = next) {
503 hash = tbl->hash(n->primary_key, n->dev,
504 new_nht->hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
David S. Millercd089332011-07-11 01:28:12 -0700506 hash >>= (32 - new_nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700507 next = rcu_dereference_protected(n->next,
508 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
Eric Dumazet767e97e2010-10-06 17:49:21 -0700510 rcu_assign_pointer(n->next,
511 rcu_dereference_protected(
512 new_nht->hash_buckets[hash],
513 lockdep_is_held(&tbl->lock)));
514 rcu_assign_pointer(new_nht->hash_buckets[hash], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 }
516 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000518 rcu_assign_pointer(tbl->nht, new_nht);
519 call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
520 return new_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521}
522
523struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
524 struct net_device *dev)
525{
526 struct neighbour *n;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900527
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 NEIGH_CACHE_STAT_INC(tbl, lookups);
529
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000530 rcu_read_lock_bh();
Eric W. Biederman60395a22015-03-03 17:10:44 -0600531 n = __neigh_lookup_noref(tbl, pkey, dev);
532 if (n) {
Reshetova, Elena9f237432017-06-30 13:07:55 +0300533 if (!refcount_inc_not_zero(&n->refcnt))
Eric W. Biederman60395a22015-03-03 17:10:44 -0600534 n = NULL;
535 NEIGH_CACHE_STAT_INC(tbl, hits);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700537
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000538 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 return n;
540}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900541EXPORT_SYMBOL(neigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
Eric W. Biederman426b5302008-01-24 00:13:18 -0800543struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
544 const void *pkey)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545{
546 struct neighbour *n;
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300547 unsigned int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800548 u32 hash_val;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000549 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
551 NEIGH_CACHE_STAT_INC(tbl, lookups);
552
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000553 rcu_read_lock_bh();
554 nht = rcu_dereference_bh(tbl->nht);
David S. Millercd089332011-07-11 01:28:12 -0700555 hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700556
557 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
558 n != NULL;
559 n = rcu_dereference_bh(n->next)) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800560 if (!memcmp(n->primary_key, pkey, key_len) &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900561 net_eq(dev_net(n->dev), net)) {
Reshetova, Elena9f237432017-06-30 13:07:55 +0300562 if (!refcount_inc_not_zero(&n->refcnt))
Eric Dumazet767e97e2010-10-06 17:49:21 -0700563 n = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 NEIGH_CACHE_STAT_INC(tbl, hits);
565 break;
566 }
567 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700568
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000569 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 return n;
571}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900572EXPORT_SYMBOL(neigh_lookup_nodev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573
David Ahern58956312018-12-07 12:24:57 -0800574static struct neighbour *___neigh_create(struct neigh_table *tbl,
575 const void *pkey,
576 struct net_device *dev,
David Aherne997f8a2018-12-11 18:57:25 -0700577 bool exempt_from_gc, bool want_ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578{
David Aherne997f8a2018-12-11 18:57:25 -0700579 struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev, exempt_from_gc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 u32 hash_val;
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300581 unsigned int key_len = tbl->key_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 int error;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000583 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584
David Ahernfc651002019-05-22 12:22:21 -0700585 trace_neigh_create(tbl, dev, pkey, n, exempt_from_gc);
586
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 if (!n) {
588 rc = ERR_PTR(-ENOBUFS);
589 goto out;
590 }
591
592 memcpy(n->primary_key, pkey, key_len);
593 n->dev = dev;
594 dev_hold(dev);
595
596 /* Protocol specific setup. */
597 if (tbl->constructor && (error = tbl->constructor(n)) < 0) {
598 rc = ERR_PTR(error);
599 goto out_neigh_release;
600 }
601
David Millerda6a8fa2011-07-25 00:01:38 +0000602 if (dev->netdev_ops->ndo_neigh_construct) {
Jiri Pirko503eebc2016-07-05 11:27:37 +0200603 error = dev->netdev_ops->ndo_neigh_construct(dev, n);
David Millerda6a8fa2011-07-25 00:01:38 +0000604 if (error < 0) {
605 rc = ERR_PTR(error);
606 goto out_neigh_release;
607 }
608 }
609
David S. Miller447f2192011-12-19 15:04:41 -0500610 /* Device specific setup. */
611 if (n->parms->neigh_setup &&
612 (error = n->parms->neigh_setup(n)) < 0) {
613 rc = ERR_PTR(error);
614 goto out_neigh_release;
615 }
616
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100617 n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
619 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000620 nht = rcu_dereference_protected(tbl->nht,
621 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
David S. Millercd089332011-07-11 01:28:12 -0700623 if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
624 nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
Jim Westfall096b9852018-01-14 04:18:50 -0800626 hash_val = tbl->hash(n->primary_key, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
628 if (n->parms->dead) {
629 rc = ERR_PTR(-EINVAL);
630 goto out_tbl_unlock;
631 }
632
Eric Dumazet767e97e2010-10-06 17:49:21 -0700633 for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
634 lockdep_is_held(&tbl->lock));
635 n1 != NULL;
636 n1 = rcu_dereference_protected(n1->next,
637 lockdep_is_held(&tbl->lock))) {
Jim Westfall096b9852018-01-14 04:18:50 -0800638 if (dev == n1->dev && !memcmp(n1->primary_key, n->primary_key, key_len)) {
David S. Millera263b302012-07-02 02:02:15 -0700639 if (want_ref)
640 neigh_hold(n1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 rc = n1;
642 goto out_tbl_unlock;
643 }
644 }
645
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 n->dead = 0;
David Aherne997f8a2018-12-11 18:57:25 -0700647 if (!exempt_from_gc)
David Ahern8cc196d2018-12-10 13:54:07 -0800648 list_add_tail(&n->gc_list, &n->tbl->gc_list);
649
David S. Millera263b302012-07-02 02:02:15 -0700650 if (want_ref)
651 neigh_hold(n);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700652 rcu_assign_pointer(n->next,
653 rcu_dereference_protected(nht->hash_buckets[hash_val],
654 lockdep_is_held(&tbl->lock)));
655 rcu_assign_pointer(nht->hash_buckets[hash_val], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 write_unlock_bh(&tbl->lock);
Joe Perchesd5d427c2013-04-15 15:17:19 +0000657 neigh_dbg(2, "neigh %p is created\n", n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 rc = n;
659out:
660 return rc;
661out_tbl_unlock:
662 write_unlock_bh(&tbl->lock);
663out_neigh_release:
David Ahern64c6f4b2019-05-01 18:08:34 -0700664 if (!exempt_from_gc)
665 atomic_dec(&tbl->gc_entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 neigh_release(n);
667 goto out;
668}
David Ahern58956312018-12-07 12:24:57 -0800669
670struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
671 struct net_device *dev, bool want_ref)
672{
673 return ___neigh_create(tbl, pkey, dev, false, want_ref);
674}
David S. Millera263b302012-07-02 02:02:15 -0700675EXPORT_SYMBOL(__neigh_create);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300677static u32 pneigh_hash(const void *pkey, unsigned int key_len)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700678{
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700679 u32 hash_val = *(u32 *)(pkey + key_len - 4);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700680 hash_val ^= (hash_val >> 16);
681 hash_val ^= hash_val >> 8;
682 hash_val ^= hash_val >> 4;
683 hash_val &= PNEIGH_HASHMASK;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900684 return hash_val;
685}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700686
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900687static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
688 struct net *net,
689 const void *pkey,
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300690 unsigned int key_len,
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900691 struct net_device *dev)
692{
693 while (n) {
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700694 if (!memcmp(n->key, pkey, key_len) &&
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900695 net_eq(pneigh_net(n), net) &&
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700696 (n->dev == dev || !n->dev))
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900697 return n;
698 n = n->next;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700699 }
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900700 return NULL;
701}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700702
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900703struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
704 struct net *net, const void *pkey, struct net_device *dev)
705{
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300706 unsigned int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900707 u32 hash_val = pneigh_hash(pkey, key_len);
708
709 return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
710 net, pkey, key_len, dev);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700711}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900712EXPORT_SYMBOL_GPL(__pneigh_lookup);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700713
Eric W. Biederman426b5302008-01-24 00:13:18 -0800714struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
715 struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 struct net_device *dev, int creat)
717{
718 struct pneigh_entry *n;
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300719 unsigned int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900720 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
722 read_lock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900723 n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
724 net, pkey, key_len, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 read_unlock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900726
727 if (n || !creat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 goto out;
729
Pavel Emelyanov4ae28942007-10-15 12:54:15 -0700730 ASSERT_RTNL();
731
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
733 if (!n)
734 goto out;
735
David Ahern754d5da2018-12-19 15:53:22 -0800736 n->protocol = 0;
Eric W. Biedermanefd7ef12015-03-11 23:04:08 -0500737 write_pnet(&n->net, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 memcpy(n->key, pkey, key_len);
739 n->dev = dev;
740 if (dev)
741 dev_hold(dev);
742
743 if (tbl->pconstructor && tbl->pconstructor(n)) {
744 if (dev)
745 dev_put(dev);
746 kfree(n);
747 n = NULL;
748 goto out;
749 }
750
751 write_lock_bh(&tbl->lock);
752 n->next = tbl->phash_buckets[hash_val];
753 tbl->phash_buckets[hash_val] = n;
754 write_unlock_bh(&tbl->lock);
755out:
756 return n;
757}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900758EXPORT_SYMBOL(pneigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
760
Eric W. Biederman426b5302008-01-24 00:13:18 -0800761int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 struct net_device *dev)
763{
764 struct pneigh_entry *n, **np;
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300765 unsigned int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900766 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
768 write_lock_bh(&tbl->lock);
769 for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
770 np = &n->next) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800771 if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900772 net_eq(pneigh_net(n), net)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 *np = n->next;
774 write_unlock_bh(&tbl->lock);
775 if (tbl->pdestructor)
776 tbl->pdestructor(n);
777 if (n->dev)
778 dev_put(n->dev);
779 kfree(n);
780 return 0;
781 }
782 }
783 write_unlock_bh(&tbl->lock);
784 return -ENOENT;
785}
786
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +0200787static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
788 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789{
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +0200790 struct pneigh_entry *n, **np, *freelist = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 u32 h;
792
793 for (h = 0; h <= PNEIGH_HASHMASK; h++) {
794 np = &tbl->phash_buckets[h];
795 while ((n = *np) != NULL) {
796 if (!dev || n->dev == dev) {
797 *np = n->next;
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +0200798 n->next = freelist;
799 freelist = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 continue;
801 }
802 np = &n->next;
803 }
804 }
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +0200805 write_unlock_bh(&tbl->lock);
806 while ((n = freelist)) {
807 freelist = n->next;
808 n->next = NULL;
809 if (tbl->pdestructor)
810 tbl->pdestructor(n);
811 if (n->dev)
812 dev_put(n->dev);
813 kfree(n);
814 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 return -ENOENT;
816}
817
Denis V. Lunev06f05112008-01-24 00:30:58 -0800818static void neigh_parms_destroy(struct neigh_parms *parms);
819
820static inline void neigh_parms_put(struct neigh_parms *parms)
821{
Reshetova, Elena63439442017-06-30 13:07:56 +0300822 if (refcount_dec_and_test(&parms->refcnt))
Denis V. Lunev06f05112008-01-24 00:30:58 -0800823 neigh_parms_destroy(parms);
824}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
826/*
827 * neighbour must already be out of the table;
828 *
829 */
830void neigh_destroy(struct neighbour *neigh)
831{
David Millerda6a8fa2011-07-25 00:01:38 +0000832 struct net_device *dev = neigh->dev;
833
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
835
836 if (!neigh->dead) {
Joe Perchese005d192012-05-16 19:58:40 +0000837 pr_warn("Destroying alive neighbour %p\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 dump_stack();
839 return;
840 }
841
842 if (neigh_del_timer(neigh))
Joe Perchese005d192012-05-16 19:58:40 +0000843 pr_warn("Impossible event\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700845 write_lock_bh(&neigh->lock);
846 __skb_queue_purge(&neigh->arp_queue);
847 write_unlock_bh(&neigh->lock);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000848 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
David S. Miller447f2192011-12-19 15:04:41 -0500850 if (dev->netdev_ops->ndo_neigh_destroy)
Jiri Pirko503eebc2016-07-05 11:27:37 +0200851 dev->netdev_ops->ndo_neigh_destroy(dev, neigh);
David S. Miller447f2192011-12-19 15:04:41 -0500852
David Millerda6a8fa2011-07-25 00:01:38 +0000853 dev_put(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 neigh_parms_put(neigh->parms);
855
Joe Perchesd5d427c2013-04-15 15:17:19 +0000856 neigh_dbg(2, "neigh %p is destroyed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857
858 atomic_dec(&neigh->tbl->entries);
David Miller5b8b0062011-07-25 00:01:22 +0000859 kfree_rcu(neigh, rcu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900861EXPORT_SYMBOL(neigh_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
863/* Neighbour state is suspicious;
864 disable fast path.
865
866 Called with write_locked neigh.
867 */
868static void neigh_suspect(struct neighbour *neigh)
869{
Joe Perchesd5d427c2013-04-15 15:17:19 +0000870 neigh_dbg(2, "neigh %p is suspected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
872 neigh->output = neigh->ops->output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873}
874
875/* Neighbour state is OK;
876 enable fast path.
877
878 Called with write_locked neigh.
879 */
880static void neigh_connect(struct neighbour *neigh)
881{
Joe Perchesd5d427c2013-04-15 15:17:19 +0000882 neigh_dbg(2, "neigh %p is connected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
884 neigh->output = neigh->ops->connected_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885}
886
Eric Dumazete4c4e442009-07-30 03:15:07 +0000887static void neigh_periodic_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888{
Eric Dumazete4c4e442009-07-30 03:15:07 +0000889 struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700890 struct neighbour *n;
891 struct neighbour __rcu **np;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000892 unsigned int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000893 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
895 NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
896
Eric Dumazete4c4e442009-07-30 03:15:07 +0000897 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000898 nht = rcu_dereference_protected(tbl->nht,
899 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
901 /*
902 * periodically recompute ReachableTime from random function
903 */
904
Eric Dumazete4c4e442009-07-30 03:15:07 +0000905 if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 struct neigh_parms *p;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000907 tbl->last_rand = jiffies;
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +0100908 list_for_each_entry(p, &tbl->parms_list, list)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 p->reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100910 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 }
912
Duan Jiongfeff9ab2014-02-27 17:14:41 +0800913 if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
914 goto out;
915
David S. Millercd089332011-07-11 01:28:12 -0700916 for (i = 0 ; i < (1 << nht->hash_shift); i++) {
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000917 np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
Eric Dumazet767e97e2010-10-06 17:49:21 -0700919 while ((n = rcu_dereference_protected(*np,
920 lockdep_is_held(&tbl->lock))) != NULL) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000921 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
Eric Dumazete4c4e442009-07-30 03:15:07 +0000923 write_lock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
Eric Dumazete4c4e442009-07-30 03:15:07 +0000925 state = n->nud_state;
Roopa Prabhu9ce33e42018-04-24 13:49:34 -0700926 if ((state & (NUD_PERMANENT | NUD_IN_TIMER)) ||
927 (n->flags & NTF_EXT_LEARNED)) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000928 write_unlock(&n->lock);
929 goto next_elt;
930 }
931
932 if (time_before(n->used, n->confirmed))
933 n->used = n->confirmed;
934
Reshetova, Elena9f237432017-06-30 13:07:55 +0300935 if (refcount_read(&n->refcnt) == 1 &&
Eric Dumazete4c4e442009-07-30 03:15:07 +0000936 (state == NUD_FAILED ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100937 time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000938 *np = n->next;
David Ahern58956312018-12-07 12:24:57 -0800939 neigh_mark_dead(n);
Eric Dumazete4c4e442009-07-30 03:15:07 +0000940 write_unlock(&n->lock);
941 neigh_cleanup_and_release(n);
942 continue;
943 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 write_unlock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946next_elt:
Eric Dumazete4c4e442009-07-30 03:15:07 +0000947 np = &n->next;
948 }
949 /*
950 * It's fine to release lock here, even if hash table
951 * grows while we are preempted.
952 */
953 write_unlock_bh(&tbl->lock);
954 cond_resched();
955 write_lock_bh(&tbl->lock);
Michel Machado84338a62012-02-21 16:04:13 -0500956 nht = rcu_dereference_protected(tbl->nht,
957 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 }
YOSHIFUJI Hideaki / 吉藤英明27246802013-01-22 05:20:05 +0000959out:
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100960 /* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks.
961 * ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2
962 * BASE_REACHABLE_TIME.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 */
viresh kumarf6180022014-01-22 12:23:33 +0530964 queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100965 NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1);
Eric Dumazete4c4e442009-07-30 03:15:07 +0000966 write_unlock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967}
968
969static __inline__ int neigh_max_probes(struct neighbour *n)
970{
971 struct neigh_parms *p = n->parms;
YOSHIFUJI Hideaki/吉藤英明8da86462015-03-19 22:41:46 +0900972 return NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) +
973 (n->nud_state & NUD_PROBE ? NEIGH_VAR(p, MCAST_REPROBES) :
974 NEIGH_VAR(p, MCAST_PROBES));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975}
976
Timo Teras5ef12d92009-06-11 04:16:28 -0700977static void neigh_invalidate(struct neighbour *neigh)
Eric Dumazet0a141502010-03-09 19:40:54 +0000978 __releases(neigh->lock)
979 __acquires(neigh->lock)
Timo Teras5ef12d92009-06-11 04:16:28 -0700980{
981 struct sk_buff *skb;
982
983 NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
Joe Perchesd5d427c2013-04-15 15:17:19 +0000984 neigh_dbg(2, "neigh %p is failed\n", neigh);
Timo Teras5ef12d92009-06-11 04:16:28 -0700985 neigh->updated = jiffies;
986
987 /* It is very thin place. report_unreachable is very complicated
988 routine. Particularly, it can hit the same neighbour entry!
989
990 So that, we try to be accurate and avoid dead loop. --ANK
991 */
992 while (neigh->nud_state == NUD_FAILED &&
993 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
994 write_unlock(&neigh->lock);
995 neigh->ops->error_report(neigh, skb);
996 write_lock(&neigh->lock);
997 }
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700998 __skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000999 neigh->arp_queue_len_bytes = 0;
Timo Teras5ef12d92009-06-11 04:16:28 -07001000}
1001
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001002static void neigh_probe(struct neighbour *neigh)
1003 __releases(neigh->lock)
1004{
Hannes Frederic Sowa4ed377e2013-09-21 06:32:34 +02001005 struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001006 /* keep skb alive even if arp_queue overflows */
1007 if (skb)
Martin Zhang19125c12015-11-17 20:49:30 +08001008 skb = skb_clone(skb, GFP_ATOMIC);
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001009 write_unlock(&neigh->lock);
Eric Dumazet48481c82017-03-23 12:39:21 -07001010 if (neigh->ops->solicit)
1011 neigh->ops->solicit(neigh, skb);
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001012 atomic_inc(&neigh->probes);
Yang Wei87fff3ca2019-01-17 23:11:30 +08001013 consume_skb(skb);
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001014}
1015
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016/* Called when a timer expires for a neighbour entry. */
1017
Kees Cooke99e88a2017-10-16 14:43:17 -07001018static void neigh_timer_handler(struct timer_list *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019{
1020 unsigned long now, next;
Kees Cooke99e88a2017-10-16 14:43:17 -07001021 struct neighbour *neigh = from_timer(neigh, t, timer);
Eric Dumazet95c96172012-04-15 05:58:06 +00001022 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 int notify = 0;
1024
1025 write_lock(&neigh->lock);
1026
1027 state = neigh->nud_state;
1028 now = jiffies;
1029 next = now + HZ;
1030
David S. Miller045f7b32011-11-01 17:45:55 -04001031 if (!(state & NUD_IN_TIMER))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034 if (state & NUD_REACHABLE) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001035 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 neigh->confirmed + neigh->parms->reachable_time)) {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001037 neigh_dbg(2, "neigh %p is still alive\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 next = neigh->confirmed + neigh->parms->reachable_time;
1039 } else if (time_before_eq(now,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001040 neigh->used +
1041 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001042 neigh_dbg(2, "neigh %p is delayed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001044 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 neigh_suspect(neigh);
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001046 next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 } else {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001048 neigh_dbg(2, "neigh %p is suspected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 neigh->nud_state = NUD_STALE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001050 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 neigh_suspect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -07001052 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 }
1054 } else if (state & NUD_DELAY) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001055 if (time_before_eq(now,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001056 neigh->confirmed +
1057 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001058 neigh_dbg(2, "neigh %p is now reachable\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 neigh->nud_state = NUD_REACHABLE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001060 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 neigh_connect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -07001062 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 next = neigh->confirmed + neigh->parms->reachable_time;
1064 } else {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001065 neigh_dbg(2, "neigh %p is probed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 neigh->nud_state = NUD_PROBE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001067 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 atomic_set(&neigh->probes, 0);
Erik Kline765c9c62015-05-18 19:44:41 +09001069 notify = 1;
Hangbin Liu19e16d22020-04-01 14:46:20 +08001070 next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
1071 HZ/100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 }
1073 } else {
1074 /* NUD_PROBE|NUD_INCOMPLETE */
Hangbin Liu19e16d22020-04-01 14:46:20 +08001075 next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME), HZ/100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 }
1077
1078 if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
1079 atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 neigh->nud_state = NUD_FAILED;
1081 notify = 1;
Timo Teras5ef12d92009-06-11 04:16:28 -07001082 neigh_invalidate(neigh);
Duan Jiong5e2c21d2014-02-27 17:03:03 +08001083 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 }
1085
1086 if (neigh->nud_state & NUD_IN_TIMER) {
Hangbin Liu96d10d52020-05-28 15:15:13 +08001087 if (time_before(next, jiffies + HZ/100))
1088 next = jiffies + HZ/100;
Herbert Xu6fb99742005-10-23 16:37:48 +10001089 if (!mod_timer(&neigh->timer, next))
1090 neigh_hold(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 }
1092 if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001093 neigh_probe(neigh);
David S. Miller9ff56602008-02-17 18:39:54 -08001094 } else {
David S. Miller69cc64d2008-02-11 21:45:44 -08001095out:
David S. Miller9ff56602008-02-17 18:39:54 -08001096 write_unlock(&neigh->lock);
1097 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
Thomas Grafd961db32007-08-08 23:12:56 -07001099 if (notify)
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07001100 neigh_update_notify(neigh, 0);
Thomas Grafd961db32007-08-08 23:12:56 -07001101
Roopa Prabhu56dd18a2019-02-14 09:15:11 -08001102 trace_neigh_timer_handler(neigh, 0);
1103
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 neigh_release(neigh);
1105}
1106
1107int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
1108{
1109 int rc;
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001110 bool immediate_probe = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
1112 write_lock_bh(&neigh->lock);
1113
1114 rc = 0;
1115 if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
1116 goto out_unlock_bh;
Julian Anastasov2c51a972015-06-16 22:56:39 +03001117 if (neigh->dead)
1118 goto out_dead;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001121 if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
1122 NEIGH_VAR(neigh->parms, APP_PROBES)) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001123 unsigned long next, now = jiffies;
1124
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001125 atomic_set(&neigh->probes,
1126 NEIGH_VAR(neigh->parms, UCAST_PROBES));
Lorenzo Bianconi071c3792019-07-14 23:36:11 +02001127 neigh_del_timer(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 neigh->nud_state = NUD_INCOMPLETE;
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001129 neigh->updated = now;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001130 next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
Hangbin Liu19e16d22020-04-01 14:46:20 +08001131 HZ/100);
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001132 neigh_add_timer(neigh, next);
1133 immediate_probe = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 } else {
1135 neigh->nud_state = NUD_FAILED;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001136 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 write_unlock_bh(&neigh->lock);
1138
Wei Yongjunf3fbbe02009-02-25 00:37:32 +00001139 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 return 1;
1141 }
1142 } else if (neigh->nud_state & NUD_STALE) {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001143 neigh_dbg(2, "neigh %p is delayed\n", neigh);
Lorenzo Bianconi071c3792019-07-14 23:36:11 +02001144 neigh_del_timer(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001146 neigh->updated = jiffies;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001147 neigh_add_timer(neigh, jiffies +
1148 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 }
1150
1151 if (neigh->nud_state == NUD_INCOMPLETE) {
1152 if (skb) {
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001153 while (neigh->arp_queue_len_bytes + skb->truesize >
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001154 NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 struct sk_buff *buff;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001156
David S. Millerf72051b2008-09-23 01:11:18 -07001157 buff = __skb_dequeue(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001158 if (!buff)
1159 break;
1160 neigh->arp_queue_len_bytes -= buff->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 kfree_skb(buff);
Neil Horman9a6d2762008-07-16 20:50:49 -07001162 NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 }
Eric Dumazeta4731132010-05-27 16:09:39 -07001164 skb_dst_force(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 __skb_queue_tail(&neigh->arp_queue, skb);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001166 neigh->arp_queue_len_bytes += skb->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 }
1168 rc = 1;
1169 }
1170out_unlock_bh:
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001171 if (immediate_probe)
1172 neigh_probe(neigh);
1173 else
1174 write_unlock(&neigh->lock);
1175 local_bh_enable();
Roopa Prabhu56dd18a2019-02-14 09:15:11 -08001176 trace_neigh_event_send_done(neigh, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 return rc;
Julian Anastasov2c51a972015-06-16 22:56:39 +03001178
1179out_dead:
1180 if (neigh->nud_state & NUD_STALE)
1181 goto out_unlock_bh;
1182 write_unlock_bh(&neigh->lock);
1183 kfree_skb(skb);
Roopa Prabhu56dd18a2019-02-14 09:15:11 -08001184 trace_neigh_event_send_dead(neigh, 1);
Julian Anastasov2c51a972015-06-16 22:56:39 +03001185 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001187EXPORT_SYMBOL(__neigh_event_send);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188
David S. Millerf6b72b622011-07-14 07:53:20 -07001189static void neigh_update_hhs(struct neighbour *neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190{
1191 struct hh_cache *hh;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001192 void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
Doug Kehn91a72a72010-07-14 18:02:16 -07001193 = NULL;
1194
1195 if (neigh->dev->header_ops)
1196 update = neigh->dev->header_ops->cache_update;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197
1198 if (update) {
David S. Millerf6b72b622011-07-14 07:53:20 -07001199 hh = &neigh->hh;
Eric Dumazetc305c6ae2019-11-07 18:29:11 -08001200 if (READ_ONCE(hh->hh_len)) {
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001201 write_seqlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 update(hh, neigh->dev, neigh->ha);
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001203 write_sequnlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 }
1205 }
1206}
1207
1208
1209
1210/* Generic update routine.
1211 -- lladdr is new lladdr or NULL, if it is not supplied.
1212 -- new is new state.
1213 -- flags
1214 NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
1215 if it is different.
1216 NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001217 lladdr instead of overriding it
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 if it is different.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 NEIGH_UPDATE_F_ADMIN means that the change is administrative.
1220
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001221 NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 NTF_ROUTER flag.
1223 NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
1224 a router.
1225
1226 Caller MUST hold reference count on the entry.
1227 */
1228
David Ahern7a35a502018-12-05 20:02:29 -08001229static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
1230 u8 new, u32 flags, u32 nlmsg_pid,
1231 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232{
David Aherne997f8a2018-12-11 18:57:25 -07001233 bool ext_learn_change = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 u8 old;
1235 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 int notify = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 struct net_device *dev;
1238 int update_isrouter = 0;
1239
Roopa Prabhu56dd18a2019-02-14 09:15:11 -08001240 trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid);
1241
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 write_lock_bh(&neigh->lock);
1243
1244 dev = neigh->dev;
1245 old = neigh->nud_state;
1246 err = -EPERM;
1247
Chinmay Agarwaleb4e8fa2021-01-27 22:24:54 +05301248 if (neigh->dead) {
1249 NL_SET_ERR_MSG(extack, "Neighbor entry is now dead");
1250 new = old;
1251 goto out;
1252 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001253 if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 (old & (NUD_NOARP | NUD_PERMANENT)))
1255 goto out;
1256
David Aherne997f8a2018-12-11 18:57:25 -07001257 ext_learn_change = neigh_update_ext_learned(neigh, flags, &notify);
Roopa Prabhu9ce33e42018-04-24 13:49:34 -07001258
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 if (!(new & NUD_VALID)) {
1260 neigh_del_timer(neigh);
1261 if (old & NUD_CONNECTED)
1262 neigh_suspect(neigh);
David Ahern9c29a2f2018-12-11 18:57:21 -07001263 neigh->nud_state = new;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 notify = old & NUD_VALID;
Roopa Prabhud2fb4fb2018-10-20 18:09:31 -07001266 if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
Timo Teras5ef12d92009-06-11 04:16:28 -07001267 (new & NUD_FAILED)) {
1268 neigh_invalidate(neigh);
1269 notify = 1;
1270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 goto out;
1272 }
1273
1274 /* Compare new lladdr with cached one */
1275 if (!dev->addr_len) {
1276 /* First case: device needs no address. */
1277 lladdr = neigh->ha;
1278 } else if (lladdr) {
1279 /* The second case: if something is already cached
1280 and a new address is proposed:
1281 - compare new & old
1282 - if they are different, check override flag
1283 */
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001284 if ((old & NUD_VALID) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 !memcmp(lladdr, neigh->ha, dev->addr_len))
1286 lladdr = neigh->ha;
1287 } else {
1288 /* No address is supplied; if we know something,
1289 use it, otherwise discard the request.
1290 */
1291 err = -EINVAL;
David Ahern7a35a502018-12-05 20:02:29 -08001292 if (!(old & NUD_VALID)) {
1293 NL_SET_ERR_MSG(extack, "No link layer address given");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001295 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 lladdr = neigh->ha;
1297 }
1298
Vasily Khoruzhickf0e0d042018-09-13 11:12:03 -07001299 /* Update confirmed timestamp for neighbour entry after we
1300 * received ARP packet even if it doesn't change IP to MAC binding.
1301 */
1302 if (new & NUD_CONNECTED)
1303 neigh->confirmed = jiffies;
1304
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 /* If entry was valid and address is not changed,
1306 do not change entry state, if new one is STALE.
1307 */
1308 err = 0;
1309 update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
1310 if (old & NUD_VALID) {
1311 if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
1312 update_isrouter = 0;
1313 if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
1314 (old & NUD_CONNECTED)) {
1315 lladdr = neigh->ha;
1316 new = NUD_STALE;
1317 } else
1318 goto out;
1319 } else {
Julian Anastasov0e7bbcc2016-07-27 09:56:50 +03001320 if (lladdr == neigh->ha && new == NUD_STALE &&
1321 !(flags & NEIGH_UPDATE_F_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 new = old;
1323 }
1324 }
1325
Vasily Khoruzhickf0e0d042018-09-13 11:12:03 -07001326 /* Update timestamp only once we know we will make a change to the
Ihar Hrachyshka77d71232017-05-16 08:44:24 -07001327 * neighbour entry. Otherwise we risk to move the locktime window with
1328 * noop updates and ignore relevant ARP updates.
1329 */
Vasily Khoruzhickf0e0d042018-09-13 11:12:03 -07001330 if (new != old || lladdr != neigh->ha)
Ihar Hrachyshka77d71232017-05-16 08:44:24 -07001331 neigh->updated = jiffies;
Ihar Hrachyshka77d71232017-05-16 08:44:24 -07001332
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 if (new != old) {
1334 neigh_del_timer(neigh);
Erik Kline765c9c62015-05-18 19:44:41 +09001335 if (new & NUD_PROBE)
1336 atomic_set(&neigh->probes, 0);
Pavel Emelyanova43d8992007-12-20 15:49:05 -08001337 if (new & NUD_IN_TIMER)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001338 neigh_add_timer(neigh, (jiffies +
1339 ((new & NUD_REACHABLE) ?
David S. Miller667347f2005-09-27 12:07:44 -07001340 neigh->parms->reachable_time :
1341 0)));
David Ahern9c29a2f2018-12-11 18:57:21 -07001342 neigh->nud_state = new;
Bob Gilligan53385d22013-12-15 13:39:56 -08001343 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 }
1345
1346 if (lladdr != neigh->ha) {
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001347 write_seqlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 memcpy(&neigh->ha, lladdr, dev->addr_len);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001349 write_sequnlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 neigh_update_hhs(neigh);
1351 if (!(new & NUD_CONNECTED))
1352 neigh->confirmed = jiffies -
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001353 (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 }
1356 if (new == old)
1357 goto out;
1358 if (new & NUD_CONNECTED)
1359 neigh_connect(neigh);
1360 else
1361 neigh_suspect(neigh);
1362 if (!(old & NUD_VALID)) {
1363 struct sk_buff *skb;
1364
1365 /* Again: avoid dead loop if something went wrong */
1366
1367 while (neigh->nud_state & NUD_VALID &&
1368 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
David S. Miller69cce1d2011-07-17 23:09:49 -07001369 struct dst_entry *dst = skb_dst(skb);
1370 struct neighbour *n2, *n1 = neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 write_unlock_bh(&neigh->lock);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001372
1373 rcu_read_lock();
David S. Miller13a43d92012-07-02 22:15:37 -07001374
1375 /* Why not just use 'neigh' as-is? The problem is that
1376 * things such as shaper, eql, and sch_teql can end up
1377 * using alternative, different, neigh objects to output
1378 * the packet in the output path. So what we need to do
1379 * here is re-lookup the top-level neigh in the path so
1380 * we can reinject the packet there.
1381 */
1382 n2 = NULL;
1383 if (dst) {
1384 n2 = dst_neigh_lookup_skb(dst, skb);
1385 if (n2)
1386 n1 = n2;
1387 }
David S. Miller8f40b162011-07-17 13:34:11 -07001388 n1->output(n1, skb);
David S. Miller13a43d92012-07-02 22:15:37 -07001389 if (n2)
1390 neigh_release(n2);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001391 rcu_read_unlock();
1392
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 write_lock_bh(&neigh->lock);
1394 }
Eric Dumazetc9ab4d82013-06-28 02:37:42 -07001395 __skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001396 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 }
1398out:
Roopa Prabhufc6e8072018-09-22 21:26:20 -07001399 if (update_isrouter)
1400 neigh_update_is_router(neigh, flags, &notify);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 write_unlock_bh(&neigh->lock);
Tom Tucker8d717402006-07-30 20:43:36 -07001402
David Aherne997f8a2018-12-11 18:57:25 -07001403 if (((new ^ old) & NUD_PERMANENT) || ext_learn_change)
David Ahern9c29a2f2018-12-11 18:57:21 -07001404 neigh_update_gc_list(neigh);
1405
Tom Tucker8d717402006-07-30 20:43:36 -07001406 if (notify)
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07001407 neigh_update_notify(neigh, nlmsg_pid);
Thomas Grafd961db32007-08-08 23:12:56 -07001408
Roopa Prabhu56dd18a2019-02-14 09:15:11 -08001409 trace_neigh_update_done(neigh, err);
1410
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 return err;
1412}
David Ahern7a35a502018-12-05 20:02:29 -08001413
1414int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
1415 u32 flags, u32 nlmsg_pid)
1416{
1417 return __neigh_update(neigh, lladdr, new, flags, nlmsg_pid, NULL);
1418}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001419EXPORT_SYMBOL(neigh_update);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420
Jiri Benc7e980562013-12-11 13:48:20 +01001421/* Update the neigh to listen temporarily for probe responses, even if it is
1422 * in a NUD_FAILED state. The caller has to hold neigh->lock for writing.
1423 */
1424void __neigh_set_probe_once(struct neighbour *neigh)
1425{
Julian Anastasov2c51a972015-06-16 22:56:39 +03001426 if (neigh->dead)
1427 return;
Jiri Benc7e980562013-12-11 13:48:20 +01001428 neigh->updated = jiffies;
1429 if (!(neigh->nud_state & NUD_FAILED))
1430 return;
Duan Jiong2176d5d2014-05-09 13:16:48 +08001431 neigh->nud_state = NUD_INCOMPLETE;
1432 atomic_set(&neigh->probes, neigh_max_probes(neigh));
Jiri Benc7e980562013-12-11 13:48:20 +01001433 neigh_add_timer(neigh,
Hangbin Liu19e16d22020-04-01 14:46:20 +08001434 jiffies + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
1435 HZ/100));
Jiri Benc7e980562013-12-11 13:48:20 +01001436}
1437EXPORT_SYMBOL(__neigh_set_probe_once);
1438
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439struct neighbour *neigh_event_ns(struct neigh_table *tbl,
1440 u8 *lladdr, void *saddr,
1441 struct net_device *dev)
1442{
1443 struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
1444 lladdr || !dev->addr_len);
1445 if (neigh)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001446 neigh_update(neigh, lladdr, NUD_STALE,
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07001447 NEIGH_UPDATE_F_OVERRIDE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 return neigh;
1449}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001450EXPORT_SYMBOL(neigh_event_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451
Eric Dumazet34d101d2010-10-11 09:16:57 -07001452/* called with read_lock_bh(&n->lock); */
Eric W. Biedermanbdf53c52015-03-02 00:13:22 -06001453static void neigh_hh_init(struct neighbour *n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454{
Eric W. Biedermanbdf53c52015-03-02 00:13:22 -06001455 struct net_device *dev = n->dev;
1456 __be16 prot = n->tbl->protocol;
David S. Millerf6b72b622011-07-14 07:53:20 -07001457 struct hh_cache *hh = &n->hh;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001458
1459 write_lock_bh(&n->lock);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001460
David S. Millerf6b72b622011-07-14 07:53:20 -07001461 /* Only one thread can come in here and initialize the
1462 * hh_cache entry.
1463 */
David S. Millerb23b5452011-07-16 17:45:02 -07001464 if (!hh->hh_len)
1465 dev->header_ops->cache(n, hh, prot);
David S. Millerf6b72b622011-07-14 07:53:20 -07001466
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001467 write_unlock_bh(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468}
1469
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470/* Slow and careful. */
1471
David S. Miller8f40b162011-07-17 13:34:11 -07001472int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 int rc = 0;
1475
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 if (!neigh_event_send(neigh, skb)) {
1477 int err;
1478 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001479 unsigned int seq;
Eric Dumazet34d101d2010-10-11 09:16:57 -07001480
Eric Dumazetc305c6ae2019-11-07 18:29:11 -08001481 if (dev->header_ops->cache && !READ_ONCE(neigh->hh.hh_len))
Eric W. Biedermanbdf53c52015-03-02 00:13:22 -06001482 neigh_hh_init(neigh);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001483
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001484 do {
ramesh.nagappa@gmail.come1f16502012-10-05 19:10:15 +00001485 __skb_pull(skb, skb_network_offset(skb));
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001486 seq = read_seqbegin(&neigh->ha_lock);
1487 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1488 neigh->ha, NULL, skb->len);
1489 } while (read_seqretry(&neigh->ha_lock, seq));
Eric Dumazet34d101d2010-10-11 09:16:57 -07001490
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001492 rc = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 else
1494 goto out_kfree_skb;
1495 }
1496out:
1497 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498out_kfree_skb:
1499 rc = -EINVAL;
1500 kfree_skb(skb);
1501 goto out;
1502}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001503EXPORT_SYMBOL(neigh_resolve_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504
1505/* As fast as possible without hh cache */
1506
David S. Miller8f40b162011-07-17 13:34:11 -07001507int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001510 unsigned int seq;
David S. Miller8f40b162011-07-17 13:34:11 -07001511 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001513 do {
ramesh.nagappa@gmail.come1f16502012-10-05 19:10:15 +00001514 __skb_pull(skb, skb_network_offset(skb));
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001515 seq = read_seqbegin(&neigh->ha_lock);
1516 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1517 neigh->ha, NULL, skb->len);
1518 } while (read_seqretry(&neigh->ha_lock, seq));
1519
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001521 err = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 else {
1523 err = -EINVAL;
1524 kfree_skb(skb);
1525 }
1526 return err;
1527}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001528EXPORT_SYMBOL(neigh_connected_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
David S. Miller8f40b162011-07-17 13:34:11 -07001530int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
1531{
1532 return dev_queue_xmit(skb);
1533}
1534EXPORT_SYMBOL(neigh_direct_output);
1535
Kees Cooke99e88a2017-10-16 14:43:17 -07001536static void neigh_proxy_process(struct timer_list *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537{
Kees Cooke99e88a2017-10-16 14:43:17 -07001538 struct neigh_table *tbl = from_timer(tbl, t, proxy_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 long sched_next = 0;
1540 unsigned long now = jiffies;
David S. Millerf72051b2008-09-23 01:11:18 -07001541 struct sk_buff *skb, *n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542
1543 spin_lock(&tbl->proxy_queue.lock);
1544
David S. Millerf72051b2008-09-23 01:11:18 -07001545 skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1546 long tdif = NEIGH_CB(skb)->sched_next - now;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 if (tdif <= 0) {
David S. Millerf72051b2008-09-23 01:11:18 -07001549 struct net_device *dev = skb->dev;
Eric Dumazet20e60742011-08-22 19:32:42 +00001550
David S. Millerf72051b2008-09-23 01:11:18 -07001551 __skb_unlink(skb, &tbl->proxy_queue);
Eric Dumazet20e60742011-08-22 19:32:42 +00001552 if (tbl->proxy_redo && netif_running(dev)) {
1553 rcu_read_lock();
David S. Millerf72051b2008-09-23 01:11:18 -07001554 tbl->proxy_redo(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001555 rcu_read_unlock();
1556 } else {
David S. Millerf72051b2008-09-23 01:11:18 -07001557 kfree_skb(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001558 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
1560 dev_put(dev);
1561 } else if (!sched_next || tdif < sched_next)
1562 sched_next = tdif;
1563 }
1564 del_timer(&tbl->proxy_timer);
1565 if (sched_next)
1566 mod_timer(&tbl->proxy_timer, jiffies + sched_next);
1567 spin_unlock(&tbl->proxy_queue.lock);
1568}
1569
1570void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
1571 struct sk_buff *skb)
1572{
weichenchena533b702020-12-25 13:44:45 +08001573 unsigned long sched_next = jiffies +
1574 prandom_u32_max(NEIGH_VAR(p, PROXY_DELAY));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001576 if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 kfree_skb(skb);
1578 return;
1579 }
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001580
1581 NEIGH_CB(skb)->sched_next = sched_next;
1582 NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
1584 spin_lock(&tbl->proxy_queue.lock);
1585 if (del_timer(&tbl->proxy_timer)) {
1586 if (time_before(tbl->proxy_timer.expires, sched_next))
1587 sched_next = tbl->proxy_timer.expires;
1588 }
Eric Dumazetadf30902009-06-02 05:19:30 +00001589 skb_dst_drop(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 dev_hold(skb->dev);
1591 __skb_queue_tail(&tbl->proxy_queue, skb);
1592 mod_timer(&tbl->proxy_timer, sched_next);
1593 spin_unlock(&tbl->proxy_queue.lock);
1594}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001595EXPORT_SYMBOL(pneigh_enqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001597static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
Eric W. Biederman426b5302008-01-24 00:13:18 -08001598 struct net *net, int ifindex)
1599{
1600 struct neigh_parms *p;
1601
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001602 list_for_each_entry(p, &tbl->parms_list, list) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09001603 if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
Gao feng170d6f92013-06-20 10:01:33 +08001604 (!p->dev && !ifindex && net_eq(net, &init_net)))
Eric W. Biederman426b5302008-01-24 00:13:18 -08001605 return p;
1606 }
1607
1608 return NULL;
1609}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610
1611struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
1612 struct neigh_table *tbl)
1613{
Gao fengcf89d6b2013-06-20 10:01:32 +08001614 struct neigh_parms *p;
Stephen Hemminger00829822008-11-20 20:14:53 -08001615 struct net *net = dev_net(dev);
1616 const struct net_device_ops *ops = dev->netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617
Gao fengcf89d6b2013-06-20 10:01:32 +08001618 p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 if (p) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 p->tbl = tbl;
Reshetova, Elena63439442017-06-30 13:07:56 +03001621 refcount_set(&p->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 p->reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001623 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001624 dev_hold(dev);
1625 p->dev = dev;
Eric W. Biedermanefd7ef12015-03-11 23:04:08 -05001626 write_pnet(&p->net, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 p->sysctl_table = NULL;
Veaceslav Falico63134802013-08-02 19:07:38 +02001628
1629 if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
Veaceslav Falico63134802013-08-02 19:07:38 +02001630 dev_put(dev);
1631 kfree(p);
1632 return NULL;
1633 }
1634
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 write_lock_bh(&tbl->lock);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001636 list_add(&p->list, &tbl->parms.list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 write_unlock_bh(&tbl->lock);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01001638
1639 neigh_parms_data_state_cleanall(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 }
1641 return p;
1642}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001643EXPORT_SYMBOL(neigh_parms_alloc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644
1645static void neigh_rcu_free_parms(struct rcu_head *head)
1646{
1647 struct neigh_parms *parms =
1648 container_of(head, struct neigh_parms, rcu_head);
1649
1650 neigh_parms_put(parms);
1651}
1652
1653void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
1654{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 if (!parms || parms == &tbl->parms)
1656 return;
1657 write_lock_bh(&tbl->lock);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001658 list_del(&parms->list);
1659 parms->dead = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 write_unlock_bh(&tbl->lock);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001661 if (parms->dev)
1662 dev_put(parms->dev);
1663 call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001665EXPORT_SYMBOL(neigh_parms_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666
Denis V. Lunev06f05112008-01-24 00:30:58 -08001667static void neigh_parms_destroy(struct neigh_parms *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668{
1669 kfree(parms);
1670}
1671
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001672static struct lock_class_key neigh_table_proxy_queue_class;
1673
WANG Congd7480fd2014-11-10 15:59:36 -08001674static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly;
1675
1676void neigh_table_init(int index, struct neigh_table *tbl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677{
1678 unsigned long now = jiffies;
1679 unsigned long phsize;
1680
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001681 INIT_LIST_HEAD(&tbl->parms_list);
David Ahern58956312018-12-07 12:24:57 -08001682 INIT_LIST_HEAD(&tbl->gc_list);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001683 list_add(&tbl->parms.list, &tbl->parms_list);
Eric Dumazete42ea982008-11-12 00:54:54 -08001684 write_pnet(&tbl->parms.net, &init_net);
Reshetova, Elena63439442017-06-30 13:07:56 +03001685 refcount_set(&tbl->parms.refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 tbl->parms.reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001687 neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 tbl->stats = alloc_percpu(struct neigh_statistics);
1690 if (!tbl->stats)
1691 panic("cannot create neighbour cache statistics");
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001692
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693#ifdef CONFIG_PROC_FS
Christoph Hellwig71a50532018-04-15 10:16:41 +02001694 if (!proc_create_seq_data(tbl->id, 0, init_net.proc_net_stat,
1695 &neigh_stat_seq_ops, tbl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 panic("cannot create neighbour proc dir entry");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697#endif
1698
David S. Millercd089332011-07-11 01:28:12 -07001699 RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700
1701 phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
Andrew Morton77d04bd2006-04-07 14:52:59 -07001702 tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001704 if (!tbl->nht || !tbl->phash_buckets)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 panic("cannot allocate neighbour cache hashes");
1706
YOSHIFUJI Hideaki / 吉藤英明08433ef2013-01-24 00:44:23 +00001707 if (!tbl->entry_size)
1708 tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
1709 tbl->key_len, NEIGH_PRIV_ALIGN);
1710 else
1711 WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
1712
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 rwlock_init(&tbl->lock);
Tejun Heo203b42f2012-08-21 13:18:23 -07001714 INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
viresh kumarf6180022014-01-22 12:23:33 +05301715 queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
1716 tbl->parms.reachable_time);
Kees Cooke99e88a2017-10-16 14:43:17 -07001717 timer_setup(&tbl->proxy_timer, neigh_proxy_process, 0);
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001718 skb_queue_head_init_class(&tbl->proxy_queue,
1719 &neigh_table_proxy_queue_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720
1721 tbl->last_flush = now;
1722 tbl->last_rand = now + tbl->parms.reachable_time * 20;
Simon Kelleybd89efc2006-05-12 14:56:08 -07001723
WANG Congd7480fd2014-11-10 15:59:36 -08001724 neigh_tables[index] = tbl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001726EXPORT_SYMBOL(neigh_table_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727
WANG Congd7480fd2014-11-10 15:59:36 -08001728int neigh_table_clear(int index, struct neigh_table *tbl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729{
WANG Congd7480fd2014-11-10 15:59:36 -08001730 neigh_tables[index] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 /* It is not clean... Fix it to unload IPv6 module safely */
Tejun Heoa5c30b32010-10-19 06:04:42 +00001732 cancel_delayed_work_sync(&tbl->gc_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 del_timer_sync(&tbl->proxy_timer);
1734 pneigh_queue_purge(&tbl->proxy_queue);
1735 neigh_ifdown(tbl, NULL);
1736 if (atomic_read(&tbl->entries))
Joe Perchese005d192012-05-16 19:58:40 +00001737 pr_crit("neighbour leakage\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738
Eric Dumazet6193d2b2011-01-19 22:02:47 +00001739 call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
1740 neigh_hash_free_rcu);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001741 tbl->nht = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742
1743 kfree(tbl->phash_buckets);
1744 tbl->phash_buckets = NULL;
1745
Alexey Dobriyan3f192b52007-11-05 21:28:13 -08001746 remove_proc_entry(tbl->id, init_net.proc_net_stat);
1747
Kirill Korotaev3fcde742006-09-01 01:34:10 -07001748 free_percpu(tbl->stats);
1749 tbl->stats = NULL;
1750
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 return 0;
1752}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001753EXPORT_SYMBOL(neigh_table_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754
WANG Congd7480fd2014-11-10 15:59:36 -08001755static struct neigh_table *neigh_find_table(int family)
1756{
1757 struct neigh_table *tbl = NULL;
1758
1759 switch (family) {
1760 case AF_INET:
1761 tbl = neigh_tables[NEIGH_ARP_TABLE];
1762 break;
1763 case AF_INET6:
1764 tbl = neigh_tables[NEIGH_ND_TABLE];
1765 break;
1766 case AF_DECnet:
1767 tbl = neigh_tables[NEIGH_DN_TABLE];
1768 break;
1769 }
1770
1771 return tbl;
1772}
1773
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08001774const struct nla_policy nda_policy[NDA_MAX+1] = {
Roopa Prabhu1274e1c2020-05-21 22:26:14 -07001775 [NDA_UNSPEC] = { .strict_start_type = NDA_NH_ID },
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08001776 [NDA_DST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
1777 [NDA_LLADDR] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
1778 [NDA_CACHEINFO] = { .len = sizeof(struct nda_cacheinfo) },
1779 [NDA_PROBES] = { .type = NLA_U32 },
1780 [NDA_VLAN] = { .type = NLA_U16 },
1781 [NDA_PORT] = { .type = NLA_U16 },
1782 [NDA_VNI] = { .type = NLA_U32 },
1783 [NDA_IFINDEX] = { .type = NLA_U32 },
1784 [NDA_MASTER] = { .type = NLA_U32 },
David Aherna9cd3432018-12-19 20:02:36 -08001785 [NDA_PROTOCOL] = { .type = NLA_U8 },
Roopa Prabhu1274e1c2020-05-21 22:26:14 -07001786 [NDA_NH_ID] = { .type = NLA_U32 },
Nikolay Aleksandrov899426b2020-06-23 23:47:16 +03001787 [NDA_FDB_EXT_ATTRS] = { .type = NLA_NESTED },
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08001788};
1789
David Ahernc21ef3e2017-04-16 09:48:24 -07001790static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
1791 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001793 struct net *net = sock_net(skb->sk);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001794 struct ndmsg *ndm;
1795 struct nlattr *dst_attr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 struct neigh_table *tbl;
WANG Congd7480fd2014-11-10 15:59:36 -08001797 struct neighbour *neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 struct net_device *dev = NULL;
Thomas Grafa14a49d2006-08-07 17:53:08 -07001799 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
Eric Dumazet110b2492010-10-04 04:27:36 +00001801 ASSERT_RTNL();
Thomas Grafa14a49d2006-08-07 17:53:08 -07001802 if (nlmsg_len(nlh) < sizeof(*ndm))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 goto out;
1804
Thomas Grafa14a49d2006-08-07 17:53:08 -07001805 dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
David Ahern7a35a502018-12-05 20:02:29 -08001806 if (!dst_attr) {
1807 NL_SET_ERR_MSG(extack, "Network address not specified");
Thomas Grafa14a49d2006-08-07 17:53:08 -07001808 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001809 }
Thomas Grafa14a49d2006-08-07 17:53:08 -07001810
1811 ndm = nlmsg_data(nlh);
1812 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001813 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001814 if (dev == NULL) {
1815 err = -ENODEV;
1816 goto out;
1817 }
1818 }
1819
WANG Congd7480fd2014-11-10 15:59:36 -08001820 tbl = neigh_find_table(ndm->ndm_family);
1821 if (tbl == NULL)
1822 return -EAFNOSUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823
David Ahern7a35a502018-12-05 20:02:29 -08001824 if (nla_len(dst_attr) < (int)tbl->key_len) {
1825 NL_SET_ERR_MSG(extack, "Invalid network address");
WANG Congd7480fd2014-11-10 15:59:36 -08001826 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001827 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828
WANG Congd7480fd2014-11-10 15:59:36 -08001829 if (ndm->ndm_flags & NTF_PROXY) {
1830 err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
Eric Dumazet110b2492010-10-04 04:27:36 +00001831 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 }
WANG Congd7480fd2014-11-10 15:59:36 -08001833
1834 if (dev == NULL)
1835 goto out;
1836
1837 neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1838 if (neigh == NULL) {
1839 err = -ENOENT;
1840 goto out;
1841 }
1842
David Ahern7a35a502018-12-05 20:02:29 -08001843 err = __neigh_update(neigh, NULL, NUD_FAILED,
1844 NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN,
1845 NETLINK_CB(skb).portid, extack);
Sowmini Varadhan50710342017-06-02 09:01:49 -07001846 write_lock_bh(&tbl->lock);
WANG Congd7480fd2014-11-10 15:59:36 -08001847 neigh_release(neigh);
Sowmini Varadhan50710342017-06-02 09:01:49 -07001848 neigh_remove_one(neigh, tbl);
1849 write_unlock_bh(&tbl->lock);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001850
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851out:
1852 return err;
1853}
1854
David Ahernc21ef3e2017-04-16 09:48:24 -07001855static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
1856 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857{
Roopa Prabhuf7aa74e2018-09-22 21:26:19 -07001858 int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE |
1859 NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001860 struct net *net = sock_net(skb->sk);
Thomas Graf5208deb2006-08-07 17:55:40 -07001861 struct ndmsg *ndm;
1862 struct nlattr *tb[NDA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 struct neigh_table *tbl;
1864 struct net_device *dev = NULL;
WANG Congd7480fd2014-11-10 15:59:36 -08001865 struct neighbour *neigh;
1866 void *dst, *lladdr;
David Aherndf9b0e32018-12-15 14:09:06 -08001867 u8 protocol = 0;
Thomas Graf5208deb2006-08-07 17:55:40 -07001868 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869
Eric Dumazet110b2492010-10-04 04:27:36 +00001870 ASSERT_RTNL();
Johannes Berg8cb08172019-04-26 14:07:28 +02001871 err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX,
1872 nda_policy, extack);
Thomas Graf5208deb2006-08-07 17:55:40 -07001873 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 goto out;
1875
Thomas Graf5208deb2006-08-07 17:55:40 -07001876 err = -EINVAL;
David Ahern7a35a502018-12-05 20:02:29 -08001877 if (!tb[NDA_DST]) {
1878 NL_SET_ERR_MSG(extack, "Network address not specified");
Thomas Graf5208deb2006-08-07 17:55:40 -07001879 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001880 }
Thomas Graf5208deb2006-08-07 17:55:40 -07001881
1882 ndm = nlmsg_data(nlh);
1883 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001884 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Graf5208deb2006-08-07 17:55:40 -07001885 if (dev == NULL) {
1886 err = -ENODEV;
1887 goto out;
1888 }
1889
David Ahern7a35a502018-12-05 20:02:29 -08001890 if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) {
1891 NL_SET_ERR_MSG(extack, "Invalid link address");
Eric Dumazet110b2492010-10-04 04:27:36 +00001892 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001893 }
Thomas Graf5208deb2006-08-07 17:55:40 -07001894 }
1895
WANG Congd7480fd2014-11-10 15:59:36 -08001896 tbl = neigh_find_table(ndm->ndm_family);
1897 if (tbl == NULL)
1898 return -EAFNOSUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
David Ahern7a35a502018-12-05 20:02:29 -08001900 if (nla_len(tb[NDA_DST]) < (int)tbl->key_len) {
1901 NL_SET_ERR_MSG(extack, "Invalid network address");
WANG Congd7480fd2014-11-10 15:59:36 -08001902 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001903 }
1904
WANG Congd7480fd2014-11-10 15:59:36 -08001905 dst = nla_data(tb[NDA_DST]);
1906 lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907
David Aherna9cd3432018-12-19 20:02:36 -08001908 if (tb[NDA_PROTOCOL])
David Aherndf9b0e32018-12-15 14:09:06 -08001909 protocol = nla_get_u8(tb[NDA_PROTOCOL]);
David Aherndf9b0e32018-12-15 14:09:06 -08001910
WANG Congd7480fd2014-11-10 15:59:36 -08001911 if (ndm->ndm_flags & NTF_PROXY) {
1912 struct pneigh_entry *pn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913
WANG Congd7480fd2014-11-10 15:59:36 -08001914 err = -ENOBUFS;
1915 pn = pneigh_lookup(tbl, net, dst, dev, 1);
1916 if (pn) {
1917 pn->flags = ndm->ndm_flags;
David Aherndf9b0e32018-12-15 14:09:06 -08001918 if (protocol)
1919 pn->protocol = protocol;
Eric Biederman0c5c2d32009-03-04 00:03:08 -08001920 err = 0;
WANG Congd7480fd2014-11-10 15:59:36 -08001921 }
Eric Dumazet110b2492010-10-04 04:27:36 +00001922 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 }
1924
David Ahern7a35a502018-12-05 20:02:29 -08001925 if (!dev) {
1926 NL_SET_ERR_MSG(extack, "Device not specified");
WANG Congd7480fd2014-11-10 15:59:36 -08001927 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001928 }
WANG Congd7480fd2014-11-10 15:59:36 -08001929
David Ahernb8fb1ab2019-04-16 17:31:43 -07001930 if (tbl->allow_add && !tbl->allow_add(dev, extack)) {
1931 err = -EINVAL;
1932 goto out;
1933 }
1934
WANG Congd7480fd2014-11-10 15:59:36 -08001935 neigh = neigh_lookup(tbl, dst, dev);
1936 if (neigh == NULL) {
David Aherne997f8a2018-12-11 18:57:25 -07001937 bool exempt_from_gc;
1938
WANG Congd7480fd2014-11-10 15:59:36 -08001939 if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
1940 err = -ENOENT;
1941 goto out;
1942 }
1943
David Aherne997f8a2018-12-11 18:57:25 -07001944 exempt_from_gc = ndm->ndm_state & NUD_PERMANENT ||
1945 ndm->ndm_flags & NTF_EXT_LEARNED;
1946 neigh = ___neigh_create(tbl, dst, dev, exempt_from_gc, true);
WANG Congd7480fd2014-11-10 15:59:36 -08001947 if (IS_ERR(neigh)) {
1948 err = PTR_ERR(neigh);
1949 goto out;
1950 }
1951 } else {
1952 if (nlh->nlmsg_flags & NLM_F_EXCL) {
1953 err = -EEXIST;
1954 neigh_release(neigh);
1955 goto out;
1956 }
1957
1958 if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
Roopa Prabhuf7aa74e2018-09-22 21:26:19 -07001959 flags &= ~(NEIGH_UPDATE_F_OVERRIDE |
1960 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
WANG Congd7480fd2014-11-10 15:59:36 -08001961 }
1962
Roman Mashak38212bb2020-05-01 21:34:18 -04001963 if (protocol)
1964 neigh->protocol = protocol;
1965
Roopa Prabhu9ce33e42018-04-24 13:49:34 -07001966 if (ndm->ndm_flags & NTF_EXT_LEARNED)
1967 flags |= NEIGH_UPDATE_F_EXT_LEARNED;
1968
Roopa Prabhuf7aa74e2018-09-22 21:26:19 -07001969 if (ndm->ndm_flags & NTF_ROUTER)
1970 flags |= NEIGH_UPDATE_F_ISROUTER;
1971
WANG Congd7480fd2014-11-10 15:59:36 -08001972 if (ndm->ndm_flags & NTF_USE) {
1973 neigh_event_send(neigh, NULL);
1974 err = 0;
1975 } else
David Ahern7a35a502018-12-05 20:02:29 -08001976 err = __neigh_update(neigh, lladdr, ndm->ndm_state, flags,
1977 NETLINK_CB(skb).portid, extack);
David Aherndf9b0e32018-12-15 14:09:06 -08001978
WANG Congd7480fd2014-11-10 15:59:36 -08001979 neigh_release(neigh);
1980
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981out:
1982 return err;
1983}
1984
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001985static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
1986{
Thomas Grafca860fb2006-08-07 18:00:18 -07001987 struct nlattr *nest;
1988
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001989 nest = nla_nest_start_noflag(skb, NDTA_PARMS);
Thomas Grafca860fb2006-08-07 18:00:18 -07001990 if (nest == NULL)
1991 return -ENOBUFS;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001992
David S. Miller9a6308d2012-04-01 20:06:28 -04001993 if ((parms->dev &&
1994 nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
Reshetova, Elena63439442017-06-30 13:07:56 +03001995 nla_put_u32(skb, NDTPA_REFCNT, refcount_read(&parms->refcnt)) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001996 nla_put_u32(skb, NDTPA_QUEUE_LENBYTES,
1997 NEIGH_VAR(parms, QUEUE_LEN_BYTES)) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04001998 /* approximative value for deprecated QUEUE_LEN (in packets) */
1999 nla_put_u32(skb, NDTPA_QUEUE_LEN,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002000 NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) ||
2001 nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) ||
2002 nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) ||
2003 nla_put_u32(skb, NDTPA_UCAST_PROBES,
2004 NEIGH_VAR(parms, UCAST_PROBES)) ||
2005 nla_put_u32(skb, NDTPA_MCAST_PROBES,
2006 NEIGH_VAR(parms, MCAST_PROBES)) ||
YOSHIFUJI Hideaki/吉藤英明8da86462015-03-19 22:41:46 +09002007 nla_put_u32(skb, NDTPA_MCAST_REPROBES,
2008 NEIGH_VAR(parms, MCAST_REPROBES)) ||
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002009 nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time,
2010 NDTPA_PAD) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04002011 nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002012 NEIGH_VAR(parms, BASE_REACHABLE_TIME), NDTPA_PAD) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002013 nla_put_msecs(skb, NDTPA_GC_STALETIME,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002014 NEIGH_VAR(parms, GC_STALETIME), NDTPA_PAD) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04002015 nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002016 NEIGH_VAR(parms, DELAY_PROBE_TIME), NDTPA_PAD) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002017 nla_put_msecs(skb, NDTPA_RETRANS_TIME,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002018 NEIGH_VAR(parms, RETRANS_TIME), NDTPA_PAD) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002019 nla_put_msecs(skb, NDTPA_ANYCAST_DELAY,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002020 NEIGH_VAR(parms, ANYCAST_DELAY), NDTPA_PAD) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002021 nla_put_msecs(skb, NDTPA_PROXY_DELAY,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002022 NEIGH_VAR(parms, PROXY_DELAY), NDTPA_PAD) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002023 nla_put_msecs(skb, NDTPA_LOCKTIME,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002024 NEIGH_VAR(parms, LOCKTIME), NDTPA_PAD))
David S. Miller9a6308d2012-04-01 20:06:28 -04002025 goto nla_put_failure;
Thomas Grafca860fb2006-08-07 18:00:18 -07002026 return nla_nest_end(skb, nest);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002027
Thomas Grafca860fb2006-08-07 18:00:18 -07002028nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07002029 nla_nest_cancel(skb, nest);
2030 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002031}
2032
Thomas Grafca860fb2006-08-07 18:00:18 -07002033static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
2034 u32 pid, u32 seq, int type, int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002035{
2036 struct nlmsghdr *nlh;
2037 struct ndtmsg *ndtmsg;
2038
Thomas Grafca860fb2006-08-07 18:00:18 -07002039 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2040 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08002041 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002042
Thomas Grafca860fb2006-08-07 18:00:18 -07002043 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002044
2045 read_lock_bh(&tbl->lock);
2046 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07002047 ndtmsg->ndtm_pad1 = 0;
2048 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002049
David S. Miller9a6308d2012-04-01 20:06:28 -04002050 if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002051 nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval, NDTA_PAD) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04002052 nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
2053 nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
2054 nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
2055 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002056 {
2057 unsigned long now = jiffies;
Eric Dumazet9d027e32019-11-05 14:11:49 -08002058 long flush_delta = now - tbl->last_flush;
2059 long rand_delta = now - tbl->last_rand;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002060 struct neigh_hash_table *nht;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002061 struct ndt_config ndc = {
2062 .ndtc_key_len = tbl->key_len,
2063 .ndtc_entry_size = tbl->entry_size,
2064 .ndtc_entries = atomic_read(&tbl->entries),
2065 .ndtc_last_flush = jiffies_to_msecs(flush_delta),
2066 .ndtc_last_rand = jiffies_to_msecs(rand_delta),
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002067 .ndtc_proxy_qlen = tbl->proxy_queue.qlen,
2068 };
2069
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002070 rcu_read_lock_bh();
2071 nht = rcu_dereference_bh(tbl->nht);
David S. Miller2c2aba62011-12-28 15:06:58 -05002072 ndc.ndtc_hash_rnd = nht->hash_rnd[0];
David S. Millercd089332011-07-11 01:28:12 -07002073 ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002074 rcu_read_unlock_bh();
2075
David S. Miller9a6308d2012-04-01 20:06:28 -04002076 if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
2077 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002078 }
2079
2080 {
2081 int cpu;
2082 struct ndt_stats ndst;
2083
2084 memset(&ndst, 0, sizeof(ndst));
2085
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07002086 for_each_possible_cpu(cpu) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002087 struct neigh_statistics *st;
2088
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002089 st = per_cpu_ptr(tbl->stats, cpu);
2090 ndst.ndts_allocs += st->allocs;
2091 ndst.ndts_destroys += st->destroys;
2092 ndst.ndts_hash_grows += st->hash_grows;
2093 ndst.ndts_res_failed += st->res_failed;
2094 ndst.ndts_lookups += st->lookups;
2095 ndst.ndts_hits += st->hits;
2096 ndst.ndts_rcv_probes_mcast += st->rcv_probes_mcast;
2097 ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast;
2098 ndst.ndts_periodic_gc_runs += st->periodic_gc_runs;
2099 ndst.ndts_forced_gc_runs += st->forced_gc_runs;
Rick Jonesfb811392015-08-07 11:10:37 -07002100 ndst.ndts_table_fulls += st->table_fulls;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002101 }
2102
Nicolas Dichtelb6763382016-04-26 10:06:17 +02002103 if (nla_put_64bit(skb, NDTA_STATS, sizeof(ndst), &ndst,
2104 NDTA_PAD))
David S. Miller9a6308d2012-04-01 20:06:28 -04002105 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002106 }
2107
2108 BUG_ON(tbl->parms.dev);
2109 if (neightbl_fill_parms(skb, &tbl->parms) < 0)
Thomas Grafca860fb2006-08-07 18:00:18 -07002110 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002111
2112 read_unlock_bh(&tbl->lock);
Johannes Berg053c0952015-01-16 22:09:00 +01002113 nlmsg_end(skb, nlh);
2114 return 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002115
Thomas Grafca860fb2006-08-07 18:00:18 -07002116nla_put_failure:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002117 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08002118 nlmsg_cancel(skb, nlh);
2119 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002120}
2121
Thomas Grafca860fb2006-08-07 18:00:18 -07002122static int neightbl_fill_param_info(struct sk_buff *skb,
2123 struct neigh_table *tbl,
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002124 struct neigh_parms *parms,
Thomas Grafca860fb2006-08-07 18:00:18 -07002125 u32 pid, u32 seq, int type,
2126 unsigned int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002127{
2128 struct ndtmsg *ndtmsg;
2129 struct nlmsghdr *nlh;
2130
Thomas Grafca860fb2006-08-07 18:00:18 -07002131 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2132 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08002133 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002134
Thomas Grafca860fb2006-08-07 18:00:18 -07002135 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002136
2137 read_lock_bh(&tbl->lock);
2138 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07002139 ndtmsg->ndtm_pad1 = 0;
2140 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002141
Thomas Grafca860fb2006-08-07 18:00:18 -07002142 if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
2143 neightbl_fill_parms(skb, parms) < 0)
2144 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002145
2146 read_unlock_bh(&tbl->lock);
Johannes Berg053c0952015-01-16 22:09:00 +01002147 nlmsg_end(skb, nlh);
2148 return 0;
Thomas Grafca860fb2006-08-07 18:00:18 -07002149errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002150 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08002151 nlmsg_cancel(skb, nlh);
2152 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002153}
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002154
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002155static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07002156 [NDTA_NAME] = { .type = NLA_STRING },
2157 [NDTA_THRESH1] = { .type = NLA_U32 },
2158 [NDTA_THRESH2] = { .type = NLA_U32 },
2159 [NDTA_THRESH3] = { .type = NLA_U32 },
2160 [NDTA_GC_INTERVAL] = { .type = NLA_U64 },
2161 [NDTA_PARMS] = { .type = NLA_NESTED },
2162};
2163
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002164static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07002165 [NDTPA_IFINDEX] = { .type = NLA_U32 },
2166 [NDTPA_QUEUE_LEN] = { .type = NLA_U32 },
2167 [NDTPA_PROXY_QLEN] = { .type = NLA_U32 },
2168 [NDTPA_APP_PROBES] = { .type = NLA_U32 },
2169 [NDTPA_UCAST_PROBES] = { .type = NLA_U32 },
2170 [NDTPA_MCAST_PROBES] = { .type = NLA_U32 },
YOSHIFUJI Hideaki/吉藤英明8da86462015-03-19 22:41:46 +09002171 [NDTPA_MCAST_REPROBES] = { .type = NLA_U32 },
Thomas Graf6b3f8672006-08-07 17:58:53 -07002172 [NDTPA_BASE_REACHABLE_TIME] = { .type = NLA_U64 },
2173 [NDTPA_GC_STALETIME] = { .type = NLA_U64 },
2174 [NDTPA_DELAY_PROBE_TIME] = { .type = NLA_U64 },
2175 [NDTPA_RETRANS_TIME] = { .type = NLA_U64 },
2176 [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 },
2177 [NDTPA_PROXY_DELAY] = { .type = NLA_U64 },
2178 [NDTPA_LOCKTIME] = { .type = NLA_U64 },
2179};
2180
David Ahernc21ef3e2017-04-16 09:48:24 -07002181static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
2182 struct netlink_ext_ack *extack)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002183{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002184 struct net *net = sock_net(skb->sk);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002185 struct neigh_table *tbl;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002186 struct ndtmsg *ndtmsg;
2187 struct nlattr *tb[NDTA_MAX+1];
WANG Congd7480fd2014-11-10 15:59:36 -08002188 bool found = false;
2189 int err, tidx;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002190
Johannes Berg8cb08172019-04-26 14:07:28 +02002191 err = nlmsg_parse_deprecated(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
2192 nl_neightbl_policy, extack);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002193 if (err < 0)
2194 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002195
Thomas Graf6b3f8672006-08-07 17:58:53 -07002196 if (tb[NDTA_NAME] == NULL) {
2197 err = -EINVAL;
2198 goto errout;
2199 }
2200
2201 ndtmsg = nlmsg_data(nlh);
WANG Congd7480fd2014-11-10 15:59:36 -08002202
2203 for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2204 tbl = neigh_tables[tidx];
2205 if (!tbl)
2206 continue;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002207 if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
2208 continue;
WANG Congd7480fd2014-11-10 15:59:36 -08002209 if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) {
2210 found = true;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002211 break;
WANG Congd7480fd2014-11-10 15:59:36 -08002212 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002213 }
2214
WANG Congd7480fd2014-11-10 15:59:36 -08002215 if (!found)
2216 return -ENOENT;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002217
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002218 /*
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002219 * We acquire tbl->lock to be nice to the periodic timers and
2220 * make sure they always see a consistent set of values.
2221 */
2222 write_lock_bh(&tbl->lock);
2223
Thomas Graf6b3f8672006-08-07 17:58:53 -07002224 if (tb[NDTA_PARMS]) {
2225 struct nlattr *tbp[NDTPA_MAX+1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002226 struct neigh_parms *p;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002227 int i, ifindex = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002228
Johannes Berg8cb08172019-04-26 14:07:28 +02002229 err = nla_parse_nested_deprecated(tbp, NDTPA_MAX,
2230 tb[NDTA_PARMS],
2231 nl_ntbl_parm_policy, extack);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002232 if (err < 0)
2233 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002234
Thomas Graf6b3f8672006-08-07 17:58:53 -07002235 if (tbp[NDTPA_IFINDEX])
2236 ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002237
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07002238 p = lookup_neigh_parms(tbl, net, ifindex);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002239 if (p == NULL) {
2240 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002241 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002242 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002243
Thomas Graf6b3f8672006-08-07 17:58:53 -07002244 for (i = 1; i <= NDTPA_MAX; i++) {
2245 if (tbp[i] == NULL)
2246 continue;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002247
Thomas Graf6b3f8672006-08-07 17:58:53 -07002248 switch (i) {
2249 case NDTPA_QUEUE_LEN:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002250 NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
2251 nla_get_u32(tbp[i]) *
2252 SKB_TRUESIZE(ETH_FRAME_LEN));
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002253 break;
2254 case NDTPA_QUEUE_LENBYTES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002255 NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
2256 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002257 break;
2258 case NDTPA_PROXY_QLEN:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002259 NEIGH_VAR_SET(p, PROXY_QLEN,
2260 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002261 break;
2262 case NDTPA_APP_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002263 NEIGH_VAR_SET(p, APP_PROBES,
2264 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002265 break;
2266 case NDTPA_UCAST_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002267 NEIGH_VAR_SET(p, UCAST_PROBES,
2268 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002269 break;
2270 case NDTPA_MCAST_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002271 NEIGH_VAR_SET(p, MCAST_PROBES,
2272 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002273 break;
YOSHIFUJI Hideaki/吉藤英明8da86462015-03-19 22:41:46 +09002274 case NDTPA_MCAST_REPROBES:
2275 NEIGH_VAR_SET(p, MCAST_REPROBES,
2276 nla_get_u32(tbp[i]));
2277 break;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002278 case NDTPA_BASE_REACHABLE_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002279 NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,
2280 nla_get_msecs(tbp[i]));
Jean-Francois Remy4bf69802015-01-14 04:22:39 +01002281 /* update reachable_time as well, otherwise, the change will
2282 * only be effective after the next time neigh_periodic_work
2283 * decides to recompute it (can be multiple minutes)
2284 */
2285 p->reachable_time =
2286 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002287 break;
2288 case NDTPA_GC_STALETIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002289 NEIGH_VAR_SET(p, GC_STALETIME,
2290 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002291 break;
2292 case NDTPA_DELAY_PROBE_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002293 NEIGH_VAR_SET(p, DELAY_PROBE_TIME,
2294 nla_get_msecs(tbp[i]));
Ido Schimmel2a4501a2016-07-05 11:27:42 +02002295 call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002296 break;
2297 case NDTPA_RETRANS_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002298 NEIGH_VAR_SET(p, RETRANS_TIME,
2299 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002300 break;
2301 case NDTPA_ANYCAST_DELAY:
Jiri Pirko39774582014-01-14 15:46:07 +01002302 NEIGH_VAR_SET(p, ANYCAST_DELAY,
2303 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002304 break;
2305 case NDTPA_PROXY_DELAY:
Jiri Pirko39774582014-01-14 15:46:07 +01002306 NEIGH_VAR_SET(p, PROXY_DELAY,
2307 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002308 break;
2309 case NDTPA_LOCKTIME:
Jiri Pirko39774582014-01-14 15:46:07 +01002310 NEIGH_VAR_SET(p, LOCKTIME,
2311 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002312 break;
2313 }
2314 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002315 }
2316
Gao fengdc25c672013-06-20 10:01:34 +08002317 err = -ENOENT;
2318 if ((tb[NDTA_THRESH1] || tb[NDTA_THRESH2] ||
2319 tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]) &&
2320 !net_eq(net, &init_net))
2321 goto errout_tbl_lock;
2322
Thomas Graf6b3f8672006-08-07 17:58:53 -07002323 if (tb[NDTA_THRESH1])
2324 tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
2325
2326 if (tb[NDTA_THRESH2])
2327 tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
2328
2329 if (tb[NDTA_THRESH3])
2330 tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
2331
2332 if (tb[NDTA_GC_INTERVAL])
2333 tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2334
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002335 err = 0;
2336
Thomas Graf6b3f8672006-08-07 17:58:53 -07002337errout_tbl_lock:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002338 write_unlock_bh(&tbl->lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002339errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002340 return err;
2341}
2342
David Ahern9632d472018-10-07 20:16:37 -07002343static int neightbl_valid_dump_info(const struct nlmsghdr *nlh,
2344 struct netlink_ext_ack *extack)
2345{
2346 struct ndtmsg *ndtm;
2347
2348 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndtm))) {
2349 NL_SET_ERR_MSG(extack, "Invalid header for neighbor table dump request");
2350 return -EINVAL;
2351 }
2352
2353 ndtm = nlmsg_data(nlh);
2354 if (ndtm->ndtm_pad1 || ndtm->ndtm_pad2) {
2355 NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor table dump request");
2356 return -EINVAL;
2357 }
2358
2359 if (nlmsg_attrlen(nlh, sizeof(*ndtm))) {
2360 NL_SET_ERR_MSG(extack, "Invalid data after header in neighbor table dump request");
2361 return -EINVAL;
2362 }
2363
2364 return 0;
2365}
2366
Thomas Grafc8822a42007-03-22 11:50:06 -07002367static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002368{
David Ahern9632d472018-10-07 20:16:37 -07002369 const struct nlmsghdr *nlh = cb->nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002370 struct net *net = sock_net(skb->sk);
Thomas Grafca860fb2006-08-07 18:00:18 -07002371 int family, tidx, nidx = 0;
2372 int tbl_skip = cb->args[0];
2373 int neigh_skip = cb->args[1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002374 struct neigh_table *tbl;
2375
David Ahern9632d472018-10-07 20:16:37 -07002376 if (cb->strict_check) {
2377 int err = neightbl_valid_dump_info(nlh, cb->extack);
2378
2379 if (err < 0)
2380 return err;
2381 }
2382
2383 family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002384
WANG Congd7480fd2014-11-10 15:59:36 -08002385 for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002386 struct neigh_parms *p;
2387
WANG Congd7480fd2014-11-10 15:59:36 -08002388 tbl = neigh_tables[tidx];
2389 if (!tbl)
2390 continue;
2391
Thomas Grafca860fb2006-08-07 18:00:18 -07002392 if (tidx < tbl_skip || (family && tbl->family != family))
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002393 continue;
2394
Eric W. Biederman15e47302012-09-07 20:12:54 +00002395 if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
David Ahern9632d472018-10-07 20:16:37 -07002396 nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
David S. Miller7b46a642015-01-18 23:36:08 -05002397 NLM_F_MULTI) < 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002398 break;
2399
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01002400 nidx = 0;
2401 p = list_next_entry(&tbl->parms, list);
2402 list_for_each_entry_from(p, &tbl->parms_list, list) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002403 if (!net_eq(neigh_parms_net(p), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002404 continue;
2405
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002406 if (nidx < neigh_skip)
2407 goto next;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002408
Thomas Grafca860fb2006-08-07 18:00:18 -07002409 if (neightbl_fill_param_info(skb, tbl, p,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002410 NETLINK_CB(cb->skb).portid,
David Ahern9632d472018-10-07 20:16:37 -07002411 nlh->nlmsg_seq,
Thomas Grafca860fb2006-08-07 18:00:18 -07002412 RTM_NEWNEIGHTBL,
David S. Miller7b46a642015-01-18 23:36:08 -05002413 NLM_F_MULTI) < 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002414 goto out;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002415 next:
2416 nidx++;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002417 }
2418
Thomas Grafca860fb2006-08-07 18:00:18 -07002419 neigh_skip = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002420 }
2421out:
Thomas Grafca860fb2006-08-07 18:00:18 -07002422 cb->args[0] = tidx;
2423 cb->args[1] = nidx;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002424
2425 return skb->len;
2426}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427
Thomas Graf8b8aec52006-08-07 17:56:37 -07002428static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
2429 u32 pid, u32 seq, int type, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430{
2431 unsigned long now = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 struct nda_cacheinfo ci;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002433 struct nlmsghdr *nlh;
2434 struct ndmsg *ndm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435
Thomas Graf8b8aec52006-08-07 17:56:37 -07002436 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2437 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08002438 return -EMSGSIZE;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002439
2440 ndm = nlmsg_data(nlh);
2441 ndm->ndm_family = neigh->ops->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07002442 ndm->ndm_pad1 = 0;
2443 ndm->ndm_pad2 = 0;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002444 ndm->ndm_flags = neigh->flags;
2445 ndm->ndm_type = neigh->type;
2446 ndm->ndm_ifindex = neigh->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447
David S. Miller9a6308d2012-04-01 20:06:28 -04002448 if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
2449 goto nla_put_failure;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002450
2451 read_lock_bh(&neigh->lock);
2452 ndm->ndm_state = neigh->nud_state;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00002453 if (neigh->nud_state & NUD_VALID) {
2454 char haddr[MAX_ADDR_LEN];
2455
2456 neigh_ha_snapshot(haddr, neigh, neigh->dev);
2457 if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
2458 read_unlock_bh(&neigh->lock);
2459 goto nla_put_failure;
2460 }
Thomas Graf8b8aec52006-08-07 17:56:37 -07002461 }
2462
Stephen Hemmingerb9f5f522008-06-03 16:03:15 -07002463 ci.ndm_used = jiffies_to_clock_t(now - neigh->used);
2464 ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2465 ci.ndm_updated = jiffies_to_clock_t(now - neigh->updated);
Reshetova, Elena9f237432017-06-30 13:07:55 +03002466 ci.ndm_refcnt = refcount_read(&neigh->refcnt) - 1;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002467 read_unlock_bh(&neigh->lock);
2468
David S. Miller9a6308d2012-04-01 20:06:28 -04002469 if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
2470 nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
2471 goto nla_put_failure;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002472
David Aherndf9b0e32018-12-15 14:09:06 -08002473 if (neigh->protocol && nla_put_u8(skb, NDA_PROTOCOL, neigh->protocol))
2474 goto nla_put_failure;
2475
Johannes Berg053c0952015-01-16 22:09:00 +01002476 nlmsg_end(skb, nlh);
2477 return 0;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002478
2479nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002480 nlmsg_cancel(skb, nlh);
2481 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482}
2483
Tony Zelenoff84920c12012-01-26 22:28:58 +00002484static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
2485 u32 pid, u32 seq, int type, unsigned int flags,
2486 struct neigh_table *tbl)
2487{
2488 struct nlmsghdr *nlh;
2489 struct ndmsg *ndm;
2490
2491 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2492 if (nlh == NULL)
2493 return -EMSGSIZE;
2494
2495 ndm = nlmsg_data(nlh);
2496 ndm->ndm_family = tbl->family;
2497 ndm->ndm_pad1 = 0;
2498 ndm->ndm_pad2 = 0;
2499 ndm->ndm_flags = pn->flags | NTF_PROXY;
Jun Zhao545469f2014-07-26 00:38:59 +08002500 ndm->ndm_type = RTN_UNICAST;
Konstantin Khlebnikov6adc5fd2015-12-01 01:14:48 +03002501 ndm->ndm_ifindex = pn->dev ? pn->dev->ifindex : 0;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002502 ndm->ndm_state = NUD_NONE;
2503
David S. Miller9a6308d2012-04-01 20:06:28 -04002504 if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
2505 goto nla_put_failure;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002506
David Aherndf9b0e32018-12-15 14:09:06 -08002507 if (pn->protocol && nla_put_u8(skb, NDA_PROTOCOL, pn->protocol))
2508 goto nla_put_failure;
2509
Johannes Berg053c0952015-01-16 22:09:00 +01002510 nlmsg_end(skb, nlh);
2511 return 0;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002512
2513nla_put_failure:
2514 nlmsg_cancel(skb, nlh);
2515 return -EMSGSIZE;
2516}
2517
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07002518static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid)
Thomas Grafd961db32007-08-08 23:12:56 -07002519{
2520 call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07002521 __neigh_notify(neigh, RTM_NEWNEIGH, 0, nlmsg_pid);
Thomas Grafd961db32007-08-08 23:12:56 -07002522}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523
David Ahern21fdd092015-09-29 09:32:03 -07002524static bool neigh_master_filtered(struct net_device *dev, int master_idx)
2525{
2526 struct net_device *master;
2527
2528 if (!master_idx)
2529 return false;
2530
Eric Dumazetaab456d2018-10-26 09:33:27 -07002531 master = dev ? netdev_master_upper_dev_get(dev) : NULL;
David Ahern21fdd092015-09-29 09:32:03 -07002532 if (!master || master->ifindex != master_idx)
2533 return true;
2534
2535 return false;
2536}
2537
David Ahern16660f02015-10-03 11:43:46 -07002538static bool neigh_ifindex_filtered(struct net_device *dev, int filter_idx)
2539{
Eric Dumazetaab456d2018-10-26 09:33:27 -07002540 if (filter_idx && (!dev || dev->ifindex != filter_idx))
David Ahern16660f02015-10-03 11:43:46 -07002541 return true;
2542
2543 return false;
2544}
2545
David Ahern6f52f802018-10-03 15:33:12 -07002546struct neigh_dump_filter {
2547 int master_idx;
2548 int dev_idx;
2549};
2550
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
David Ahern6f52f802018-10-03 15:33:12 -07002552 struct netlink_callback *cb,
2553 struct neigh_dump_filter *filter)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554{
Eric Dumazet767e97e2010-10-06 17:49:21 -07002555 struct net *net = sock_net(skb->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 struct neighbour *n;
2557 int rc, h, s_h = cb->args[1];
2558 int idx, s_idx = idx = cb->args[2];
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002559 struct neigh_hash_table *nht;
David Ahern21fdd092015-09-29 09:32:03 -07002560 unsigned int flags = NLM_F_MULTI;
David Ahern21fdd092015-09-29 09:32:03 -07002561
David Ahern6f52f802018-10-03 15:33:12 -07002562 if (filter->dev_idx || filter->master_idx)
2563 flags |= NLM_F_DUMP_FILTERED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002565 rcu_read_lock_bh();
2566 nht = rcu_dereference_bh(tbl->nht);
2567
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002568 for (h = s_h; h < (1 << nht->hash_shift); h++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 if (h > s_h)
2570 s_idx = 0;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002571 for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2572 n != NULL;
2573 n = rcu_dereference_bh(n->next)) {
Zhang Shengju18502ac2016-11-30 11:24:42 +08002574 if (idx < s_idx || !net_eq(dev_net(n->dev), net))
2575 goto next;
David Ahern6f52f802018-10-03 15:33:12 -07002576 if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
2577 neigh_master_filtered(n->dev, filter->master_idx))
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002578 goto next;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002579 if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 cb->nlh->nlmsg_seq,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07002581 RTM_NEWNEIGH,
David Ahern21fdd092015-09-29 09:32:03 -07002582 flags) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 rc = -1;
2584 goto out;
2585 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07002586next:
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002587 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 }
2590 rc = skb->len;
2591out:
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002592 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 cb->args[1] = h;
2594 cb->args[2] = idx;
2595 return rc;
2596}
2597
Tony Zelenoff84920c12012-01-26 22:28:58 +00002598static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
David Ahern6f52f802018-10-03 15:33:12 -07002599 struct netlink_callback *cb,
2600 struct neigh_dump_filter *filter)
Tony Zelenoff84920c12012-01-26 22:28:58 +00002601{
2602 struct pneigh_entry *n;
2603 struct net *net = sock_net(skb->sk);
2604 int rc, h, s_h = cb->args[3];
2605 int idx, s_idx = idx = cb->args[4];
David Ahern6f52f802018-10-03 15:33:12 -07002606 unsigned int flags = NLM_F_MULTI;
2607
2608 if (filter->dev_idx || filter->master_idx)
2609 flags |= NLM_F_DUMP_FILTERED;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002610
2611 read_lock_bh(&tbl->lock);
2612
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002613 for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
Tony Zelenoff84920c12012-01-26 22:28:58 +00002614 if (h > s_h)
2615 s_idx = 0;
2616 for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
Zhang Shengju18502ac2016-11-30 11:24:42 +08002617 if (idx < s_idx || pneigh_net(n) != net)
Tony Zelenoff84920c12012-01-26 22:28:58 +00002618 goto next;
David Ahern6f52f802018-10-03 15:33:12 -07002619 if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
2620 neigh_master_filtered(n->dev, filter->master_idx))
2621 goto next;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002622 if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
Tony Zelenoff84920c12012-01-26 22:28:58 +00002623 cb->nlh->nlmsg_seq,
David Ahern6f52f802018-10-03 15:33:12 -07002624 RTM_NEWNEIGH, flags, tbl) < 0) {
Tony Zelenoff84920c12012-01-26 22:28:58 +00002625 read_unlock_bh(&tbl->lock);
2626 rc = -1;
2627 goto out;
2628 }
2629 next:
2630 idx++;
2631 }
2632 }
2633
2634 read_unlock_bh(&tbl->lock);
2635 rc = skb->len;
2636out:
2637 cb->args[3] = h;
2638 cb->args[4] = idx;
2639 return rc;
2640
2641}
2642
David Ahern51183d22018-10-07 20:16:36 -07002643static int neigh_valid_dump_req(const struct nlmsghdr *nlh,
2644 bool strict_check,
2645 struct neigh_dump_filter *filter,
2646 struct netlink_ext_ack *extack)
2647{
2648 struct nlattr *tb[NDA_MAX + 1];
2649 int err, i;
2650
2651 if (strict_check) {
2652 struct ndmsg *ndm;
2653
2654 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
2655 NL_SET_ERR_MSG(extack, "Invalid header for neighbor dump request");
2656 return -EINVAL;
2657 }
2658
2659 ndm = nlmsg_data(nlh);
2660 if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_ifindex ||
David Ahernc0fde872018-12-19 16:54:38 -08002661 ndm->ndm_state || ndm->ndm_type) {
David Ahern51183d22018-10-07 20:16:36 -07002662 NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor dump request");
2663 return -EINVAL;
2664 }
2665
David Ahernc0fde872018-12-19 16:54:38 -08002666 if (ndm->ndm_flags & ~NTF_PROXY) {
2667 NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor dump request");
2668 return -EINVAL;
2669 }
2670
Johannes Berg8cb08172019-04-26 14:07:28 +02002671 err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg),
2672 tb, NDA_MAX, nda_policy,
2673 extack);
David Ahern51183d22018-10-07 20:16:36 -07002674 } else {
Johannes Berg8cb08172019-04-26 14:07:28 +02002675 err = nlmsg_parse_deprecated(nlh, sizeof(struct ndmsg), tb,
2676 NDA_MAX, nda_policy, extack);
David Ahern51183d22018-10-07 20:16:36 -07002677 }
2678 if (err < 0)
2679 return err;
2680
2681 for (i = 0; i <= NDA_MAX; ++i) {
2682 if (!tb[i])
2683 continue;
2684
2685 /* all new attributes should require strict_check */
2686 switch (i) {
2687 case NDA_IFINDEX:
David Ahern51183d22018-10-07 20:16:36 -07002688 filter->dev_idx = nla_get_u32(tb[i]);
2689 break;
2690 case NDA_MASTER:
David Ahern51183d22018-10-07 20:16:36 -07002691 filter->master_idx = nla_get_u32(tb[i]);
2692 break;
2693 default:
2694 if (strict_check) {
2695 NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor dump request");
2696 return -EINVAL;
2697 }
2698 }
2699 }
2700
2701 return 0;
2702}
2703
Thomas Grafc8822a42007-03-22 11:50:06 -07002704static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705{
David Ahern6f52f802018-10-03 15:33:12 -07002706 const struct nlmsghdr *nlh = cb->nlh;
2707 struct neigh_dump_filter filter = {};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 struct neigh_table *tbl;
2709 int t, family, s_t;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002710 int proxy = 0;
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002711 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712
David Ahern6f52f802018-10-03 15:33:12 -07002713 family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002714
2715 /* check for full ndmsg structure presence, family member is
2716 * the same for both structures
2717 */
David Ahern6f52f802018-10-03 15:33:12 -07002718 if (nlmsg_len(nlh) >= sizeof(struct ndmsg) &&
2719 ((struct ndmsg *)nlmsg_data(nlh))->ndm_flags == NTF_PROXY)
Tony Zelenoff84920c12012-01-26 22:28:58 +00002720 proxy = 1;
2721
David Ahern51183d22018-10-07 20:16:36 -07002722 err = neigh_valid_dump_req(nlh, cb->strict_check, &filter, cb->extack);
2723 if (err < 0 && cb->strict_check)
2724 return err;
2725
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 s_t = cb->args[0];
2727
WANG Congd7480fd2014-11-10 15:59:36 -08002728 for (t = 0; t < NEIGH_NR_TABLES; t++) {
2729 tbl = neigh_tables[t];
2730
2731 if (!tbl)
2732 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 if (t < s_t || (family && tbl->family != family))
2734 continue;
2735 if (t > s_t)
2736 memset(&cb->args[1], 0, sizeof(cb->args) -
2737 sizeof(cb->args[0]));
Tony Zelenoff84920c12012-01-26 22:28:58 +00002738 if (proxy)
David Ahern6f52f802018-10-03 15:33:12 -07002739 err = pneigh_dump_table(tbl, skb, cb, &filter);
Tony Zelenoff84920c12012-01-26 22:28:58 +00002740 else
David Ahern6f52f802018-10-03 15:33:12 -07002741 err = neigh_dump_table(tbl, skb, cb, &filter);
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002742 if (err < 0)
2743 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745
2746 cb->args[0] = t;
2747 return skb->len;
2748}
2749
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08002750static int neigh_valid_get_req(const struct nlmsghdr *nlh,
2751 struct neigh_table **tbl,
2752 void **dst, int *dev_idx, u8 *ndm_flags,
2753 struct netlink_ext_ack *extack)
2754{
2755 struct nlattr *tb[NDA_MAX + 1];
2756 struct ndmsg *ndm;
2757 int err, i;
2758
2759 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
2760 NL_SET_ERR_MSG(extack, "Invalid header for neighbor get request");
2761 return -EINVAL;
2762 }
2763
2764 ndm = nlmsg_data(nlh);
2765 if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_state ||
2766 ndm->ndm_type) {
2767 NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor get request");
2768 return -EINVAL;
2769 }
2770
2771 if (ndm->ndm_flags & ~NTF_PROXY) {
2772 NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor get request");
2773 return -EINVAL;
2774 }
2775
Johannes Berg8cb08172019-04-26 14:07:28 +02002776 err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb,
2777 NDA_MAX, nda_policy, extack);
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08002778 if (err < 0)
2779 return err;
2780
2781 *ndm_flags = ndm->ndm_flags;
2782 *dev_idx = ndm->ndm_ifindex;
2783 *tbl = neigh_find_table(ndm->ndm_family);
2784 if (*tbl == NULL) {
2785 NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
2786 return -EAFNOSUPPORT;
2787 }
2788
2789 for (i = 0; i <= NDA_MAX; ++i) {
2790 if (!tb[i])
2791 continue;
2792
2793 switch (i) {
2794 case NDA_DST:
2795 if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
2796 NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
2797 return -EINVAL;
2798 }
2799 *dst = nla_data(tb[i]);
2800 break;
2801 default:
2802 NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request");
2803 return -EINVAL;
2804 }
2805 }
2806
2807 return 0;
2808}
2809
2810static inline size_t neigh_nlmsg_size(void)
2811{
2812 return NLMSG_ALIGN(sizeof(struct ndmsg))
2813 + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
2814 + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
2815 + nla_total_size(sizeof(struct nda_cacheinfo))
2816 + nla_total_size(4) /* NDA_PROBES */
2817 + nla_total_size(1); /* NDA_PROTOCOL */
2818}
2819
2820static int neigh_get_reply(struct net *net, struct neighbour *neigh,
2821 u32 pid, u32 seq)
2822{
2823 struct sk_buff *skb;
2824 int err = 0;
2825
2826 skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL);
2827 if (!skb)
2828 return -ENOBUFS;
2829
2830 err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0);
2831 if (err) {
2832 kfree_skb(skb);
2833 goto errout;
2834 }
2835
2836 err = rtnl_unicast(skb, net, pid);
2837errout:
2838 return err;
2839}
2840
2841static inline size_t pneigh_nlmsg_size(void)
2842{
2843 return NLMSG_ALIGN(sizeof(struct ndmsg))
Colin Ian King463561e2018-12-20 16:50:50 +00002844 + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08002845 + nla_total_size(1); /* NDA_PROTOCOL */
2846}
2847
2848static int pneigh_get_reply(struct net *net, struct pneigh_entry *neigh,
2849 u32 pid, u32 seq, struct neigh_table *tbl)
2850{
2851 struct sk_buff *skb;
2852 int err = 0;
2853
2854 skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL);
2855 if (!skb)
2856 return -ENOBUFS;
2857
2858 err = pneigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0, tbl);
2859 if (err) {
2860 kfree_skb(skb);
2861 goto errout;
2862 }
2863
2864 err = rtnl_unicast(skb, net, pid);
2865errout:
2866 return err;
2867}
2868
2869static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
2870 struct netlink_ext_ack *extack)
2871{
2872 struct net *net = sock_net(in_skb->sk);
2873 struct net_device *dev = NULL;
2874 struct neigh_table *tbl = NULL;
2875 struct neighbour *neigh;
2876 void *dst = NULL;
2877 u8 ndm_flags = 0;
2878 int dev_idx = 0;
2879 int err;
2880
2881 err = neigh_valid_get_req(nlh, &tbl, &dst, &dev_idx, &ndm_flags,
2882 extack);
2883 if (err < 0)
2884 return err;
2885
2886 if (dev_idx) {
2887 dev = __dev_get_by_index(net, dev_idx);
2888 if (!dev) {
2889 NL_SET_ERR_MSG(extack, "Unknown device ifindex");
2890 return -ENODEV;
2891 }
2892 }
2893
2894 if (!dst) {
2895 NL_SET_ERR_MSG(extack, "Network address not specified");
2896 return -EINVAL;
2897 }
2898
2899 if (ndm_flags & NTF_PROXY) {
2900 struct pneigh_entry *pn;
2901
2902 pn = pneigh_lookup(tbl, net, dst, dev, 0);
2903 if (!pn) {
2904 NL_SET_ERR_MSG(extack, "Proxy neighbour entry not found");
2905 return -ENOENT;
2906 }
2907 return pneigh_get_reply(net, pn, NETLINK_CB(in_skb).portid,
2908 nlh->nlmsg_seq, tbl);
2909 }
2910
2911 if (!dev) {
2912 NL_SET_ERR_MSG(extack, "No device specified");
2913 return -EINVAL;
2914 }
2915
2916 neigh = neigh_lookup(tbl, dst, dev);
2917 if (!neigh) {
2918 NL_SET_ERR_MSG(extack, "Neighbour entry not found");
2919 return -ENOENT;
2920 }
2921
2922 err = neigh_get_reply(net, neigh, NETLINK_CB(in_skb).portid,
2923 nlh->nlmsg_seq);
2924
2925 neigh_release(neigh);
2926
2927 return err;
2928}
2929
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
2931{
2932 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002933 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002935 rcu_read_lock_bh();
2936 nht = rcu_dereference_bh(tbl->nht);
2937
Eric Dumazet767e97e2010-10-06 17:49:21 -07002938 read_lock(&tbl->lock); /* avoid resizes */
David S. Millercd089332011-07-11 01:28:12 -07002939 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 struct neighbour *n;
2941
Eric Dumazet767e97e2010-10-06 17:49:21 -07002942 for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
2943 n != NULL;
2944 n = rcu_dereference_bh(n->next))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 cb(n, cookie);
2946 }
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002947 read_unlock(&tbl->lock);
2948 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949}
2950EXPORT_SYMBOL(neigh_for_each);
2951
2952/* The tbl->lock must be held as a writer and BH disabled. */
2953void __neigh_for_each_release(struct neigh_table *tbl,
2954 int (*cb)(struct neighbour *))
2955{
2956 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002957 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002959 nht = rcu_dereference_protected(tbl->nht,
2960 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -07002961 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002962 struct neighbour *n;
2963 struct neighbour __rcu **np;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002965 np = &nht->hash_buckets[chain];
Eric Dumazet767e97e2010-10-06 17:49:21 -07002966 while ((n = rcu_dereference_protected(*np,
2967 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 int release;
2969
2970 write_lock(&n->lock);
2971 release = cb(n);
2972 if (release) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002973 rcu_assign_pointer(*np,
2974 rcu_dereference_protected(n->next,
2975 lockdep_is_held(&tbl->lock)));
David Ahern58956312018-12-07 12:24:57 -08002976 neigh_mark_dead(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 } else
2978 np = &n->next;
2979 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -07002980 if (release)
2981 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 }
2983 }
2984}
2985EXPORT_SYMBOL(__neigh_for_each_release);
2986
Eric W. Biedermanb79bda32015-03-07 16:25:56 -06002987int neigh_xmit(int index, struct net_device *dev,
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06002988 const void *addr, struct sk_buff *skb)
2989{
Eric W. Biedermanb79bda32015-03-07 16:25:56 -06002990 int err = -EAFNOSUPPORT;
2991 if (likely(index < NEIGH_NR_TABLES)) {
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06002992 struct neigh_table *tbl;
2993 struct neighbour *neigh;
2994
Eric W. Biedermanb79bda32015-03-07 16:25:56 -06002995 tbl = neigh_tables[index];
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06002996 if (!tbl)
2997 goto out;
David Barrosob560f032016-06-28 11:16:43 +03002998 rcu_read_lock_bh();
David Ahern4b2a2bf2019-05-01 18:18:42 -07002999 if (index == NEIGH_ARP_TABLE) {
3000 u32 key = *((u32 *)addr);
3001
3002 neigh = __ipv4_neigh_lookup_noref(dev, key);
3003 } else {
3004 neigh = __neigh_lookup_noref(tbl, addr, dev);
3005 }
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06003006 if (!neigh)
3007 neigh = __neigh_create(tbl, addr, dev, false);
3008 err = PTR_ERR(neigh);
David Barrosob560f032016-06-28 11:16:43 +03003009 if (IS_ERR(neigh)) {
3010 rcu_read_unlock_bh();
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06003011 goto out_kfree_skb;
David Barrosob560f032016-06-28 11:16:43 +03003012 }
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06003013 err = neigh->output(neigh, skb);
David Barrosob560f032016-06-28 11:16:43 +03003014 rcu_read_unlock_bh();
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06003015 }
Eric W. Biedermanb79bda32015-03-07 16:25:56 -06003016 else if (index == NEIGH_LINK_TABLE) {
3017 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
3018 addr, NULL, skb->len);
3019 if (err < 0)
3020 goto out_kfree_skb;
3021 err = dev_queue_xmit(skb);
3022 }
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06003023out:
3024 return err;
3025out_kfree_skb:
3026 kfree_skb(skb);
3027 goto out;
3028}
3029EXPORT_SYMBOL(neigh_xmit);
3030
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031#ifdef CONFIG_PROC_FS
3032
3033static struct neighbour *neigh_get_first(struct seq_file *seq)
3034{
3035 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09003036 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003037 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 struct neighbour *n = NULL;
Colin Ian Kingf530eed2019-07-26 10:46:11 +01003039 int bucket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040
3041 state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
David S. Millercd089332011-07-11 01:28:12 -07003042 for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07003043 n = rcu_dereference_bh(nht->hash_buckets[bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044
3045 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09003046 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08003047 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 if (state->neigh_sub_iter) {
3049 loff_t fakep = 0;
3050 void *v;
3051
3052 v = state->neigh_sub_iter(state, n, &fakep);
3053 if (!v)
3054 goto next;
3055 }
3056 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
3057 break;
3058 if (n->nud_state & ~NUD_NOARP)
3059 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07003060next:
3061 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 }
3063
3064 if (n)
3065 break;
3066 }
3067 state->bucket = bucket;
3068
3069 return n;
3070}
3071
3072static struct neighbour *neigh_get_next(struct seq_file *seq,
3073 struct neighbour *n,
3074 loff_t *pos)
3075{
3076 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09003077 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003078 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079
3080 if (state->neigh_sub_iter) {
3081 void *v = state->neigh_sub_iter(state, n, pos);
3082 if (v)
3083 return n;
3084 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07003085 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086
3087 while (1) {
3088 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09003089 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08003090 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 if (state->neigh_sub_iter) {
3092 void *v = state->neigh_sub_iter(state, n, pos);
3093 if (v)
3094 return n;
3095 goto next;
3096 }
3097 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
3098 break;
3099
3100 if (n->nud_state & ~NUD_NOARP)
3101 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07003102next:
3103 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 }
3105
3106 if (n)
3107 break;
3108
David S. Millercd089332011-07-11 01:28:12 -07003109 if (++state->bucket >= (1 << nht->hash_shift))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 break;
3111
Eric Dumazet767e97e2010-10-06 17:49:21 -07003112 n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 }
3114
3115 if (n && pos)
3116 --(*pos);
3117 return n;
3118}
3119
3120static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
3121{
3122 struct neighbour *n = neigh_get_first(seq);
3123
3124 if (n) {
Chris Larson745e2032008-08-03 01:10:55 -07003125 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 while (*pos) {
3127 n = neigh_get_next(seq, n, pos);
3128 if (!n)
3129 break;
3130 }
3131 }
3132 return *pos ? NULL : n;
3133}
3134
3135static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
3136{
3137 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09003138 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 struct neigh_table *tbl = state->tbl;
3140 struct pneigh_entry *pn = NULL;
3141 int bucket = state->bucket;
3142
3143 state->flags |= NEIGH_SEQ_IS_PNEIGH;
3144 for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
3145 pn = tbl->phash_buckets[bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09003146 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08003147 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 if (pn)
3149 break;
3150 }
3151 state->bucket = bucket;
3152
3153 return pn;
3154}
3155
3156static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
3157 struct pneigh_entry *pn,
3158 loff_t *pos)
3159{
3160 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09003161 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 struct neigh_table *tbl = state->tbl;
3163
Jorge Boncompte [DTI2]df07a942011-11-25 13:24:49 -05003164 do {
3165 pn = pn->next;
3166 } while (pn && !net_eq(pneigh_net(pn), net));
3167
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 while (!pn) {
3169 if (++state->bucket > PNEIGH_HASHMASK)
3170 break;
3171 pn = tbl->phash_buckets[state->bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09003172 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08003173 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174 if (pn)
3175 break;
3176 }
3177
3178 if (pn && pos)
3179 --(*pos);
3180
3181 return pn;
3182}
3183
3184static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
3185{
3186 struct pneigh_entry *pn = pneigh_get_first(seq);
3187
3188 if (pn) {
Chris Larson745e2032008-08-03 01:10:55 -07003189 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 while (*pos) {
3191 pn = pneigh_get_next(seq, pn, pos);
3192 if (!pn)
3193 break;
3194 }
3195 }
3196 return *pos ? NULL : pn;
3197}
3198
3199static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
3200{
3201 struct neigh_seq_state *state = seq->private;
3202 void *rc;
Chris Larson745e2032008-08-03 01:10:55 -07003203 loff_t idxpos = *pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204
Chris Larson745e2032008-08-03 01:10:55 -07003205 rc = neigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
Chris Larson745e2032008-08-03 01:10:55 -07003207 rc = pneigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208
3209 return rc;
3210}
3211
3212void *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 -07003213 __acquires(tbl->lock)
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003214 __acquires(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215{
3216 struct neigh_seq_state *state = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217
3218 state->tbl = tbl;
3219 state->bucket = 0;
3220 state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
3221
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003222 rcu_read_lock_bh();
3223 state->nht = rcu_dereference_bh(tbl->nht);
Eric Dumazetf3e92cb2019-06-15 16:28:48 -07003224 read_lock(&tbl->lock);
Eric Dumazet767e97e2010-10-06 17:49:21 -07003225
Chris Larson745e2032008-08-03 01:10:55 -07003226 return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227}
3228EXPORT_SYMBOL(neigh_seq_start);
3229
3230void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
3231{
3232 struct neigh_seq_state *state;
3233 void *rc;
3234
3235 if (v == SEQ_START_TOKEN) {
Chris Larsonbff69732008-08-03 01:02:41 -07003236 rc = neigh_get_first(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 goto out;
3238 }
3239
3240 state = seq->private;
3241 if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
3242 rc = neigh_get_next(seq, v, NULL);
3243 if (rc)
3244 goto out;
3245 if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
3246 rc = pneigh_get_first(seq);
3247 } else {
3248 BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
3249 rc = pneigh_get_next(seq, v, NULL);
3250 }
3251out:
3252 ++(*pos);
3253 return rc;
3254}
3255EXPORT_SYMBOL(neigh_seq_next);
3256
3257void neigh_seq_stop(struct seq_file *seq, void *v)
Eric Dumazetf3e92cb2019-06-15 16:28:48 -07003258 __releases(tbl->lock)
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003259 __releases(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260{
Eric Dumazetf3e92cb2019-06-15 16:28:48 -07003261 struct neigh_seq_state *state = seq->private;
3262 struct neigh_table *tbl = state->tbl;
3263
3264 read_unlock(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003265 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266}
3267EXPORT_SYMBOL(neigh_seq_stop);
3268
3269/* statistics via seq_file */
3270
3271static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
3272{
Christoph Hellwig71a50532018-04-15 10:16:41 +02003273 struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 int cpu;
3275
3276 if (*pos == 0)
3277 return SEQ_START_TOKEN;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09003278
Rusty Russell0f23174a2008-12-29 12:23:42 +00003279 for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 if (!cpu_possible(cpu))
3281 continue;
3282 *pos = cpu+1;
3283 return per_cpu_ptr(tbl->stats, cpu);
3284 }
3285 return NULL;
3286}
3287
3288static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
3289{
Christoph Hellwig71a50532018-04-15 10:16:41 +02003290 struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291 int cpu;
3292
Rusty Russell0f23174a2008-12-29 12:23:42 +00003293 for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 if (!cpu_possible(cpu))
3295 continue;
3296 *pos = cpu+1;
3297 return per_cpu_ptr(tbl->stats, cpu);
3298 }
Vasily Averin1e3f9f02020-01-23 10:11:28 +03003299 (*pos)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300 return NULL;
3301}
3302
3303static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
3304{
3305
3306}
3307
3308static int neigh_stat_seq_show(struct seq_file *seq, void *v)
3309{
Christoph Hellwig71a50532018-04-15 10:16:41 +02003310 struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 struct neigh_statistics *st = v;
3312
3313 if (v == SEQ_START_TOKEN) {
Rick Jonesfb811392015-08-07 11:10:37 -07003314 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 -07003315 return 0;
3316 }
3317
3318 seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx "
Rick Jonesfb811392015-08-07 11:10:37 -07003319 "%08lx %08lx %08lx %08lx %08lx %08lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320 atomic_read(&tbl->entries),
3321
3322 st->allocs,
3323 st->destroys,
3324 st->hash_grows,
3325
3326 st->lookups,
3327 st->hits,
3328
3329 st->res_failed,
3330
3331 st->rcv_probes_mcast,
3332 st->rcv_probes_ucast,
3333
3334 st->periodic_gc_runs,
Neil Horman9a6d2762008-07-16 20:50:49 -07003335 st->forced_gc_runs,
Rick Jonesfb811392015-08-07 11:10:37 -07003336 st->unres_discards,
3337 st->table_fulls
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 );
3339
3340 return 0;
3341}
3342
Stephen Hemmingerf6908082007-03-12 14:34:29 -07003343static const struct seq_operations neigh_stat_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 .start = neigh_stat_seq_start,
3345 .next = neigh_stat_seq_next,
3346 .stop = neigh_stat_seq_stop,
3347 .show = neigh_stat_seq_show,
3348};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349#endif /* CONFIG_PROC_FS */
3350
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07003351static void __neigh_notify(struct neighbour *n, int type, int flags,
3352 u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09003354 struct net *net = dev_net(n->dev);
Thomas Graf8b8aec52006-08-07 17:56:37 -07003355 struct sk_buff *skb;
Thomas Grafb8673312006-08-15 00:33:14 -07003356 int err = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357
Thomas Graf339bf982006-11-10 14:10:15 -08003358 skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
Thomas Graf8b8aec52006-08-07 17:56:37 -07003359 if (skb == NULL)
Thomas Grafb8673312006-08-15 00:33:14 -07003360 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07003362 err = neigh_fill_info(skb, n, pid, 0, type, flags);
Patrick McHardy26932562007-01-31 23:16:40 -08003363 if (err < 0) {
3364 /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
3365 WARN_ON(err == -EMSGSIZE);
3366 kfree_skb(skb);
3367 goto errout;
3368 }
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08003369 rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
3370 return;
Thomas Grafb8673312006-08-15 00:33:14 -07003371errout:
3372 if (err < 0)
Eric W. Biederman426b5302008-01-24 00:13:18 -08003373 rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
Thomas Grafb8673312006-08-15 00:33:14 -07003374}
3375
3376void neigh_app_ns(struct neighbour *n)
3377{
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07003378 __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003380EXPORT_SYMBOL(neigh_app_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381
3382#ifdef CONFIG_SYSCTL
Cong Wangb93196d2012-12-06 10:04:04 +08003383static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384
Joe Perchesfe2c6332013-06-11 23:04:25 -07003385static int proc_unres_qlen(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003386 void *buffer, size_t *lenp, loff_t *ppos)
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003387{
3388 int size, ret;
Joe Perchesfe2c6332013-06-11 23:04:25 -07003389 struct ctl_table tmp = *ctl;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003390
Matteo Croceeec48442019-07-18 15:58:50 -07003391 tmp.extra1 = SYSCTL_ZERO;
Shan Weice46cc62012-12-04 18:49:15 +00003392 tmp.extra2 = &unres_qlen_max;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003393 tmp.data = &size;
Shan Weice46cc62012-12-04 18:49:15 +00003394
3395 size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN);
3396 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
3397
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003398 if (write && !ret)
3399 *(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
3400 return ret;
3401}
3402
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003403static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
3404 int family)
3405{
Jiri Pirkobba24892013-12-07 19:26:57 +01003406 switch (family) {
3407 case AF_INET:
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003408 return __in_dev_arp_parms_get_rcu(dev);
Jiri Pirkobba24892013-12-07 19:26:57 +01003409 case AF_INET6:
3410 return __in6_dev_nd_parms_get_rcu(dev);
3411 }
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003412 return NULL;
3413}
3414
3415static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
3416 int index)
3417{
3418 struct net_device *dev;
3419 int family = neigh_parms_family(p);
3420
3421 rcu_read_lock();
3422 for_each_netdev_rcu(net, dev) {
3423 struct neigh_parms *dst_p =
3424 neigh_get_dev_parms_rcu(dev, family);
3425
3426 if (dst_p && !test_bit(index, dst_p->data_state))
3427 dst_p->data[index] = p->data[index];
3428 }
3429 rcu_read_unlock();
3430}
3431
3432static void neigh_proc_update(struct ctl_table *ctl, int write)
3433{
3434 struct net_device *dev = ctl->extra1;
3435 struct neigh_parms *p = ctl->extra2;
Jiri Pirko77d47af2013-12-10 23:55:07 +01003436 struct net *net = neigh_parms_net(p);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003437 int index = (int *) ctl->data - p->data;
3438
3439 if (!write)
3440 return;
3441
3442 set_bit(index, p->data_state);
Marcus Huewe7627ae62017-02-15 01:00:36 +01003443 if (index == NEIGH_VAR_DELAY_PROBE_TIME)
3444 call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003445 if (!dev) /* NULL dev means this is default value */
3446 neigh_copy_dflt_parms(net, p, index);
3447}
3448
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003449static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003450 void *buffer, size_t *lenp,
3451 loff_t *ppos)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003452{
3453 struct ctl_table tmp = *ctl;
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003454 int ret;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003455
Matteo Croceeec48442019-07-18 15:58:50 -07003456 tmp.extra1 = SYSCTL_ZERO;
3457 tmp.extra2 = SYSCTL_INT_MAX;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003458
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003459 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
3460 neigh_proc_update(ctl, write);
3461 return ret;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003462}
3463
Christoph Hellwig32927392020-04-24 08:43:38 +02003464int neigh_proc_dointvec(struct ctl_table *ctl, int write, void *buffer,
3465 size_t *lenp, loff_t *ppos)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003466{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003467 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
3468
3469 neigh_proc_update(ctl, write);
3470 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003471}
3472EXPORT_SYMBOL(neigh_proc_dointvec);
3473
Christoph Hellwig32927392020-04-24 08:43:38 +02003474int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, void *buffer,
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003475 size_t *lenp, loff_t *ppos)
3476{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003477 int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
3478
3479 neigh_proc_update(ctl, write);
3480 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003481}
3482EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
3483
3484static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003485 void *buffer, size_t *lenp,
3486 loff_t *ppos)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003487{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003488 int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
3489
3490 neigh_proc_update(ctl, write);
3491 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003492}
3493
3494int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003495 void *buffer, size_t *lenp, loff_t *ppos)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003496{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003497 int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
3498
3499 neigh_proc_update(ctl, write);
3500 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003501}
3502EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
3503
3504static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003505 void *buffer, size_t *lenp,
3506 loff_t *ppos)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003507{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003508 int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
3509
3510 neigh_proc_update(ctl, write);
3511 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003512}
3513
Jean-Francois Remy4bf69802015-01-14 04:22:39 +01003514static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003515 void *buffer, size_t *lenp,
3516 loff_t *ppos)
Jean-Francois Remy4bf69802015-01-14 04:22:39 +01003517{
3518 struct neigh_parms *p = ctl->extra2;
3519 int ret;
3520
3521 if (strcmp(ctl->procname, "base_reachable_time") == 0)
3522 ret = neigh_proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
3523 else if (strcmp(ctl->procname, "base_reachable_time_ms") == 0)
3524 ret = neigh_proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
3525 else
3526 ret = -1;
3527
3528 if (write && ret == 0) {
3529 /* update reachable_time as well, otherwise, the change will
3530 * only be effective after the next time neigh_periodic_work
3531 * decides to recompute it
3532 */
3533 p->reachable_time =
3534 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
3535 }
3536 return ret;
3537}
3538
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003539#define NEIGH_PARMS_DATA_OFFSET(index) \
3540 (&((struct neigh_parms *) 0)->data[index])
3541
3542#define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \
3543 [NEIGH_VAR_ ## attr] = { \
3544 .procname = name, \
3545 .data = NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \
3546 .maxlen = sizeof(int), \
3547 .mode = mval, \
3548 .proc_handler = proc, \
3549 }
3550
3551#define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \
3552 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax)
3553
3554#define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003555 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003556
3557#define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003558 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003559
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003560#define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003561 NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003562
3563#define NEIGH_SYSCTL_UNRES_QLEN_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_unres_qlen)
Eric W. Biederman54716e32010-02-14 03:27:03 +00003565
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566static struct neigh_sysctl_table {
3567 struct ctl_table_header *sysctl_header;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003568 struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
Brian Haleyab32ea52006-09-22 14:15:41 -07003569} neigh_sysctl_template __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 .neigh_vars = {
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003571 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"),
3572 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"),
3573 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"),
YOSHIFUJI Hideaki/吉藤英明8da86462015-03-19 22:41:46 +09003574 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_REPROBES, "mcast_resolicit"),
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003575 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),
3576 NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),
3577 NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"),
3578 NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"),
3579 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"),
3580 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"),
3581 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"),
3582 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"),
3583 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"),
3584 NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"),
3585 NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"),
3586 NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"),
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003587 [NEIGH_VAR_GC_INTERVAL] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 .procname = "gc_interval",
3589 .maxlen = sizeof(int),
3590 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003591 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003593 [NEIGH_VAR_GC_THRESH1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 .procname = "gc_thresh1",
3595 .maxlen = sizeof(int),
3596 .mode = 0644,
Matteo Croceeec48442019-07-18 15:58:50 -07003597 .extra1 = SYSCTL_ZERO,
3598 .extra2 = SYSCTL_INT_MAX,
Francesco Fusco555445c2013-07-24 10:39:06 +02003599 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003601 [NEIGH_VAR_GC_THRESH2] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 .procname = "gc_thresh2",
3603 .maxlen = sizeof(int),
3604 .mode = 0644,
Matteo Croceeec48442019-07-18 15:58:50 -07003605 .extra1 = SYSCTL_ZERO,
3606 .extra2 = SYSCTL_INT_MAX,
Francesco Fusco555445c2013-07-24 10:39:06 +02003607 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003609 [NEIGH_VAR_GC_THRESH3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 .procname = "gc_thresh3",
3611 .maxlen = sizeof(int),
3612 .mode = 0644,
Matteo Croceeec48442019-07-18 15:58:50 -07003613 .extra1 = SYSCTL_ZERO,
3614 .extra2 = SYSCTL_INT_MAX,
Francesco Fusco555445c2013-07-24 10:39:06 +02003615 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 },
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11003617 {},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 },
3619};
3620
3621int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
Jiri Pirko73af6142013-12-07 19:26:55 +01003622 proc_handler *handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623{
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003624 int i;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003625 struct neigh_sysctl_table *t;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003626 const char *dev_name_source;
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003627 char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
Jiri Pirko73af6142013-12-07 19:26:55 +01003628 char *p_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003630 t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 if (!t)
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003632 goto err;
3633
Jiri Pirkob194c1f2014-02-21 14:52:57 +01003634 for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003635 t->neigh_vars[i].data += (long) p;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003636 t->neigh_vars[i].extra1 = dev;
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003637 t->neigh_vars[i].extra2 = p;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003638 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639
3640 if (dev) {
3641 dev_name_source = dev->name;
Eric W. Biedermand12af672007-10-18 03:05:25 -07003642 /* Terminate the table early */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003643 memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
3644 sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 } else {
Mathias Krause9ecf07a2014-07-12 22:36:44 +02003646 struct neigh_table *tbl = p->tbl;
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003647 dev_name_source = "default";
Mathias Krause9ecf07a2014-07-12 22:36:44 +02003648 t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = &tbl->gc_interval;
3649 t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = &tbl->gc_thresh1;
3650 t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = &tbl->gc_thresh2;
3651 t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = &tbl->gc_thresh3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 }
3653
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003654 if (handler) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 /* RetransTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003656 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 /* ReachableTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003658 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 /* RetransTime (in milliseconds)*/
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003660 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 /* ReachableTime (in milliseconds) */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003662 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
Jean-Francois Remy4bf69802015-01-14 04:22:39 +01003663 } else {
3664 /* Those handlers will update p->reachable_time after
3665 * base_reachable_time(_ms) is set to ensure the new timer starts being
3666 * applied after the next neighbour update instead of waiting for
3667 * neigh_periodic_work to update its value (can be multiple minutes)
3668 * So any handler that replaces them should do this as well
3669 */
3670 /* ReachableTime */
3671 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler =
3672 neigh_proc_base_reachable_time;
3673 /* ReachableTime (in milliseconds) */
3674 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler =
3675 neigh_proc_base_reachable_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 }
3677
Eric W. Biederman464dc802012-11-16 03:02:59 +00003678 /* Don't export sysctls to unprivileged users */
3679 if (neigh_parms_net(p)->user_ns != &init_user_ns)
3680 t->neigh_vars[0].procname = NULL;
3681
Jiri Pirko73af6142013-12-07 19:26:55 +01003682 switch (neigh_parms_family(p)) {
3683 case AF_INET:
3684 p_name = "ipv4";
3685 break;
3686 case AF_INET6:
3687 p_name = "ipv6";
3688 break;
3689 default:
3690 BUG();
3691 }
3692
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003693 snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
3694 p_name, dev_name_source);
Denis V. Lunev4ab438f2008-02-28 20:48:01 -08003695 t->sysctl_header =
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003696 register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003697 if (!t->sysctl_header)
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003698 goto free;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003699
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 p->sysctl_table = t;
3701 return 0;
3702
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003703free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 kfree(t);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003705err:
3706 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003708EXPORT_SYMBOL(neigh_sysctl_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709
3710void neigh_sysctl_unregister(struct neigh_parms *p)
3711{
3712 if (p->sysctl_table) {
3713 struct neigh_sysctl_table *t = p->sysctl_table;
3714 p->sysctl_table = NULL;
Eric W. Biederman5dd3df12012-04-19 13:24:33 +00003715 unregister_net_sysctl_table(t->sysctl_header);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 kfree(t);
3717 }
3718}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003719EXPORT_SYMBOL(neigh_sysctl_unregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720
3721#endif /* CONFIG_SYSCTL */
3722
Thomas Grafc8822a42007-03-22 11:50:06 -07003723static int __init neigh_init(void)
3724{
Florian Westphalb97bac62017-08-09 20:41:48 +02003725 rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0);
3726 rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0);
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08003727 rtnl_register(PF_UNSPEC, RTM_GETNEIGH, neigh_get, neigh_dump_info, 0);
Thomas Grafc8822a42007-03-22 11:50:06 -07003728
Greg Rosec7ac8672011-06-10 01:27:09 +00003729 rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
Florian Westphalb97bac62017-08-09 20:41:48 +02003730 0);
3731 rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, 0);
Thomas Grafc8822a42007-03-22 11:50:06 -07003732
3733 return 0;
3734}
3735
3736subsys_initcall(neigh_init);